name: services-and-interfaces description: Define and implement services that encapsulate business logic with proper constructor-based dependency injection.
Services & Interface Design
When to use this skill
- Create services that encapsulate business logic
- Implement business operations that delegate to repositories for data access (Database)
- Add authentication or domain-specific features as services
Key principles
- Concrete struct design: Services are defined as interfaces and implemented by concrete structs with the same name lowercase and with a constructor (e.g.,
TodoServiceandtodoServicewithNewTodoServiceconstructor) - Constructor-based injection: Dependencies passed at construction
- Single responsibility: Each service handles one domain concern
- Repository delegation: Services delegate all data access to repositories
- Context-aware: All public methods accept
context.Context - Interface return types: Constructors return interfaces, not concrete types
- Single File Exports: Each service implementation is in its own file. However, all service interfaces are exported from
interfaces.gounder theservices/folder.
Pattern
Services handle business logic:
- Define interface for service with methods representing business operations
- Implement as concrete struct with repository dependencies
- Constructor function injects all dependencies
- Methods are thin wrappers that validate, transform, and delegate to repositories
- Return interfaces from constructors
Example
See examples/todo_service.go for:
- TodoService interface definition
- todoService implementation with constructor
- Validation and repository delegation patterns
Common mistakes
- Service-to-service direct calls without interfaces
- Putting queries in services (repositories own data access)
- Missing context parameter
- Exporting implementation struct instead of interface
- Not testing with mocks
References
- services/core.go - Core service interfaces
- internal/services/user_service.go
- internal/services/account_service.go