From clean-architecture
Reviews code against Clean Architecture principles: dependency rule, layer separation, boundary crossing, and SOLID. Use for architecture review or design guidance.
How this skill is triggered — by the user, by Claude, or both
Slash command
/clean-architecture:clean-architectureThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill analyzes and reviews code based on Robert C. Martin's (Uncle Bob) Clean Architecture principles.
This skill analyzes and reviews code based on Robert C. Martin's (Uncle Bob) Clean Architecture principles.
First, understand the project's directory structure:
Core Principle: Source code dependencies must only point inward (toward higher-level policies).
┌─────────────────────────────────────────────────────────┐
│ Frameworks & Drivers │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Interface Adapters │ │
│ │ ┌─────────────────────────────────────────┐ │ │
│ │ │ Use Cases │ │ │
│ │ │ ┌─────────────────────────────────┐ │ │ │
│ │ │ │ Entities │ │ │ │
│ │ │ └─────────────────────────────────┘ │ │ │
│ │ └─────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
← Dependencies flow inward
Checklist:
The flow of control and source code dependency can point in opposite directions.
Controller → Use Case → Presenter
↓ ↓ ↑
[dependency] [dependency] [inverted!]
Example: When Use Case needs to call Presenter
// Use Case Layer (inner)
interface OrderOutputPort {
presentOrder(order: OrderData): void;
}
class CreateOrderUseCase {
constructor(private outputPort: OrderOutputPort) {}
execute() {
// ... business logic
this.outputPort.presentOrder(orderData);
}
}
// Adapter Layer (outer) - depends on Use Case
class OrderPresenter implements OrderOutputPort {
presentOrder(order: OrderData): void {
// Transform for UI
}
}
Principle: Data crossing boundaries should be simple data structures (DTOs).
// Bad: Passing Entity directly
class GetUserUseCase {
execute(): User { // Returning Entity directly
return this.userRepository.findById(id);
}
}
// Good: Transform to DTO
class GetUserUseCase {
execute(): UserResponseDTO { // Simple data structure
const user = this.userRepository.findById(id);
return { id: user.id, name: user.name };
}
}
Checklist:
Checklist:
Checklist:
Checklist:
Checklist:
Object-oriented design principles used in Clean Architecture implementation. DIP is essential for Crossing Boundaries.
| Principle | Description | Clean Architecture Relevance |
|---|---|---|
| SRP | A class should have only one reason to change | Layer responsibility separation |
| OCP | Open for extension, closed for modification | Extension through interfaces |
| LSP | Subtypes must be substitutable for base types | Implementation replaceability |
| ISP | Don't depend on interfaces you don't use | Port interface segregation |
| DIP | Depend on abstractions, not concretions | Core of Crossing Boundaries |
Provide review results in this format:
# Clean Architecture Review Report
## Summary
- Overall Assessment: [Good/Needs Improvement/Critical]
- Key findings summary
## Dependency Rule Analysis
- List of violations
- Improvement suggestions
## Layer Structure Review
### Entities: [Good/Needs Improvement]
### Use Cases: [Good/Needs Improvement]
### Interface Adapters: [Good/Needs Improvement]
### Infrastructure: [Good/Needs Improvement]
## Recommendations
1. High priority improvements
2. Medium priority improvements
3. Long-term suggestions
Always consider these questions during review:
Ask yourself if you're really benefiting from Clean Architecture:
// Good: Dependency Inversion
interface UserRepository {
findById(id: string): Promise<User>;
}
class GetUserUseCase {
constructor(private userRepository: UserRepository) {}
}
// Bad: Depending on concrete implementation
class GetUserUseCase {
constructor(private userRepository: PostgresUserRepository) {}
}
# Good: Interface definition using Protocol
from typing import Protocol
class UserRepository(Protocol):
def find_by_id(self, id: str) -> User: ...
# Bad: Direct implementation import
from infrastructure.postgres import PostgresUserRepository
// Good: Interface segregation
interface UserRepository {
fun findById(id: String): User?
}
class GetUserUseCase(
private val userRepository: UserRepository
)
// Bad: Using concrete implementation
class GetUserUseCase(
private val userRepository: JpaUserRepository
)
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub nathankim0/clean-architecture-skills --plugin clean-architecture