Common Anti-Patterns When Java Devs Write Go
Its totally upside down thinking for java devs in designing interface. 😄
This is where things usually go wrong 😄
I’ll show the anti-pattern, why it’s bad, and the Go-native fix.
Anti-Pattern 1: Interface-First Design
Java habit
“Define interfaces before writing code”
type UserService interface {
CreateUser(...)
UpdateUser(...)
DeleteUser(...)
GetUser(...)
ListUsers(...)
}Why it’s bad in Go
speculative abstraction
fat interfaces
hard to implement and test
Go way
Start with concrete code.
Extract interfaces only when needed.
type UserCreator interface {
CreateUser(ctx context.Context, u User) error
}Small. Focused. Intentional.
Anti-Pattern 2: One Interface Per Struct
type UserService interface {
Serve()
}
type userService struct{}This adds zero value.
Why Java devs do this
inheritance mindset
framework expectations
Go way
If there’s only one implementation:
don’t use an interface
use the concrete type
Interfaces are for variation, not formality.
Anti-Pattern 3: God Interfaces (a.k.a. “Service Interfaces”)
type OrderService interface {
Create()
Cancel()
Refund()
Get()
List()
Validate()
Notify()
}Problems
violates interface segregation
painful to mock
impossible to evolve safely
Go way
Split by behavior:
type OrderCreator interface {
Create(ctx context.Context, o Order) error
}
type OrderReader interface {
Get(ctx context.Context, id string) (*Order, error)
}Consumers depend only on what they need.
Anti-Pattern 4: Sharing Go Interfaces Across Services
// shared/contracts/payment.go
type PaymentService interface {
Charge(...)
}Why this is dangerous
compile-time coupling across services
forces lockstep deployments
breaks microservice autonomy
Go way
Share protobuf / OpenAPI
Generate clients
Define interfaces locally in the consumer
Anti-Pattern 5: Mocking Frameworks Everywhere
Java dev instinct:
“Where’s the mocking library?”
In Go, mocks are often overkill.
Bad Go code
code generation for trivial tests
brittle expectations
Good Go code
type FakeClock struct{}
func (f *FakeClock) Now() time.Time {
return fixedTime
}Simple structs beat magic.
Anti-Pattern 6: Inheritance Thinking
Java mindset:
BaseService
├─ UserService
├─ OrderServiceGo has no inheritance for a reason.
Go way: composition
type Service struct {
logger Logger
store Store
}Behavior is composed, not inherited.
Final Mental Model (Keep This)
Java / C#:
Interfaces describe what a service is
Go:
Interfaces describe what my code needs
This one shift:
shrinks abstractions
hardens boundaries
improves service autonomy
simplifies testing
If you enjoyed this deep dive…
I write weekly about:
Go performance and runtime behavior
Kubernetes-native service design
Expert-level engineering lessons from real systems
Subscribe if you want more posts like this.


