Use interfaces for function parameters to enable flexibility and testing, but return concrete structs to preserve extensibility.
Define your function parameters and return types as interfaces to decouple dependencies, but return concrete structs to maintain flexibility and avoid breaking changes.
type Service interface {
Process(data []byte) error
}
type MyService struct {
// fields
}
func NewService() Service {
return &MyService{}
}
func (m *MyService) Process(data []byte) error {
// implementation
return nil
}
DI Patterns in Go: Accept Interfaces, Return Structs means your code asks for a specific capability (interface) rather than a specific implementation, making it easy to swap out parts or test with fakes. You return the actual concrete type so the caller can access extra features later if needed, without forcing them to depend on a rigid interface definition.