AgentSkillsCN

clean-architecture

设计并实现清晰分层的 Clean Architecture 模式。适用于系统架构设计、新项目创建、向 Clean Architecture 重构,或将关注点按层级分离时使用。

SKILL.md
--- frontmatter
name: clean-architecture
description: >
  Design and implement Clean Architecture patterns with clear layer separation.
  Trigger: When designing system architecture, creating new projects, refactoring to clean architecture, or separating concerns into layers.
license: Apache-2.0
metadata:
  author: 333-333-333
  version: "1.0"
  scope: [root]
  auto_invoke:
    - "Designing new project architecture"
    - "Creating domain entities or use cases"
    - "Implementing ports and adapters pattern"
    - "Refactoring to clean architecture"

When to Use

  • Designing a new project structure from scratch
  • Refactoring existing code to clean architecture
  • Creating domain entities, use cases, or repositories
  • Defining boundaries between layers
  • Implementing dependency injection patterns

Core Principles

PrincipleDescription
Dependency RuleDependencies point inward. Inner layers know nothing about outer layers
EntitiesEnterprise business rules, independent of application
Use CasesApplication business rules, orchestrate entities
Interface AdaptersConvert data between use cases and external agents
Frameworks & DriversExternal tools (DB, Web, UI) - outermost layer

Layer Structure

code
project/
├── domain/                 # Innermost - Enterprise Business Rules
│   ├── entities/           # Business objects with behavior
│   └── value_objects/      # Immutable domain primitives
│
├── application/            # Application Business Rules
│   ├── use_cases/          # Application-specific business rules
│   ├── ports/              # Interfaces (input/output boundaries)
│   │   ├── input/          # Use case interfaces (driven)
│   │   └── output/         # Repository/service interfaces (driving)
│   └── dto/                # Data Transfer Objects
│
├── adapters/               # Interface Adapters
│   ├── controllers/        # Input adapters (HTTP, CLI, gRPC)
│   ├── presenters/         # Output formatters
│   ├── repositories/       # Data persistence implementations
│   └── gateways/           # External service implementations
│
└── infrastructure/         # Frameworks & Drivers
    ├── config/             # Configuration loading
    ├── database/           # DB connections, migrations
    ├── http/               # HTTP server setup
    └── di/                 # Dependency injection container

Critical Patterns

1. Dependency Inversion

code
WRONG: UseCase depends on concrete Repository
RIGHT: UseCase depends on Repository interface (port)
       Concrete Repository implements the interface

2. Entity Design

go
// Domain Entity - contains business logic
type Order struct {
    ID        OrderID
    Items     []OrderItem
    Status    OrderStatus
    CreatedAt time.Time
}

func (o *Order) AddItem(item OrderItem) error {
    if o.Status != StatusDraft {
        return ErrOrderNotModifiable
    }
    o.Items = append(o.Items, item)
    return nil
}

func (o *Order) Total() Money {
    var total Money
    for _, item := range o.Items {
        total = total.Add(item.Subtotal())
    }
    return total
}

3. Use Case / Interactor

go
// Port (interface) - defined in application layer
type OrderRepository interface {
    Save(ctx context.Context, order *Order) error
    FindByID(ctx context.Context, id OrderID) (*Order, error)
}

// Use Case - orchestrates domain logic
type CreateOrderUseCase struct {
    orderRepo OrderRepository
    eventBus  EventPublisher
}

func (uc *CreateOrderUseCase) Execute(ctx context.Context, input CreateOrderInput) (*CreateOrderOutput, error) {
    order := NewOrder(input.CustomerID)
    
    for _, item := range input.Items {
        if err := order.AddItem(item); err != nil {
            return nil, err
        }
    }
    
    if err := uc.orderRepo.Save(ctx, order); err != nil {
        return nil, err
    }
    
    uc.eventBus.Publish(OrderCreatedEvent{OrderID: order.ID})
    
    return &CreateOrderOutput{OrderID: order.ID}, nil
}

4. Repository Implementation (Adapter)

go
// Adapter - implements the port
type PostgresOrderRepository struct {
    db *sql.DB
}

func (r *PostgresOrderRepository) Save(ctx context.Context, order *Order) error {
    // Convert domain entity to DB model
    model := toOrderModel(order)
    // Persist using infrastructure
    return r.db.Save(ctx, model)
}

func (r *PostgresOrderRepository) FindByID(ctx context.Context, id OrderID) (*Order, error) {
    model, err := r.db.FindByID(ctx, id)
    if err != nil {
        return nil, err
    }
    // Convert DB model back to domain entity
    return toOrderEntity(model), nil
}

Layer Communication Rules

FromToAllowed?How
InfrastructureAdaptersYesDirect import
AdaptersApplicationYesVia ports (interfaces)
ApplicationDomainYesDirect import
DomainApplicationNONever
ApplicationAdaptersNOUse dependency injection
AdaptersInfrastructureYesDirect import

Decision Tree: Where Does This Code Go?

code
Is it a business rule that exists regardless of application?
├─ YES → domain/entities/
└─ NO
   Is it application-specific business logic?
   ├─ YES → application/use_cases/
   └─ NO
      Does it convert data between formats?
      ├─ YES → adapters/
      └─ NO → infrastructure/

Anti-Patterns to Avoid

Anti-PatternProblemSolution
Anemic DomainEntities with only getters/settersAdd business methods to entities
Leaky AbstractionDomain knows about DB/HTTPUse ports for external concerns
Use Case BloatToo much logic in use casesExtract to domain entities
Shared DTOsSame DTO across layersCreate layer-specific DTOs
Direct InfrastructureController calls DB directlyAlways go through use cases

Testing Strategy

LayerTest TypeDependencies
DomainUnit testsNone (pure logic)
ApplicationUnit testsMock ports
AdaptersIntegration testsReal/test infrastructure
InfrastructureIntegration testsReal external systems

Commands

bash
# Typical directory creation for new clean architecture project
mkdir -p domain/{entities,value_objects}
mkdir -p application/{use_cases,ports/{input,output},dto}
mkdir -p adapters/{controllers,repositories,gateways,presenters}
mkdir -p infrastructure/{config,database,http,di}

Resources

  • Reference: Uncle Bob's Clean Architecture book
  • Pattern: Hexagonal Architecture (Ports and Adapters) - related pattern
  • Pattern: Onion Architecture - related pattern