Files
claude-skills-reference/engineering-team/senior-architect/references/architecture_patterns.md
Alireza Rezvani 94224f2201 feat(senior-architect): Complete skill overhaul per Issue #48 (#88)
Addresses SkillzWave feedback and Anthropic best practices:

SKILL.md (343 lines):
- Third-person description with trigger phrases
- Added Table of Contents for navigation
- Concrete tool descriptions with usage examples
- Decision workflows: Database, Architecture Pattern, Monolith vs Microservices
- Removed marketing fluff, added actionable content

References (rewritten with real content):
- architecture_patterns.md: 9 patterns with trade-offs, code examples
  (Monolith, Modular Monolith, Microservices, Event-Driven, CQRS,
  Event Sourcing, Hexagonal, Clean Architecture, API Gateway)
- system_design_workflows.md: 6 step-by-step workflows
  (System Design Interview, Capacity Planning, API Design,
  Database Schema, Scalability Assessment, Migration Planning)
- tech_decision_guide.md: 7 decision frameworks with matrices
  (Database, Cache, Message Queue, Auth, Frontend, Cloud, API)

Scripts (fully functional, standard library only):
- architecture_diagram_generator.py: Mermaid + PlantUML + ASCII output
  Scans project structure, detects components, relationships
- dependency_analyzer.py: npm/pip/go/cargo support
  Circular dependency detection, coupling score calculation
- project_architect.py: Pattern detection (7 patterns)
  Layer violation detection, code quality metrics

All scripts tested and working.

Closes #48

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 10:29:14 +01:00

471 lines
14 KiB
Markdown

