Skip to content
golang-enterprise-patterns logo

Golang Enterprise Patterns

golang-enterprise-patterns

Enterprise-level Go architecture patterns including clean architecture,

aiskillstore/marketplace0installs430stars

SKILL.md

Full skill instructions

Golang Enterprise Patterns

This skill provides guidance on enterprise-level Go application architecture, design patterns, and production-ready code organization.

When to Use This Skill

  • When designing new Go applications with complex business logic
  • When implementing clean architecture or hexagonal architecture
  • When applying Domain-Driven Design (DDD) principles
  • When organizing large Go codebases
  • When establishing patterns for team consistency

Clean Architecture

Layer Structure

/​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)

Dependency Rule

Dependencies flow inward only:

Interfaces → Application → Domain
     ↓            ↓
Infrastructure (implements domain interfaces)

Domain Layer

// 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)
}

Application Layer

// 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
}

Hexagonal Architecture (Ports & Adapters)

Port Definitions

// 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
}

Adapter Implementations

// 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
}

Domain-Driven Design (DDD)

Aggregate Roots

// 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
}

Value Objects

// 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
}

Domain Events

// 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 }

Dependency Injection

Wire-Style DI

// wire.go
//+build wireinject

func InitializeApp(cfg *config.Config) (*App, error) {
    wire.Build(
        NewDatabase,
        NewUserRepository,
        NewUserService,
        NewHTTPServer,
        NewApp,
    )
    return nil, nil
}

Manual DI (Preferred for Simplicity)

// 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()
}

Error Handling Patterns

Custom Error Types

// 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"}
)

Configuration Management

// 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
}

Best Practices

  1. Keep domain pure - No framework dependencies in domain layer
  2. Interface segregation - Small, focused interfaces
  3. Dependency inversion - Depend on abstractions, not concretions
  4. Explicit dependencies - Pass dependencies via constructor
  5. Fail fast - Validate at boundaries, trust internal code
  6. Make illegal states unrepresentable - Use types to enforce invariants

More skills from aiskillstore

docx logo
aiskillstore/marketplace

docx

Comprehensive document creation, editing, and analysis with support for tracked changes, comments, formatting preservation, and text extraction. When Claude needs to work with professional documents (.docx files) for: (1) Creating new documents, (2) Modifying or editing content, (3) Working with tracked changes, (4) Adding comments, or any other document tasks

430 216
View
agent-development logo
aiskillstore/marketplace

agent-development

This handles everything around building autonomous agents for Claude Code plugins.

430 197
View
doc-coauthoring logo
aiskillstore/marketplace

doc-coauthoring

Guide users through a structured workflow for co-authoring documentation. Use when user wants to write documentation, proposals, technical specs, decision docs, or similar structured content. This workflow helps users efficiently transfer context, refine content through iteration, and verify the doc works for readers. Trigger when user mentions writing docs, creating proposals, drafting specs, or similar documentation tasks.

430 196
View
skill-development logo
aiskillstore/marketplace

skill-development

This is the meta-skill for building skills themselves.

430 196
View
canvas-design logo
aiskillstore/marketplace

canvas-design

Create beautiful visual art in .png and .pdf documents using design philosophy. You should use this skill when the user asks to create a poster, piece of art, design, or other static piece. Create original visual designs, never copying existing artists' work to avoid copyright violations.

430 193
View
webapp-testing logo
aiskillstore/marketplace

webapp-testing

Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.

430 191
View
hook-development logo
aiskillstore/marketplace

hook-development

Helps you build event-driven automation for Claude Code using hooks that trigger on tool use, session events, and stop conditions.

430 187
View
algorithmic-art logo
aiskillstore/marketplace

algorithmic-art

Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.

430 185
View
command-development logo
aiskillstore/marketplace

command-development

Shows Claude Code how to build slash commands from markdown files, covering the YAML frontmatter options, dynamic arguments with $1/$2...

430 185
View
plugin-structure logo
aiskillstore/marketplace

plugin-structure

This is your reference when scaffolding Claude Code plugins or figuring out why components aren't loading.

430 183
View
skill-installer logo
aiskillstore/marketplace

skill-installer

Install Codex skills into $CODEX_HOME/skills from a curated list or a GitHub repo path. Use when a user asks to list installable skills, install a curated skill, or install a skill from another repo (including private repos).

430 180
View
web-artifacts-builder logo
aiskillstore/marketplace

web-artifacts-builder

Suite of tools for creating elaborate, multi-component claude.ai HTML artifacts using modern frontend web technologies (React, Tailwind CSS, shadcn/ui). Use for complex artifacts requiring state management, routing, or shadcn/ui components - not for simple single-file HTML/JSX artifacts.

430 177
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View