Smithery Logo
MCPsSkillsDocsPricing
Login
NewFlame, an assistant that learns and improves. Available onTelegramSlack
    billybbuffum

    go-clean-architecture

    billybbuffum/go-clean-architecture
    Coding

    About

    SKILL.md

    Install

    • Telegram
      Telegram
    • Slack
      Slack
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    • Download skill
    ├─
    ├─
    └─
    Smithery Logo

    Give agents more agency

    Resources

    DocumentationPrivacy PolicySystem Status

    Company

    PricingAboutBlog

    Connect

    © 2026 Smithery. All rights reserved.

    About

    Expert knowledge in Go clean architecture patterns and best practices

    SKILL.md

    Go Clean Architecture Skill

    Overview

    Clean Architecture in Go emphasizes separation of concerns through distinct layers, with dependencies pointing inward toward the domain.

    Layer Structure

    Domain Layer (innermost)

    Location: internal/domain/

    Contains:

    • Business entities (structs)
    • Repository interfaces
    • Domain logic and validation
    • Business rules

    Rules:

    • NO external dependencies
    • NO framework dependencies
    • Pure business logic
    • Defines contracts for outer layers

    Example:

    // internal/domain/account.go
    package domain
    
    type Account struct {
        ID      string
        Name    string
        Type    AccountType
        Balance int // cents
    }
    
    type AccountRepository interface {
        Create(account *Account) error
        GetByID(id string) (*Account, error)
        Update(account *Account) error
        Delete(id string) error
    }
    
    // Domain validation
    func (a *Account) Validate() error {
        if a.Name == "" {
            return ErrInvalidName
        }
        if !a.Type.IsValid() {
            return ErrInvalidType
        }
        return nil
    }
    

    Application Layer (middle)

    Location: internal/application/

    Contains:

    • Business logic services
    • Use case orchestration
    • Service interfaces
    • Cross-cutting concerns

    Rules:

    • Depends ONLY on domain interfaces
    • NO HTTP dependencies
    • NO database dependencies
    • Orchestrates domain entities

    Example:

    // internal/application/account_service.go
    package application
    
    import "internal/domain"
    
    type AccountService struct {
        repo domain.AccountRepository // Interface, not concrete type
    }
    
    func NewAccountService(repo domain.AccountRepository) *AccountService {
        return &AccountService{repo: repo}
    }
    
    func (s *AccountService) CreateAccount(account *domain.Account) error {
        if err := account.Validate(); err != nil {
            return fmt.Errorf("validation failed: %w", err)
        }
    
        if err := s.repo.Create(account); err != nil {
            return fmt.Errorf("failed to create account: %w", err)
        }
    
        return nil
    }
    

    Infrastructure Layer (outermost)

    Location: internal/infrastructure/

    Contains:

    • Repository implementations
    • HTTP handlers
    • Database logic
    • External service integrations

    Rules:

    • Implements domain interfaces
    • Can have external dependencies
    • Handlers should be thin (parse → service → respond)
    • Repositories only handle persistence

    Example:

    // internal/infrastructure/repository/account_repository.go
    package repository
    
    import (
        "database/sql"
        "internal/domain"
    )
    
    type AccountRepository struct {
        db *sql.DB
    }
    
    func NewAccountRepository(db *sql.DB) *AccountRepository {
        return &AccountRepository{db: db}
    }
    
    func (r *AccountRepository) Create(account *domain.Account) error {
        query := `INSERT INTO accounts (id, name, type, balance) VALUES (?, ?, ?, ?)`
        _, err := r.db.Exec(query, account.ID, account.Name, account.Type, account.Balance)
        return err
    }
    
    // internal/infrastructure/http/handlers/account_handler.go
    package handlers
    
    type AccountHandler struct {
        service *application.AccountService
    }
    
    func (h *AccountHandler) CreateAccount(w http.ResponseWriter, r *http.Request) {
        // 1. Parse request
        var req CreateAccountRequest
        if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
            http.Error(w, "invalid request", http.StatusBadRequest)
            return
        }
    
        // 2. Call service
        account := req.ToDomain()
        if err := h.service.CreateAccount(account); err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }
    
        // 3. Return response
        w.WriteHeader(http.StatusCreated)
        json.NewEncoder(w).Encode(account)
    }
    

    Dependency Injection

    Wire dependencies in main.go:

    // cmd/server/main.go
    func main() {
        // Infrastructure
        db := setupDatabase()
    
        // Repositories (concrete implementations)
        accountRepo := repository.NewAccountRepository(db)
    
        // Services (injected with interfaces)
        accountService := application.NewAccountService(accountRepo)
    
        // Handlers (injected with services)
        accountHandler := handlers.NewAccountHandler(accountService)
    
        // Router
        router := setupRouter(accountHandler)
    
        http.ListenAndServe(":8080", router)
    }
    

    Common Patterns

    Repository Pattern

    // Domain defines interface
    type Repository interface {
        Create(entity *Entity) error
        GetByID(id string) (*Entity, error)
    }
    
    // Infrastructure implements
    type SQLRepository struct {
        db *sql.DB
    }
    
    func (r *SQLRepository) Create(entity *Entity) error {
        // SQL implementation
    }
    

    Service Pattern

    type Service struct {
        repo domain.Repository  // Depend on interface
    }
    
    func (s *Service) DoBusinessLogic(entity *domain.Entity) error {
        // Validate
        // Transform
        // Call repository
        return s.repo.Create(entity)
    }
    

    Handler Pattern

    func (h *Handler) HandleRequest(w http.ResponseWriter, r *http.Request) {
        // Parse → Service → Respond
        req := parseRequest(r)
        result, err := h.service.Do(req)
        respond(w, result, err)
    }
    

    Anti-Patterns to Avoid

    ❌ Domain with External Dependencies

    // BAD: Domain importing database
    import "database/sql"
    
    type Account struct {
        db *sql.DB  // ❌ Domain shouldn't know about database
    }
    

    ❌ Service with HTTP/Database

    // BAD: Service with HTTP dependency
    func (s *Service) Create(w http.ResponseWriter, r *http.Request) {
        // ❌ Service shouldn't handle HTTP
    }
    
    // BAD: Service with database dependency
    func (s *Service) Create(db *sql.DB, entity *Entity) error {
        // ❌ Service should use repository interface
    }
    

    ❌ Handler with Business Logic

    // BAD: Complex logic in handler
    func (h *Handler) Create(w http.ResponseWriter, r *http.Request) {
        // Parse
        // ❌ Complex validation
        // ❌ Calculations
        // ❌ Business rules
        // Direct database access
    }
    
    // GOOD: Thin handler
    func (h *Handler) Create(w http.ResponseWriter, r *http.Request) {
        req := parse(r)
        result := h.service.Create(req)  // Service has the logic
        respond(w, result)
    }
    

    ❌ Repository with Business Logic

    // BAD: Business rules in repository
    func (r *Repository) Create(account *Account) error {
        // ❌ Business validation in repository
        if account.Balance < 0 && account.Type != "credit" {
            return errors.New("invalid")
        }
        // Should only handle persistence
    }
    

    Testing Strategy

    Domain Tests

    func TestAccount_Validate(t *testing.T) {
        // Test entity validation
        // No mocks needed
    }
    

    Service Tests (Unit)

    func TestService_Create(t *testing.T) {
        mockRepo := &MockRepository{}  // Mock interface
        service := NewService(mockRepo)
        // Test business logic
    }
    

    Repository Tests (Integration)

    func TestRepository_Create(t *testing.T) {
        db := setupTestDB()  // Real database
        repo := NewRepository(db)
        // Test persistence
    }
    

    Handler Tests (E2E)

    func TestHandler_Create(t *testing.T) {
        mockService := &MockService{}
        handler := NewHandler(mockService)
        req := httptest.NewRequest("POST", "/", body)
        w := httptest.NewRecorder()
        handler.Create(w, req)
        // Test HTTP layer
    }
    

    Benefits

    ✅ Testability: Easy to mock dependencies ✅ Maintainability: Clear separation of concerns ✅ Flexibility: Easy to swap implementations ✅ Independence: Domain logic independent of frameworks ✅ Scalability: Easy to add features

    When to Apply

    • Multi-layer applications
    • Complex business logic
    • Long-lived projects
    • Team projects requiring clear boundaries
    • Applications that may change databases/frameworks

    Quick Checklist

    • Domain has no external dependencies
    • Application uses interfaces, not concrete types
    • Handlers are thin (parse → service → respond)
    • Repositories only handle persistence
    • Dependencies point inward
    • Business logic in services, not handlers
    • Each layer has clear responsibility
    Recommended Servers
    InfraNodus Knowledge Graphs & Text Analysis
    InfraNodus Knowledge Graphs & Text Analysis
    Docfork
    Docfork
    ScrapeGraph AI Integration Server
    ScrapeGraph AI Integration Server
    Repository
    billybbuffum/budget
    Files