| name | clean-architecture |
| description | Macro-level system design — layers, dependencies, modules, and boundaries following Clean Architecture, DDD, SOLID, and hexagonal/onion patterns. Use when designing new features/modules, structuring or reviewing an architecture, planning microservices or a modular monolith, or applying the Dependency Rule, dependency inversion, ports & adapters, bounded contexts, aggregates/value objects/domain events, repositories, CQRS, screaming architecture, or vertical slices. For micro-level naming, functions, comments, and code smells, use the clean-code skill instead. |
| allowed-tools | Read, Grep, Glob, Edit, Write |
Clean Architecture Development Guide
This skill helps you design and implement software following Clean Architecture principles, Domain-Driven Design (DDD), SOLID principles, and related architectural patterns (Hexagonal, Onion).
When to Use This Skill
- Designing new features or modules
- Refactoring existing code to improve architecture
- Reviewing code for architectural issues
- Planning microservices or modular monoliths
- Setting up project structure
- Making architectural decisions
Core Principles (The Foundation)
1. The Dependency Rule
Dependencies must point inward only.
┌─────────────────────────────────────┐
│ Infrastructure & Frameworks │ ← Outer layer (most concrete)
│ ┌───────────────────────────────┐ │
│ │ Interface Adapters │ │
│ │ ┌─────────────────────────┐ │ │
│ │ │ Application/Use Cases │ │ │
│ │ │ ┌───────────────────┐ │ │ │
│ │ │ │ Domain/Entities │ │ │ │ ← Inner layer (most abstract)
│ │ │ │ Business Rules │ │ │ │
│ │ │ └───────────────────┘ │ │ │
│ │ └─────────────────────────┘ │ │
│ └───────────────────────────────┘ │
└─────────────────────────────────────┘
Dependencies point inward ──→
Key Rules:
- Inner layers NEVER depend on outer layers
- Outer layers depend on inner layers through abstractions (interfaces)
- Business logic knows nothing about databases, UI, frameworks
2. SOLID Principles
- Single Responsibility: One class, one reason to change
- Open/Closed: Open for extension, closed for modification
- Liskov Substitution: Subtypes must be substitutable for base types
- Interface Segregation: Many small interfaces better than one large
- Dependency Inversion: Depend on abstractions, not concretions
3. Separation of Concerns
Each layer has a clear, single responsibility:
- Domain: Business rules and entities
- Application: Use cases and orchestration
- Infrastructure: Technical implementation details
- Presentation: User interface and APIs
Architecture Implementation Steps
Step 1: Identify the Domain
Before writing code, understand the business:
-
Define Bounded Contexts (DDD)
- What are the logical boundaries?
- What is the Ubiquitous Language?
-
Identify Entities
- What are the core business objects?
- What are their invariants (rules that must always be true)?
-
Find Value Objects
- Immutable objects defined by their attributes
- Examples: Money, Email, Address
-
Discover Aggregates
- Clusters of entities with a root
- Enforce consistency boundaries
Step 2: Design the Layers
You have two main approaches for organizing the Application layer:
Option A: Traditional Horizontal Layers
Organize each layer by technical concern (Entities, UseCases, Repositories, …). The four layers and their folder contents are detailed below under Layer 1–4. This is the simplest structure and fits small services or CRUD-heavy apps.
Option B: Vertical Slices (Feature-Based) — Recommended for 3+ Developers
Organize Application layer by features, not technical concerns. Important: Domain Layer remains horizontal, Presentation Layer is separate.
src/
├── Domain/ # HORIZONTAL - shared
│ └── Orders/
│ ├── Order.cs # Aggregate Root
│ └── OrderLine.cs # Entity
│
├── Application/ # VERTICAL SLICES
│ └── Features/
│ └── Orders/
│ ├── CreateOrder/
│ │ ├── CreateOrderCommand.cs
│ │ ├── CreateOrderHandler.cs
│ │ ├── CreateOrderValidator.cs
│ │ └── CreateOrderResponse.cs
│ └── Shared/
│ └── IOrderRepository.cs # Port
│
├── Presentation/ # SEPARATE from Application
│ └── Orders/
│ ├── CreateOrderEndpoint.cs
│ └── Contracts/
│ └── CreateOrderRequest.cs # API DTO
│
└── Infrastructure/ # HORIZONTAL
└── Persistence/
└── SqlOrderRepository.cs # Adapter
Vertical Slices Benefits:
| Benefit | Description |
|---|
| High Cohesion | All Application code for one feature in one folder |
| Layer Separation | Domain, Presentation, Infrastructure remain horizontal |
| Team Scalability | Multiple developers work without conflicts |
| Easy Navigation | Find everything in one place |
| Natural CQRS | Each slice is Command or Query |
When to Use Vertical Slices:
- Teams with 3+ developers
- Frequently changing requirements
- Projects using CQRS/MediatR
- Planning microservice extraction
Important: Domain Layer remains horizontal (shared), and Presentation Layer is separate from Application slices. See Vertical Slices Principle and Code Examples.
Layer 1: Domain (Core)
Domain/
├── Entities/ # Business objects with identity
├── ValueObjects/ # Immutable objects
├── Aggregates/ # Aggregate roots
├── DomainServices/ # Domain logic that doesn't belong to entities
├── DomainEvents/ # Events that happened in the domain
├── Repositories/ # Interfaces (implementations in Infrastructure)
└── Specifications/ # Business rules encapsulation
Rules:
- No dependencies on outer layers
- No framework code
- Pure business logic
- Framework-agnostic
Layer 2: Application (Use Cases)
Traditional Structure:
Application/
├── UseCases/ # Application-specific business rules
├── DTOs/ # Data Transfer Objects
├── Interfaces/ # Ports (for adapters to implement)
├── Services/ # Application services
├── Commands/ # CQRS commands
├── Queries/ # CQRS queries
└── Validators/ # Input validation
Rules:
- Orchestrates domain objects
- Implements use cases
- Depends only on Domain layer
- Defines interfaces for infrastructure
Layer 3: Infrastructure (Technical Details)
Infrastructure/
├── Persistence/ # Database implementations
│ ├── Repositories/ # Repository implementations
│ ├── EntityConfigurations/
│ └── Migrations/
├── ExternalServices/ # API clients, message queues
├── Identity/ # Authentication/Authorization
├── FileStorage/ # File system, cloud storage
└── Logging/ # Logging implementations
Rules:
- Implements interfaces from Application/Domain
- Contains all technical details
- Depends on Application and Domain through interfaces
Layer 4: Presentation (API/UI)
Presentation/
├── Controllers/ # API endpoints
├── ViewModels/ # UI-specific models
├── Middleware/ # HTTP pipeline
├── Filters/ # Cross-cutting concerns
└── Mappers/ # DTO to ViewModel mapping
Rules:
- Thin layer - delegates to Application
- No business logic
- Request/Response handling only
Step 3: Apply Design Patterns
Use these patterns appropriately:
Creational:
- Factory: Create complex aggregates
- Builder: Construct complex objects step-by-step
- Dependency Injection: Invert dependencies
Structural:
- Adapter: Convert interfaces (Hexagonal Architecture)
- Repository: Abstract data access
- Unit of Work: Manage transactions
Behavioral:
- Strategy: Encapsulate algorithms
- Command: Encapsulate requests (CQRS)
- Observer: Domain events
- Specification: Business rules composition
Step 4: Implement Dependency Inversion
The outer layer (Infrastructure) provides the concrete implementation at runtime through dependency injection.
Violates DIP: High-level code directly instantiates low-level concrete classes.
Follows DIP: High-level code depends on abstractions (interfaces), concrete implementations injected at runtime.
Step 5: Testing Strategy
Test Pyramid:
┌─────┐
/ E2E \ ← Few, test critical paths
/_________\
/ \
/ Integration \ ← Moderate, test layer boundaries
/_______________\
/ \
/ Unit Tests \ ← Many, test business logic
/_____________________\
What to Test:
- Domain: Unit test all business rules (most important!)
- Application: Unit test use cases, mock dependencies
- Infrastructure: Integration tests with real dependencies
- Presentation: Integration/E2E tests for critical flows
Architecture Review Checklist
Before considering implementation complete, review using CHECKLIST.md.
Common Anti-Patterns to Avoid
1. Anemic Domain Model
❌ BAD - Business logic in service, entity is just data:
public class Order
{
public Guid Id { get; set; }
public decimal Total { get; set; }
public List<OrderItem> Items { get; set; }
}
public class OrderService
{
public void AddItem(Order order, Product product, int quantity)
{
var item = new OrderItem { ProductId = product.Id, Quantity = quantity };
order.Items.Add(item);
order.Total = order.Items.Sum(i => i.Subtotal);
}
}
✅ GOOD - Business logic in entity:
public class Order
{
public OrderId Id { get; private set; }
public Money Total { get; private set; }
private readonly List<OrderItem> _items = new();
public void AddItem(Product product, int quantity)
{
if (Status != OrderStatus.Draft)
throw new DomainException("Cannot add items to non-draft order");
_items.Add(OrderItem.Create(product, quantity));
RecalculateTotal();
}
}
2. Leaking Domain to Presentation
❌ BAD - Domain entity exposed in API:
[HttpGet]
public Order GetOrder(Guid id)
{
return _orderRepository.GetById(id);
}
✅ GOOD - DTO isolates presentation from domain:
[HttpGet]
public OrderDto GetOrder(Guid id)
{
var order = _orderRepository.GetById(id);
return _mapper.Map<OrderDto>(order);
}
3. Infrastructure in Domain
❌ BAD - ORM annotations pollute domain:
[Table("Orders")]
public class Order
{
[Key]
[Column("order_id")]
public Guid Id { get; set; }
}
✅ GOOD - Configuration in Infrastructure:
public class Order
{
public OrderId Id { get; private set; }
}
public class OrderConfiguration : IEntityTypeConfiguration<Order>
{
public void Configure(EntityTypeBuilder<Order> builder)
{
builder.ToTable("Orders");
builder.Property(o => o.Id).HasColumnName("order_id");
}
}
4. God Services
❌ BAD - One service does everything:
public class OrderService
{
public void CreateOrder() { }
public void CancelOrder() { }
public void ShipOrder() { }
public void ProcessPayment() { }
public void SendEmail() { }
public void GenerateInvoice() { }
}
✅ GOOD - One handler per use case:
public class CreateOrderCommandHandler : IRequestHandler<CreateOrderCommand>
public class CancelOrderCommandHandler : IRequestHandler<CancelOrderCommand>
public class ShipOrderCommandHandler : IRequestHandler<ShipOrderCommand>
5. Transaction Script
❌ BAD - Procedural, database-centric:
public void PlaceOrder(Guid customerId, List<ItemDto> items)
{
var order = new Order();
_db.Orders.Add(order);
_db.SaveChanges();
foreach (var item in items)
{
var orderItem = new OrderItem { OrderId = order.Id, ProductId = item.ProductId };
_db.OrderItems.Add(orderItem);
}
_db.SaveChanges();
var total = _db.OrderItems.Where(i => i.OrderId == order.Id).Sum(i => i.Price);
order.Total = total;
_db.SaveChanges();
}
✅ GOOD - Object-oriented, domain-centric:
public async Task<OrderId> Handle(PlaceOrderCommand request)
{
var order = Order.Create(customerId, address);
foreach (var item in request.Items)
order.AddItem(product, item.Quantity);
await _orderRepository.AddAsync(order);
await _unitOfWork.SaveChangesAsync();
return order.Id;
}
Decision Framework
When making architectural decisions, ask:
-
Does this follow the Dependency Rule?
- Inner layers independent of outer?
-
Is business logic in the domain?
- Not scattered in services or controllers?
-
Are dependencies inverted?
- Using interfaces, not concrete types?
-
Is it testable?
- Can I test without database/network?
-
Is it simple?
- Not over-engineered for current needs?
Reference Materials
Quick Decision Tree
Need to add new feature?
├─ Using Vertical Slices?
│ ├─ Yes → Create new folder: Features/{Domain}/{FeatureName}/
│ │ └─ Add: Command/Query, Handler, Validator, Response, Endpoint
│ └─ No → Traditional layers:
│ ├─ Is it business logic?
│ │ ├─ Yes → Add to Domain layer
│ │ └─ No → Is it orchestration?
│ │ ├─ Yes → Add to Application layer
│ │ └─ No → Is it technical?
│ │ ├─ Yes → Add to Infrastructure
│ │ └─ No → Add to Presentation
│
How to structure Application layer?
├─ Team size 3+? → Vertical Slices (feature-based)
├─ Frequent changes? → Vertical Slices
├─ Simple CRUD? → Traditional layers may suffice
└─ Complex domain? → Hybrid (DDD domain + Vertical Slices application)
│
Need to access data?
├─ Define interface in Domain (or Features/{Domain}/Shared/)
├─ Implement in Infrastructure
└─ Inject into Application/Handler
│
Need external service?
├─ Define port (interface) in Application
├─ Create adapter in Infrastructure
└─ Use dependency injection
│
Found business rule?
├─ Belongs to one entity? → Method on entity
├─ Spans entities? → Domain Service
└─ Application-specific? → Use Case / Handler
│
Cross-cutting concern (logging, validation)?
├─ Using MediatR? → Pipeline Behavior in Shared/Behaviors/
└─ Traditional? → Middleware or Filters
Working with This Skill
When I use this skill, I will:
- Analyze the current architecture
- Identify violations of principles
- Suggest improvements aligned with Clean Architecture
- Implement changes following the patterns
- Validate with the checklist
- Ensure proper testing strategy
Code Examples
For complete runnable code examples:
C# / .NET Examples:
Getting Started
To apply Clean Architecture to your code:
- Review existing code structure
- Identify current layer violations
- Create proper layer structure
- Move code to appropriate layers
- Apply dependency inversion
- Add tests for business logic
- Validate with checklist
Let's build maintainable, testable, and scalable software!