Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Enterprise-level Go architecture patterns including clean architecture, hexagonal architecture, DDD, and production-ready application structure.
.claude/skills/aiskillstore-golang-enterprise-patterns/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 3% | 0% |
| case-21 | ✗→✓ | ▲ Improved | 135% | 0% |
| case-22 | ✓→✗ | ▼ Worse | 94% | 0% |
| case-07 | ✓→✓ | = Same ✓ | 69% | 0% |
| case-08 | ✓→✓ | = Same ✓ | 77% | 0% |
This skill provides guidance on enterprise-level Go application architecture, design patterns, and production-ready code organization.
text/cmd /api - HTTP/gRPC entry points /worker - Background job runners /internal /domain - Business entities and interfaces /application - Use cases and application services /infrastructure /persistence - Database implementations /messaging - Queue implementations /http - HTTP client implementations /interfaces /api - HTTP handlers /grpc - gRPC handlers /pkg - Shared libraries (public)
Dependencies flow inward only:
textInterfaces → Application → Domain ↓ ↓ Infrastructure (implements domain interfaces)
go// domain/user.go package domain import "time" type UserID string type User struct { ID UserID Email string Name string CreatedAt time.Time } // UserRepository defines the contract for user persistence type UserRepository interface { FindByID(ctx context.Context, id UserID) (*User, error) FindByEmail(ctx context.Context, email string) (*User, error) Save(ctx context.Context, user *User) error Delete(ctx context.Context, id UserID) error } // UserService defines domain business logic type UserService interface { Register(ctx context.Context, email, name string) (*User, error) Authenticate(ctx context.Context, email, password string) (*User, error) }
go// application/user_service.go package application type UserServiceImpl struct { repo domain.UserRepository hasher PasswordHasher logger Logger } func NewUserService(repo domain.UserRepository, hasher PasswordHasher, logger Logger) *UserServiceImpl { return &UserServiceImpl{repo: repo, hasher: hasher, logger: logger} } func (s *UserServiceImpl) Register(ctx context.Context, email, name string) (*domain.User, error) { // Check if user exists existing, err := s.repo.FindByEmail(ctx, email) if err != nil && !errors.Is(err, domain.ErrNotFound) { return nil, fmt.Errorf("checking existing user: %w", err) } if existing != nil { return nil, domain.ErrUserAlreadyExists } user := &domain.User{ ID: domain.UserID(uuid.New().String()), Email: email, Name: name, CreatedAt: time.Now(), } if err := s.repo.Save(ctx, user); err != nil { return nil, fmt.Errorf("saving user: %w", err) } return user, nil }
go// ports/primary.go - Driving ports (input) package ports type UserAPI interface { CreateUser(ctx context.Context, req CreateUserRequest) (*UserResponse, error) GetUser(ctx context.Context, id string) (*UserResponse, error) } // ports/secondary.go - Driven ports (output) type UserStorage interface { Save(ctx context.Context, user *domain.User) error FindByID(ctx context.Context, id string) (*domain.User, error) } type NotificationSender interface { SendWelcomeEmail(ctx context.Context, user *domain.User) error }
go// adapters/postgres/user_repository.go package postgres type UserRepository struct { db *sql.DB } func (r *UserRepository) Save(ctx context.Context, user *domain.User) error { query := `INSERT INTO users (id, email, name, created_at) VALUES ($1, $2, $3, $4)` _, err := r.db.ExecContext(ctx, query, user.ID, user.Email, user.Name, user.CreatedAt) return err }
go// domain/order/aggregate.go package order type Order struct { id OrderID customerID CustomerID items []OrderItem status OrderStatus events []DomainEvent } func NewOrder(customerID CustomerID) *Order { o := &Order{ id: OrderID(uuid.New().String()), customerID: customerID, status: StatusPending, } o.recordEvent(OrderCreated{OrderID: o.id, CustomerID: customerID}) return o } func (o *Order) AddItem(productID ProductID, quantity int, price Money) error { if o.status != StatusPending { return ErrOrderNotModifiable } o.items = append(o.items, OrderItem{ ProductID: productID, Quantity: quantity, Price: price, }) return nil } func (o *Order) Submit() error { if len(o.items) == 0 { return ErrEmptyOrder } o.status = StatusSubmitted o.recordEvent(OrderSubmitted{OrderID: o.id}) return nil }
go// domain/money.go type Money struct { amount int64 // cents currency string } func NewMoney(amount int64, currency string) (Money, error) { if amount < 0 { return Money{}, ErrNegativeAmount } return Money{amount: amount, currency: currency}, nil } func (m Money) Add(other Money) (Money, error) { if m.currency != other.currency { return Money{}, ErrCurrencyMismatch } return Money{amount: m.amount + other.amount, currency: m.currency}, nil }
go// domain/events.go type DomainEvent interface { EventName() string OccurredAt() time.Time } type OrderCreated struct { OrderID OrderID CustomerID CustomerID occurredAt time.Time } func (e OrderCreated) EventName() string { return "order.created" } func (e OrderCreated) OccurredAt() time.Time { return e.occurredAt }
go// wire.go //+build wireinject func InitializeApp(cfg *config.Config) (*App, error) { wire.Build( NewDatabase, NewUserRepository, NewUserService, NewHTTPServer, NewApp, ) return nil, nil }
go// main.go func main() { cfg := config.Load() db := database.Connect(cfg.DatabaseURL) userRepo := postgres.NewUserRepository(db) orderRepo := postgres.NewOrderRepository(db) userService := application.NewUserService(userRepo) orderService := application.NewOrderService(orderRepo, userRepo) handler := api.NewHandler(userService, orderService) server := http.NewServer(cfg.Port, handler) server.Run() }
go// domain/errors.go type Error struct { Code string Message string Err error } func (e *Error) Error() string { if e.Err != nil { return fmt.Sprintf("%s: %s: %v", e.Code, e.Message, e.Err) } return fmt.Sprintf("%s: %s", e.Code, e.Message) } func (e *Error) Unwrap() error { return e.Err } var ( ErrNotFound = &Error{Code: "NOT_FOUND", Message: "resource not found"} ErrUserAlreadyExists = &Error{Code: "USER_EXISTS", Message: "user already exists"} ErrInvalidInput = &Error{Code: "INVALID_INPUT", Message: "invalid input"} )
go// config/config.go type Config struct { Server ServerConfig Database DatabaseConfig Redis RedisConfig } func Load() (*Config, error) { cfg := &Config{} cfg.Server.Port = getEnvInt("PORT", 8080) cfg.Server.ReadTimeout = getEnvDuration("READ_TIMEOUT", 30*time.Second) cfg.Database.URL = mustGetEnv("DATABASE_URL") cfg.Database.MaxConns = getEnvInt("DB_MAX_CONNS", 25) return cfg, nil }
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-07 | pass→pass | 15,471 | 12,690 | -18% | 1 | 1 | 0% | 2,726 | 4,595 | +69% | 0 | 0 | — |
case-08 | pass→pass | 25,372 | 15,277 | -40% | 1 | 1 | 0% | 2,751 | 4,861 | +77% | 0 | 0 | — |
case-01 | fail→pass | 25,748 | 10,673 | -59% | 1 | 1 | 0% | 4,146 | 4,278 | +3% | 0 | 0 | — |
case-09 | pass→pass | 15,702 | 8,301 | -47% | 1 | 1 | 0% | 2,618 | 3,771 | +44% | 0 | 0 | — |
case-02 | pass→pass | 28,353 | 10,558 | -63% | 1 | 1 | 0% | 2,579 | 4,018 | +56% | 0 | 0 | — |
case-03 | pass→pass | 16,727 | 14,173 | -15% | 1 | 1 | 0% | 3,173 | 4,995 | +57% | 0 | 0 | — |
case-04 | pass→pass | 14,365 | 13,480 | -6% | 1 | 1 | 0% | 2,726 | 4,834 | +77% | 0 | 0 | — |
case-05 | pass→pass | 27,519 | 14,846 | -46% | 1 | 1 | 0% | 3,897 | 5,490 | +41% | 0 | 0 | — |
case-06 | pass→pass | 16,890 | 20,059 | +19% | 1 | 1 | 0% | 3,326 | 5,480 | +65% | 0 | 0 | — |
case-10 | pass→pass | 17,834 | 13,066 | -27% | 1 | 1 | 0% | 3,220 | 4,759 | +48% | 0 | 0 | — |
case-11 | pass→pass | 13,320 | 12,266 | -8% | 1 | 1 | 0% | 2,256 | 4,348 | +93% | 0 | 0 | — |
case-12 | pass→pass | 12,538 | 7,557 | -40% | 1 | 1 | 0% | 2,233 | 3,808 | +71% | 0 | 0 | — |
case-13 | pass→pass | 17,419 | 17,003 | -2% | 1 | 1 | 0% | 2,858 | 5,267 | +84% | 0 | 0 | — |
case-14 | pass→pass | 12,169 | 10,283 | -15% | 1 | 1 | 0% | 2,252 | 4,098 | +82% | 0 | 0 | — |
case-15 | pass→pass | 15,059 | 13,174 | -13% | 1 | 1 | 0% | 2,504 | 4,438 | +77% | 0 | 0 | — |
case-16 | pass→pass | 13,528 | 16,130 | +19% | 1 | 1 | 0% | 2,326 | 5,167 | +122% | 0 | 0 | — |
case-17 | pass→pass | 14,593 | 13,081 | -10% | 1 | 1 | 0% | 2,234 | 4,161 | +86% | 0 | 0 | — |
case-18 | pass→pass | 12,436 | 15,752 | +27% | 1 | 1 | 0% | 2,276 | 4,730 | +108% | 0 | 0 | — |
case-19 | pass→pass | 15,077 | 10,448 | -31% | 1 | 1 | 0% | 2,768 | 4,156 | +50% | 0 | 0 | — |
case-20 | pass→pass | 6,494 | 6,366 | -2% | 1 | 1 | 0% | 1,265 | 3,492 | +176% | 0 | 0 | — |
case-21 | fail→pass | 7,876 | 8,449 | +7% | 1 | 1 | 0% | 1,681 | 3,958 | +135% | 0 | 0 | — |
case-22 | pass→fail | 10,609 | 8,495 | -20% | 1 | 1 | 0% | 2,003 | 3,893 | +94% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +5 percentage points is the difference between those two pass rates over the 22 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.