# Architecture Patterns Reference
Detailed guide to software architecture patterns with trade-offs and implementation guidance.
## Patterns Index
1. [Monolithic Architecture](#1-monolithic-architecture)
2. [Modular Monolith](#2-modular-monolith)
3. [Microservices Architecture](#3-microservices-architecture)
4. [Event-Driven Architecture](#4-event-driven-architecture)
5. [CQRS (Command Query Responsibility Segregation)](#5-cqrs)
6. [Event Sourcing](#6-event-sourcing)
7. [Hexagonal Architecture (Ports & Adapters)](#7-hexagonal-architecture)
8. [Clean Architecture](#8-clean-architecture)
9. [API Gateway Pattern](#9-api-gateway-pattern)
---
## 1. Monolithic Architecture
**Problem it solves:** Need to build and deploy a complete application as a single unit with minimal operational complexity.
**When to use:**
- Small team (1-5 developers)
- MVP or early-stage product
- Simple domain with clear boundaries
- Deployment simplicity is priority
**When NOT to use:**
- Multiple teams need independent deployment
- Parts of system have vastly different scaling needs
- Technology diversity is required
**Trade-offs:**
| Pros | Cons |
|------|------|
| Simple deployment | Scaling is all-or-nothing |
| Easy debugging | Large codebase becomes unwieldy |
| No network latency between components | Single point of failure |
| Simple testing | Technology lock-in |
**Structure example:**
```
monolith/
├── src/
│ ├── controllers/ # HTTP handlers
│ ├── services/ # Business logic
│ ├── repositories/ # Data access
│ ├── models/ # Domain entities
│ └── utils/ # Shared utilities
├── tests/
└── package.json
```
---
## 2. Modular Monolith
**Problem it solves:** Need monolith simplicity but with clear boundaries that enable future extraction to services.
**When to use:**
- Medium team (5-15 developers)
- Domain boundaries are becoming clearer
- Want option to extract services later
- Need better code organization than traditional monolith
**When NOT to use:**
- Already need independent deployment
- Teams can't coordinate releases
**Trade-offs:**
| Pros | Cons |
|------|------|
| Clear module boundaries | Still single deployment |
| Easier to extract services later | Requires discipline to maintain boundaries |
| Single database simplifies transactions | Can drift back to coupled monolith |
| Team ownership of modules | |
**Structure example:**
```
modular-monolith/
├── modules/
│ ├── users/
│ │ ├── api/ # Public interface
│ │ ├── internal/ # Implementation
│ │ └── index.ts # Module exports
│ ├── orders/
│ │ ├── api/
│ │ ├── internal/
│ │ └── index.ts
│ └── payments/
├── shared/ # Cross-cutting concerns
└── main.ts
```
**Key rule:** Modules communicate only through their public API, never by importing internal files.
---
## 3. Microservices Architecture
**Problem it solves:** Need independent deployment, scaling, and technology choices for different parts of the system.
**When to use:**
- Large team (15+ developers) organized around business capabilities
- Different parts need different scaling
- Independent deployment is critical
- Technology diversity is beneficial
**When NOT to use:**
- Small team that can't handle operational complexity
- Domain boundaries are unclear
- Distributed transactions are common requirement
- Network latency is unacceptable
**Trade-offs:**
| Pros | Cons |
|------|------|
| Independent deployment | Network complexity |
| Independent scaling | Distributed system challenges |
| Technology flexibility | Operational overhead |
| Team autonomy | Data consistency challenges |
| Fault isolation | Testing complexity |
**Structure example:**
```
microservices/
├── services/
│ ├── user-service/
│ │ ├── src/
│ │ ├── Dockerfile
│ │ └── package.json
│ ├── order-service/
│ └── payment-service/
├── api-gateway/
├── infrastructure/
│ ├── kubernetes/
│ └── terraform/
└── docker-compose.yml
```
**Communication patterns:**
- Synchronous: REST, gRPC
- Asynchronous: Message queues (RabbitMQ, Kafka)
---
## 4. Event-Driven Architecture
**Problem it solves:** Need loose coupling between components that react to business events asynchronously.
**When to use:**
- Components need loose coupling
- Audit trail of all changes is valuable
- Real-time reactions to events
- Multiple consumers for same events
**When NOT to use:**
- Simple CRUD operations
- Synchronous responses required
- Team unfamiliar with async patterns
- Debugging simplicity is priority
**Trade-offs:**
| Pros | Cons |
|------|------|
| Loose coupling | Eventual consistency |
| Scalability | Debugging complexity |
| Audit trail built-in | Message ordering challenges |
| Easy to add new consumers | Infrastructure complexity |
**Event structure example:**
```typescript
interface DomainEvent {
eventId: string;
eventType: string;
aggregateId: string;
timestamp: Date;
payload: Record<string, unknown>;
metadata: {
correlationId: string;
causationId: string;
};
}
// Example event
const orderCreated: DomainEvent = {
eventId: "evt-123",
eventType: "OrderCreated",
aggregateId: "order-456",
timestamp: new Date(),
payload: {
customerId: "cust-789",
items: [...],
total: 99.99
},
metadata: {
correlationId: "req-001",
causationId: "cmd-create-order"
}
};
```
---
## 5. CQRS
**Problem it solves:** Read and write workloads have different requirements and need to be optimized separately.
**When to use:**
- Read/write ratio is heavily skewed (10:1 or more)
- Read and write models differ significantly
- Complex queries that don't map to write model
- Different scaling needs for reads vs writes
**When NOT to use:**
- Simple CRUD with balanced reads/writes
- Read and write models are nearly identical
- Team unfamiliar with pattern
- Added complexity isn't justified
**Trade-offs:**
| Pros | Cons |
|------|------|
| Optimized read models | Eventual consistency between models |
| Independent scaling | Complexity |
| Simplified queries | Synchronization logic |
| Better performance | More code to maintain |
**Structure example:**
```typescript
// Write side (Commands)
interface CreateOrderCommand {
customerId: string;
items: OrderItem[];
}
class OrderCommandHandler {
async handle(cmd: CreateOrderCommand): Promise<void> {
const order = Order.create(cmd);
await this.repository.save(order);
await this.eventBus.publish(order.events);
}
}
// Read side (Queries)
interface OrderSummaryQuery {
customerId: string;
dateRange: DateRange;
}
class OrderQueryHandler {
async handle(query: OrderSummaryQuery): Promise<OrderSummary[]> {
// Query optimized read model (denormalized)
return this.readDb.query(`
SELECT * FROM order_summaries
WHERE customer_id = ? AND created_at BETWEEN ? AND ?
`, [query.customerId, query.dateRange.start, query.dateRange.end]);
}
}
```
---
## 6. Event Sourcing
**Problem it solves:** Need complete audit trail and ability to reconstruct state at any point in time.
**When to use:**
- Audit trail is regulatory requirement
- Need to answer "how did we get here?"
- Complex domain with undo/redo requirements
- Debugging production issues requires history
**When NOT to use:**
- Simple CRUD applications
- No audit requirements
- Team unfamiliar with pattern
- Reporting on current state is primary need
**Trade-offs:**
| Pros | Cons |
|------|------|
| Complete audit trail | Storage grows indefinitely |
| Time-travel debugging | Query complexity |
| Natural fit for event-driven | Learning curve |
| Enables CQRS | Eventual consistency |
**Implementation example:**
```typescript
// Events
type OrderEvent =
| { type: 'OrderCreated'; customerId: string; items: Item[] }
| { type: 'ItemAdded'; itemId: string; quantity: number }
| { type: 'OrderShipped'; trackingNumber: string };
// Aggregate rebuilt from events
class Order {
private state: OrderState;
static fromEvents(events: OrderEvent[]): Order {
const order = new Order();
events.forEach(event => order.apply(event));
return order;
}
private apply(event: OrderEvent): void {
switch (event.type) {
case 'OrderCreated':
this.state = { status: 'created', items: event.items };
break;
case 'ItemAdded':
this.state.items.push({ id: event.itemId, qty: event.quantity });
break;
case 'OrderShipped':
this.state.status = 'shipped';
this.state.trackingNumber = event.trackingNumber;
break;
}
}
}
```
---
## 7. Hexagonal Architecture
**Problem it solves:** Need to isolate business logic from external concerns (databases, APIs, UI) for testability and flexibility.
**When to use:**
- Business logic is complex and valuable
- Multiple interfaces to same domain (API, CLI, events)
- Testability is priority
- External systems may change
**When NOT to use:**
- Simple CRUD with no business logic
- Single interface to domain
- Overhead isn't justified
**Trade-offs:**
| Pros | Cons |
|------|------|
| Business logic isolation | More abstractions |
| Highly testable | Initial setup overhead |
| External systems are swappable | Can be over-engineered |
| Clear boundaries | Learning curve |
**Structure example:**
```
hexagonal/
├── domain/ # Business logic (no external deps)
│ ├── entities/
│ ├── services/
│ └── ports/ # Interfaces (what domain needs)
│ ├── OrderRepository.ts
│ └── PaymentGateway.ts
├── adapters/ # Implementations
│ ├── persistence/ # Database adapters
│ │ └── PostgresOrderRepository.ts
│ ├── payment/ # External service adapters
│ │ └── StripePaymentGateway.ts
│ └── api/ # HTTP adapters
│ └── OrderController.ts
└── config/ # Wiring it all together
```
---
## 8. Clean Architecture
**Problem it solves:** Need clear dependency rules where business logic doesn't depend on frameworks or external systems.
**When to use:**
- Long-lived applications that will outlive frameworks
- Business logic is the core value
- Team discipline to maintain boundaries
- Multiple delivery mechanisms (web, mobile, CLI)
**When NOT to use:**
- Short-lived projects
- Framework-centric applications
- Simple CRUD operations
**Trade-offs:**
| Pros | Cons |
|------|------|
| Framework independence | More code |
| Testable business logic | Can feel over-engineered |
| Clear dependency direction | Learning curve |
| Flexible delivery mechanisms | Initial setup cost |
**Dependency rule:** Dependencies point inward. Inner circles know nothing about outer circles.
```
┌─────────────────────────────────────────┐
│ Frameworks & Drivers │
│ ┌─────────────────────────────────┐ │
│ │ Interface Adapters │ │
│ │ ┌─────────────────────────┐ │ │
│ │ │ Application Layer │ │ │
│ │ │ ┌─────────────────┐ │ │ │
│ │ │ │ Entities │ │ │ │
│ │ │ │ (Domain Logic) │ │ │ │
│ │ │ └─────────────────┘ │ │ │
│ │ └─────────────────────────┘ │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────────┘
```
---
## 9. API Gateway Pattern
**Problem it solves:** Need single entry point for clients that routes to multiple backend services.
**When to use:**
- Multiple backend services
- Cross-cutting concerns (auth, rate limiting, logging)
- Different clients need different APIs
- Service aggregation needed
**When NOT to use:**
- Single backend service
- Simplicity is priority
- Team can't maintain gateway
**Trade-offs:**
| Pros | Cons |
|------|------|
| Single entry point | Single point of failure |
| Cross-cutting concerns centralized | Additional latency |
| Backend service abstraction | Complexity |
| Client-specific APIs | Can become bottleneck |
**Responsibilities:**
```
┌─────────────────────────────────────┐
│ API Gateway │
├─────────────────────────────────────┤
│ • Authentication/Authorization │
│ • Rate limiting │
│ • Request/Response transformation │
│ • Load balancing │
│ • Circuit breaking │
│ • Caching │
│ • Logging/Monitoring │
└─────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌─────┐ ┌─────┐ ┌─────┐
│Svc A│ │Svc B│ │Svc C│
└─────┘ └─────┘ └─────┘
```
---
## Pattern Selection Quick Reference
| If you need... | Consider... |
|----------------|-------------|
| Simplicity, small team | Monolith |
| Clear boundaries, future flexibility | Modular Monolith |
| Independent deployment/scaling | Microservices |
| Loose coupling, async processing | Event-Driven |
| Separate read/write optimization | CQRS |
| Complete audit trail | Event Sourcing |
| Testable, swappable externals | Hexagonal |
| Framework independence | Clean Architecture |
| Single entry point, multiple services | API Gateway |