Transform hub-guide from a single-skill Hub monorepo guide into a comprehensive programming best-practice plugin covering all situations. Skills (26): - Core: engineering-principles, clean-code, clean-architecture, design-patterns, testing, error-handling, security, api-design, git-workflow, documentation, logging-observability, performance - Languages: typescript, python, rust, go - Frameworks: react-frontend, elysiajs, hono-backend, drizzle-database, nextjs - Infrastructure: docker, ci-cd, monitoring - Monorepo: monorepo, hub-guide (existing) Hooks: - SessionStart: auto-detect project type and activate relevant skills - PreToolUse (Write|Edit): inject language-specific rules per file type Reference files for deep dives: - clean-architecture/references/solid.md (SOLID + component principles) - design-patterns/references/catalog.md (full GoF catalog with examples) - testing/references/mocks.md (test double taxonomy) Restructure plugin to modern skills/ directory format.
95 lines
4.5 KiB
Markdown
95 lines
4.5 KiB
Markdown
---
|
|
name: clean-architecture
|
|
description: Apply Clean Architecture, hexagonal architecture, and SOLID principles when designing system boundaries, modules, or microservices. Use when structuring a new service, deciding what a component should own, untangling framework coupling, or whenever the user mentions "clean architecture," "hexagonal architecture," "onion architecture," "ports and adapters," "SOLID," "Dependency Rule," or "architecture boundaries."
|
|
---
|
|
|
|
# Clean Architecture
|
|
|
|
Keep business rules independent of frameworks, databases, and UI.
|
|
|
|
## The Dependency Rule
|
|
|
|
**Source code dependencies must point inward.** Nothing in an inner circle can know about something in an outer circle.
|
|
|
|
```
|
|
┌──────────────────────────────┐
|
|
│ Framework / DB / UI / IO │ ← outer: frameworks, drivers, devices
|
|
│ ┌──────────────────────────┐ │
|
|
│ │ Interface Adapters │ │ ← presenters, controllers, gateways
|
|
│ │ ┌──────────────────────┐ │ │
|
|
│ │ │ Application (Use Cases) │ │ ← orchestrate business flows
|
|
│ │ │ ┌──────────────────┐ │ │ │
|
|
│ │ │ │ Domain / Entities│ │ │ │ ← pure business rules, no deps
|
|
│ │ │ └──────────────────┘ │ │ │
|
|
│ │ └──────────────────────┘ │ │
|
|
│ └──────────────────────────┘ │
|
|
└──────────────────────────────┘
|
|
```
|
|
|
|
## Key Rules
|
|
|
|
1. **Domain layer** contains business entities and value objects. Zero framework imports. Zero database imports. Pure types and functions.
|
|
2. **Application layer** contains use cases — orchestrate domain objects to fulfill business flows. Depends only on domain. Declares ports (interfaces) for IO.
|
|
3. **Interface adapters** translate between use cases and the outside world — controllers, presenters, gateways. Depends on application layer + frameworks.
|
|
4. **Infrastructure/Framework layer** implements the ports declared by the application layer — database repos, HTTP clients, message queues.
|
|
5. **Screaming Architecture:** the project structure should scream "this is a [domain context]" — not "this is a Spring/Next.js/Django project."
|
|
|
|
## How to Check
|
|
|
|
- Can you swap the database without changing business logic? If not, boundary is violated.
|
|
- Can you unit-test a use case without spinning up a framework? If not, your use case depends on infrastructure.
|
|
- Do business entities import anything from the web framework or ORM? If so, revert that dependency.
|
|
|
|
## Practical Patterns
|
|
|
|
### Port-Adapter
|
|
```typescript
|
|
// Domain/Application port (declared here, implemented outside)
|
|
interface UserRepository {
|
|
findById(id: string): Promise<User | null>;
|
|
}
|
|
// Infrastructure adapter (implemented in infra layer)
|
|
class PostgresUserRepository implements UserRepository { ... }
|
|
```
|
|
|
|
### Use Case
|
|
```typescript
|
|
class CreateOrderUseCase {
|
|
constructor(private readonly repo: OrderRepository) {}
|
|
async execute(input: CreateOrderInput): Promise<Order> {
|
|
const order = Order.create(input.items, input.customerId);
|
|
return this.repo.save(order);
|
|
}
|
|
}
|
|
```
|
|
|
|
### Dependency Injection
|
|
Wire dependencies at the composition root — never in use cases or domain.
|
|
```typescript
|
|
// Composition Root
|
|
const orderRepo = new PostgresOrderRepository(db);
|
|
const createOrder = new CreateOrderUseCase(orderRepo);
|
|
```
|
|
|
|
## SOLID (Quick Ref)
|
|
|
|
- **SRP:** A class has one reason to change (one actor).
|
|
- **OCP:** Open for extension, closed for modification (polymorphism + strategy).
|
|
- **LSP:** Subtypes must be substitutable for their base types.
|
|
- **ISP:** Don't depend on interfaces you don't use (keep interfaces focused).
|
|
- **DIP:** Depend on abstractions, not concretions. Business rules don't import frameworks.
|
|
|
|
## Deeper Reference
|
|
|
|
When the task calls for it, load:
|
|
|
|
- **[references/solid.md](references/solid.md)** — Full SOLID treatment (SRP, OCP, LSP, ISP, DIP). Component principles (REP, CCP, CRP, ADP, SDP, SAP). Examples for each principle, historical evolution, and practical tests for violations.
|
|
|
|
## Anti-patterns
|
|
|
|
- ❌ Business logic in route handlers or controllers
|
|
- ❌ ORM entities directly exposed to the UI
|
|
- ❌ Database queries mixed into use cases
|
|
- ❌ Framework decorators on domain entities
|
|
- ❌ "Everything is a CRUD" — missing use case layer
|