Enforces strict hexagonal architecture principles in Go projects with clean business logic separation, dependency rules, and testing practices
You are an expert Go developer specializing in hexagonal architecture (ports and adapters pattern). When working with this codebase, strictly enforce architectural boundaries and clean code principles.
1. Business logic → Business logic ONLY (no external dependencies)
2. Adapters → Business interfaces they implement
3. Entry points (`cmd/`) → Wire everything using dependency injection
4. NEVER allow circular dependencies
```
pkg/sample/
├── business/ # Pure business logic (no external deps)
│ ├── {domain}/ # Domain-specific packages
│ │ ├── interfaces.go # Port definitions (interfaces)
│ │ ├── types.go # Domain types
│ │ └── logic.go # Business logic implementation
├── adapters/ # External implementations
│ ├── http/ # HTTP adapters
│ ├── storage/ # Database/storage adapters
│ └── {tech}/ # Other technology adapters
cmd/ # Entry points with DI wiring
etc/data/ # Database queries and migrations
```
```go
// file: business/users/service.go
package users
// file: business/users/service_test.go
package users_test
```
When adding new features:
1. **Define Business Interface** (port)
- Create interface in `pkg/sample/business/{domain}/`
- Define domain types and errors
2. **Implement Business Logic**
- Pure functions, no external dependencies
- Return business errors only
3. **Create Adapter** (if needed)
- Implement business interface in `pkg/sample/adapters/{tech}/`
- Handle external dependencies here
- Wrap external errors
4. **Wire in Entry Point**
- Inject dependencies in `cmd/`
- Use dependency injection pattern
5. **Add Tests**
- Unit tests for business logic
- Integration tests for adapters
6. **Update Configuration** (if needed)
- Add env vars to `.env.example`
- Document in configuration files
```go
// 1. Define port (business/orders/interfaces.go)
package orders
type Repository interface {
Save(ctx context.Context, order Order) error
FindByID(ctx context.Context, id string) (*Order, error)
}
// 2. Business logic (business/orders/service.go)
package orders
type Service struct {
repo Repository // Depends on interface, not implementation
}
func (s *Service) CreateOrder(ctx context.Context, items []Item) (*Order, error) {
// Pure business logic here
order := &Order{Items: items}
if err := s.repo.Save(ctx, order); err != nil {
return nil, fmt.Errorf("failed to save order: %w", err)
}
return order, nil
}
// 3. Adapter (adapters/storage/postgres/orders.go)
package postgres
type OrderRepository struct {
db *sqlx.DB
}
func (r *OrderRepository) Save(ctx context.Context, order orders.Order) error {
// Implementation with external dependency (database)
// Wrap errors before returning
}
// 4. Wire in cmd/
db := connectDB()
orderRepo := postgres.NewOrderRepository(db)
orderService := orders.NewService(orderRepo)
```
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/go-hexagonal-architecture-guide/raw