Procyon|Docs
ComponentsDependency Injection

Interfaces

Depend on capabilities while keeping implementations replaceable.

Use interfaces when a component depends on a capability rather than one concrete implementation.

password.go
type PasswordHasher interface {
	// Hash converts a plain password into the stored representation.
	Hash(password string) (string, error)
}

This interface describes the capability the service needs. It does not describe how the password is hashed, where configuration comes from, or which concrete type implements it.

The implementation can still be registered as a normal component.

bcrypt.go
type BcryptHasher struct{}

func NewBcryptHasher() PasswordHasher {
	return &BcryptHasher{}
}

func init() {
	component.Register(NewBcryptHasher)
}

The dependent component receives the interface.

service.go
func NewUserService(hasher PasswordHasher) *UserService {
	return &UserService{hasher: hasher}
}

Ambiguous interfaces

If multiple components satisfy the same interface, type alone is not enough. Use component names and qualifiers to select the implementation.

Keep interfaces small and close to the package that consumes them. A component should usually ask for the behavior it needs, not for a large shared interface that happens to include that behavior.