clean-architecture-golang

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Custom Clean Architecture Implementation Guide

自定义Clean架构实现指南

Expert guidance for implementing features using this project's custom Clean Architecture pattern with Golang. This is NOT Uncle Bob's standard Clean Architecture - it's a specialized adaptation.
在Golang项目中使用本项目自定义Clean架构模式实现功能的专业指导。注意:这并非Uncle Bob的标准Clean Architecture,而是经过专门适配的版本。

Architecture Overview

架构概述

Four layers with strict dependency rules:
Integration → Application → Domain ← Infrastructure
Dependency Rule: Inner layers NEVER depend on outer layers.
具有严格依赖规则的四层架构:
Integration → Application → Domain ← Infrastructure
依赖规则:内层绝不能依赖外层。

🚨 Critical Rules

🚨 核心规则

MUST DO

必须遵守

  • START with BDD feature file - Never skip test-first development
  • Integration adapters MUST implement usecase interfaces - Enable type casting
  • Use context.Context as first parameter - Always
  • Convert at boundaries - DTO↔Entity↔Model
  • Follow error code format - PREFIX-XXYYYY
  • Type cast repositories to usecases - In dependency injection
  • 从BDD特性文件开始 - 绝不能跳过测试优先开发
  • 集成适配器必须实现用例接口 - 启用类型转换
  • 始终将context.Context作为第一个参数
  • 在边界处进行转换 - DTO↔Entity↔Model
  • 遵循错误代码格式 - PREFIX-XXYYYY
  • 在依赖注入中将存储库类型转换为用例

NEVER DO

绝对禁止

  • Skip BDD test creation - Tests come first
  • Create adapters without usecase interfaces - Will break dependency injection
  • Put business logic in controllers/repositories - Only in services
  • Use DTOs in domain/application - Only in integration layer
  • Access database from services - Only through usecases
  • Create circular dependencies - Dependencies flow inward only
  • 跳过BDD测试创建 - 测试先行
  • 不基于用例接口创建适配器 - 会破坏依赖注入
  • 将业务逻辑放在控制器/存储库中 - 只能放在服务层
  • 在领域层/应用层使用DTO - 仅在集成层使用
  • 从服务层直接访问数据库 - 只能通过用例
  • 创建循环依赖 - 依赖只能向内流动

Implementation Workflow

实现流程

Step 1: Create BDD Test (MANDATORY)

步骤1:创建BDD测试(必填)

Start here ALWAYS. Location:
/test/integration/features/
gherkin
Feature: Create entity functionality
  Scenario: Create entity success
    When I call "POST" "/v1/entities" with payload
    Then status should be 201
    And db should contain entity
始终从此步骤开始。路径:
/test/integration/features/
gherkin
Feature: Create entity functionality
  Scenario: Create entity success
    When I call "POST" "/v1/entities" with payload
    Then status should be 201
    And db should contain entity

Step 2: Domain Layer

步骤2:领域层

  1. Entity (
    /internal/domain/entity/
    )
    • Simple structs, NO logic
    • Audit fields (CreatedAt, UpdatedAt)
  2. Errors (
    /internal/domain/error/
    )
    • Format:
      PREFIX-XXYYYY
    • One error per file
  3. Enums (
    /internal/domain/enums/
    )
    • String types
    • SCREAMING_SNAKE_CASE values
  1. 实体
    /internal/domain/entity/
    • 简单结构体,无逻辑
    • 包含审计字段(CreatedAt、UpdatedAt)
  2. 错误定义
    /internal/domain/error/
    • 格式:
      PREFIX-XXYYYY
    • 每个错误对应一个文件
  3. 枚举
    /internal/domain/enums/
    • 字符串类型
    • 值采用SCREAMING_SNAKE_CASE格式

Step 3: Application Layer

步骤3:应用层

  1. Adapter Interface (
    /internal/application/adapter/
    )
    • Service contracts
    • Use domain entities
  2. UseCase Interfaces (
    /internal/application/usecase/
    )
    • Atomic operations
    • FindX, SaveX, UpdateX, DeleteX
  3. Service Implementation (
    /internal/application/service/
    )
    • Business logic HERE
    • Orchestrate usecases
  1. 适配器接口
    /internal/application/adapter/
    • 服务契约
    • 使用领域实体
  2. 用例接口
    /internal/application/usecase/
    • 原子操作
    • 命名格式:FindX、SaveX、UpdateX、DeleteX
  3. 服务实现
    /internal/application/service/
    • 业务逻辑仅在此处
    • 编排用例

Step 4: Integration Layer

步骤4:集成层

  1. Adapter Interfaces (
    /internal/integration/adapter/
    )
    go
    type Repository interface {
        usecase.Find    // MUST embed
        usecase.Save    // MUST embed
    }
  2. DTOs (
    /internal/integration/entrypoint/dto/
    )
    • Request/Response structs
    • ToEntity() methods
    • Validation tags
  3. Controller (
    /internal/integration/entrypoint/controller/
    )
    • Handle HTTP
    • DTO↔Entity conversion
  4. Model (
    /internal/integration/persistence/model/
    )
    • GORM annotations
    • ToEntity() methods
  5. Repository (
    /internal/integration/persistence/
    )
    • Implements usecase interfaces
    • Entity↔Model conversion
  1. 适配器接口
    /internal/integration/adapter/
    go
    type Repository interface {
        usecase.Find    // 必须嵌入
        usecase.Save    // 必须嵌入
    }
  2. DTO
    /internal/integration/entrypoint/dto/
    • 请求/响应结构体
    • 包含ToEntity()方法
    • 带有验证标签
  3. 控制器
    /internal/integration/entrypoint/controller/
    • 处理HTTP请求
    • 完成DTO↔Entity的转换
  4. 模型
    /internal/integration/persistence/model/
    • 带有GORM注解
    • 包含ToEntity()方法
  5. 存储库
    /internal/integration/persistence/
    • 实现用例接口
    • 完成Entity↔Model的转换

Step 5: Infrastructure Layer

步骤5:基础设施层

  1. Dependency Injection (
    /internal/infra/dependency/injector.go
    )
    go
    // Type cast repository to usecase
    usecase.Find(i.GetRepository())
  2. Router (
    /internal/infra/server/router/router.go
    )
    • Add routes
    • Validation middleware
  1. 依赖注入
    /internal/infra/dependency/injector.go
    go
    // 将存储库类型转换为用例
    usecase.Find(i.GetRepository())
  2. 路由
    /internal/infra/server/router/router.go
    • 添加路由
    • 配置验证中间件

Step 6: Run Tests

步骤6:运行测试

bash
make test-integration
bash
make test-integration

Quick Patterns

快速模式

Integration Adapter Pattern (CRITICAL)

集成适配器模式(核心)

go
// Application defines need
type FindProduct interface {
    FindById(ctx, id) (*entity, error)
}

// Integration MUST implement
type ProductRepository interface {
    usecase.FindProduct  // EMBED!
}

// Type cast in DI
usecase.FindProduct(repository)
go
// 应用层定义需求
type FindProduct interface {
    FindById(ctx, id) (*entity, error)
}

// 集成层必须实现
type ProductRepository interface {
    usecase.FindProduct  // 必须嵌入!
}

// 在依赖注入中进行类型转换
usecase.FindProduct(repository)

Error Codes

错误代码示例

  • CLI-01409
    = Client conflict (409)
  • USR-01404
    = User not found (404)
  • PRD-02500
    = Product server error (500)
  • CLI-01409
    = 客户端冲突(409)
  • USR-01404
    = 用户不存在(404)
  • PRD-02500
    = 产品服务端错误(500)

Conversion Flow

转换流程

Request → DTO → Entity → Model → DB
Response ← DTO ← Entity ← Model ← DB
Request → DTO → Entity → Model → DB
Response ← DTO ← Entity ← Model ← DB

Reference Documentation

参考文档

Detailed guides in references/:
  • Layer Implementation - Complete layer examples
  • Critical Patterns - Must-know patterns
  • Implementation Workflow - Step-by-step guide
详细指南位于references/目录下:
  • Layer Implementation - 完整的层实现示例
  • Critical Patterns - 必须掌握的模式
  • Implementation Workflow - 分步指南

Templates

模板

Ready-to-use templates in assets/:
  • entity-template.go
    - Domain entity template
  • service-template.go
    - Application service template
  • repository-template.go
    - Repository template
assets/目录下提供可直接使用的模板:
  • entity-template.go
    - 领域实体模板
  • service-template.go
    - 应用服务模板
  • repository-template.go
    - 存储库模板

Implementation Checklist

实现检查清单

Before starting any feature:
  • BDD feature file exists
  • Domain entity defined
  • Domain errors created
  • Application adapter interface defined
  • Application usecases created
  • Application service implemented
  • Integration adapters created WITH usecase interfaces
  • DTOs with ToEntity() methods
  • Controller handling HTTP
  • Model with ToEntity() method
  • Repository implementing usecases
  • Dependencies wired in injector
  • Routes added to router
  • Tests passing
开始任何功能开发前,请确认:
  • BDD特性文件已存在
  • 领域实体已定义
  • 领域错误已创建
  • 应用层适配器接口已定义
  • 应用层用例已创建
  • 应用层服务已实现
  • 已创建包含用例接口的集成适配器
  • DTO带有ToEntity()方法
  • 控制器已处理HTTP请求
  • Model带有ToEntity()方法
  • 存储库已实现用例
  • 依赖已在注入器中配置
  • 路由已添加到路由器
  • 测试已通过

Common Mistakes to Avoid

需避免的常见错误

  1. Forgetting usecase interfaces on adapters - Breaks type casting
  2. Business logic in wrong layer - Only in services
  3. Wrong dependency direction - Check imports
  4. Missing BDD test - Always start with test
  5. Wrong error code format - Use PREFIX-XXYYYY
  6. Not converting at boundaries - DTO↔Entity↔Model
  1. 适配器上遗漏用例接口 - 会破坏类型转换
  2. 业务逻辑放错层级 - 只能放在服务层
  3. 依赖方向错误 - 检查导入关系
  4. 缺少BDD测试 - 始终从测试开始
  5. 错误代码格式不正确 - 使用PREFIX-XXYYYY格式
  6. 未在边界处进行转换 - 必须完成DTO↔Entity↔Model的转换

Example Implementations

示例实现

Study these existing implementations:
  • Client:
    /internal/{domain,application,integration}/*/client*.go
  • User:
    /internal/{domain,application,integration}/*/user*.go
  • Forest:
    /internal/{domain,application,integration}/*/forest*.go
可参考以下现有实现:
  • Client:
    /internal/{domain,application,integration}/*/client*.go
  • User:
    /internal/{domain,application,integration}/*/user*.go
  • Forest:
    /internal/{domain,application,integration}/*/forest*.go