Architecture Skill
Purpose: Apply proven architectural patterns for scalable, maintainable systems using industry-standard methodologies
Overview
This skill provides deep guidance for designing software architectures using Domain-Driven Design, Clean Architecture, the 12-Factor App methodology, event-driven patterns, and SOLID principles.
Architectural Patterns
1. Layered Architecture
┌─────────────────────────┐
│ Presentation Layer │ ← Controllers, Views, API endpoints
├─────────────────────────┤
│ Application Layer │ ← Use Cases, Services, Orchestration
├─────────────────────────┤
│ Domain Layer │ ← Entities, Business Logic, Domain Events
├─────────────────────────┤
│ Infrastructure Layer │ ← Database, External APIs, Messaging
└─────────────────────────┘
Rule: Each layer ONLY imports from the layer directly below it. Never skip layers.
2. Clean Architecture
┌─────────────┐
│ Frameworks │ ← Web, DB, UI (outermost)
┌─┤ ├─┐
│ │ Adapters │ │ ← Controllers, Gateways, Presenters
┌─┤ │ │ ├─┐
│ │ │ Use Cases │ │ │ ← Application business rules
┌─┤ │ │ │ │ ├─┐
│ │ │ │ Entities │ │ │ │ ← Core business objects (innermost)
└─┤ │ │ │ │ ├─┘
└─┤ │ │ ├─┘
└─┤ ├─┘
└─────────────┘
Dependency Rule: Source code dependencies ALWAYS point inward. Inner layers know nothing about outer layers.
3. Hexagonal Architecture (Ports & Adapters)
┌─────────────────┐
──────│ Ports │──────
Input │ (Interfaces) │ Output
Ports │ │ Ports
│ Domain Core │
│ │
──────│ Adapters │──────
Input │ (Implementations)│ Output
Adapters Adapters
└─────────────────┘
Key Insight: The domain core defines ports (interfaces). Adapters implement them. This makes the domain testable without infrastructure.
Domain-Driven Design (DDD)
Strategic DDD — Bounded Contexts
| Concept |
Definition |
Example |
| Bounded Context |
A boundary within which a domain model is consistent |
"Order" means different things in Sales vs Shipping |
| Ubiquitous Language |
Shared vocabulary within a bounded context |
"Customer" in Sales = "Recipient" in Shipping |
| Context Map |
Visual map of relationships between bounded contexts |
Sales ← Customer/Supplier → Fulfillment |
| Anti-Corruption Layer |
Translation layer between contexts with different models |
Adapter that maps external API models to domain models |
Tactical DDD — Building Blocks
| Building Block |
Purpose |
Rules |
| Entity |
Object with identity that persists over time |
Has unique ID, mutable state, lifecycle |
| Value Object |
Immutable object defined by its attributes |
No ID, compared by value, always valid |
| Aggregate |
Cluster of entities with a root that enforces invariants |
External access only through root, transactional consistency |
| Repository |
Interface for aggregate persistence |
One per aggregate, hides storage details |
| Domain Service |
Stateless logic spanning multiple aggregates |
When logic doesn't belong to a single entity |
| Domain Event |
Record of something that happened in the domain |
Immutable, past tense (OrderPlaced, PaymentReceived) |
| Factory |
Complex object/aggregate creation |
Encapsulates creation logic and invariant enforcement |
Aggregate Design Rules
- Protect invariants within aggregate boundaries — All business rules enforced by the aggregate root
- Reference other aggregates by ID only — Never hold direct object references across aggregate boundaries
- One transaction per aggregate — Don't modify multiple aggregates in a single transaction
- Design small aggregates — Smaller = less contention, better scalability
- Use eventual consistency between aggregates — Domain events for cross-aggregate communication
12-Factor App Methodology
| Factor |
Principle |
Implementation |
| I. Codebase |
One codebase tracked in VCS, many deploys |
Git repo, branches for environments |
| II. Dependencies |
Explicitly declare and isolate dependencies |
package.json + lockfile, no global installs |
| III. Config |
Store config in the environment |
process.env.*, never in code |
| IV. Backing Services |
Treat backing services as attached resources |
Database URL as environment variable |
| V. Build, Release, Run |
Strictly separate build and run stages |
CI builds artifact → deploy artifact → run |
| VI. Processes |
Execute the app as stateless processes |
No sticky sessions, no in-memory state between requests |
| VII. Port Binding |
Export services via port binding |
app.listen(PORT), no container-specific coupling |
| VIII. Concurrency |
Scale out via the process model |
Horizontal scaling, not bigger machines |
| IX. Disposability |
Maximize robustness with fast startup and graceful shutdown |
SIGTERM handler, connection draining |
| X. Dev/Prod Parity |
Keep development, staging, and production as similar as possible |
Same database, same services, Docker |
| XI. Logs |
Treat logs as event streams |
Write to stdout, let platform aggregate |
| XII. Admin Processes |
Run admin/management tasks as one-off processes |
Database migrations, data fixes as scripts |
Event-Driven Architecture
Pattern Selection
| Pattern |
Use When |
Complexity |
Consistency |
| Request/Response |
Synchronous, simple operations |
Low |
Strong |
| Event Notification |
Inform other services something happened |
Low |
Eventual |
| Event-Carried State Transfer |
Share data without coupling to source |
Medium |
Eventual |
| Event Sourcing |
Full audit trail, state reconstruction |
High |
Strong (per aggregate) |
| CQRS |
Different read/write models needed |
Medium-High |
Eventual (between models) |
Event Design Principles
- Events are facts — Something that happened (past tense:
OrderPlaced, not PlaceOrder)
- Events are immutable — Never modify or delete events
- Events carry sufficient data — Include everything consumers need (avoid callbacks)
- Events have schemas — Version and validate event structures
- Events are ordered within an aggregate — Global ordering is optional and expensive
Design Principles
SOLID — Applied
| Principle |
Description |
Violation Smell |
Fix |
| Single Responsibility |
One reason to change |
Class does file I/O AND business logic |
Split into Repository + Service |
| Open/Closed |
Open for extension, closed for modification |
if/else chain for new types |
Strategy pattern, polymorphism |
| Liskov Substitution |
Subtypes must be substitutable |
Subclass throws unexpected exception |
Respect base class contract |
| Interface Segregation |
Many specific interfaces |
God interface with 20 methods |
Split into focused interfaces |
| Dependency Inversion |
Depend on abstractions |
Service directly imports Prisma client |
Inject Repository interface |
Additional Principles
- DRY: Don't Repeat Yourself — Extract shared logic, but avoid premature abstraction
- KISS: Keep It Simple — Prefer straightforward solutions over clever ones
- YAGNI: You Aren't Gonna Need It — Don't build for hypothetical future requirements
Module Structure (DDD-Aligned)
src/
├── domain/ # Core business logic (no framework imports)
│ ├── entities/ # Entities with identity
│ ├── value-objects/ # Immutable value types
│ ├── events/ # Domain events
│ ├── services/ # Domain services
│ └── repositories/ # Repository interfaces (ports)
├── application/ # Use cases / application services
│ ├── commands/ # Write operations
│ ├── queries/ # Read operations
│ └── handlers/ # Command/query handlers
├── infrastructure/ # External concerns (adapters)
│ ├── database/ # Repository implementations
│ ├── messaging/ # Event bus, message queues
│ ├── external-apis/ # Third-party integrations
│ └── config/ # Environment configuration
└── interfaces/ # Entry points (driving adapters)
├── http/ # REST/GraphQL controllers
├── events/ # Event consumers
└── cli/ # CLI commands
Architecture Decision Records (ADRs)
When to Write an ADR
- Choosing between architectural approaches (monolith vs microservices)
- Selecting a technology (PostgreSQL vs MongoDB)
- Establishing a pattern (event sourcing vs CRUD)
- Making a trade-off (consistency vs availability)
ADR Template
# ADR-NNN: [Decision Title]
**Status**: Proposed | Accepted | Deprecated | Superseded by ADR-XXX
**Date**: YYYY-MM-DD
**Context**: [What is the issue? What constraints exist?]
**Decision**: [What was decided?]
**Consequences**: [What are the trade-offs? What becomes easier/harder?]
**Alternatives Considered**: [What was rejected and why?]
Quick Reference
| Pattern |
When to Use |
| Monolith |
MVP, small team, simple domain |
| Modular Monolith |
Growing team, clear bounded contexts, not ready for distributed |
| Microservices |
Large team, independent scaling, domain maturity |
| Event-Driven |
Async workflows, decoupling, audit requirements |
| CQRS |
Different read/write patterns, high-traffic reads |
| Serverless |
Variable load, cost optimization, simple functions |
| Event Sourcing |
Audit trail, state reconstruction, complex domain |
1---2name: architecture3description: System design patterns, DDD, 12-Factor App, SOLID principles, event-driven architecture, and architectural decision frameworks4---56# Architecture Skill78> **Purpose**: Apply proven architectural patterns for scalable, maintainable systems using industry-standard methodologies910---1112## Overview1314This skill provides deep guidance for designing software architectures using Domain-Driven Design, Clean Architecture, the 12-Factor App methodology, event-driven patterns, and SOLID principles.1516---1718## Architectural Patterns1920### 1. Layered Architecture2122```23┌─────────────────────────┐24│ Presentation Layer │ ← Controllers, Views, API endpoints25├─────────────────────────┤26│ Application Layer │ ← Use Cases, Services, Orchestration27├─────────────────────────┤28│ Domain Layer │ ← Entities, Business Logic, Domain Events29├─────────────────────────┤30│ Infrastructure Layer │ ← Database, External APIs, Messaging31└─────────────────────────┘32```3334**Rule**: Each layer ONLY imports from the layer directly below it. Never skip layers.3536### 2. Clean Architecture3738```39 ┌─────────────┐40 │ Frameworks │ ← Web, DB, UI (outermost)41 ┌─┤ ├─┐42 │ │ Adapters │ │ ← Controllers, Gateways, Presenters43 ┌─┤ │ │ ├─┐44 │ │ │ Use Cases │ │ │ ← Application business rules45 ┌─┤ │ │ │ │ ├─┐46 │ │ │ │ Entities │ │ │ │ ← Core business objects (innermost)47 └─┤ │ │ │ │ ├─┘48 └─┤ │ │ ├─┘49 └─┤ ├─┘50 └─────────────┘51```5253**Dependency Rule**: Source code dependencies ALWAYS point inward. Inner layers know nothing about outer layers.5455### 3. Hexagonal Architecture (Ports & Adapters)5657```58 ┌─────────────────┐59 ──────│ Ports │──────60 Input │ (Interfaces) │ Output61 Ports │ │ Ports62 │ Domain Core │63 │ │64 ──────│ Adapters │──────65 Input │ (Implementations)│ Output66 Adapters Adapters67 └─────────────────┘68```6970**Key Insight**: The domain core defines ports (interfaces). Adapters implement them. This makes the domain testable without infrastructure.7172---7374## Domain-Driven Design (DDD)7576### Strategic DDD — Bounded Contexts7778| Concept | Definition | Example |79|:--------|:-----------|:--------|80| **Bounded Context** | A boundary within which a domain model is consistent | "Order" means different things in Sales vs Shipping |81| **Ubiquitous Language** | Shared vocabulary within a bounded context | "Customer" in Sales = "Recipient" in Shipping |82| **Context Map** | Visual map of relationships between bounded contexts | Sales ← Customer/Supplier → Fulfillment |83| **Anti-Corruption Layer** | Translation layer between contexts with different models | Adapter that maps external API models to domain models |8485### Tactical DDD — Building Blocks8687| Building Block | Purpose | Rules |88|:--------------|:--------|:------|89| **Entity** | Object with identity that persists over time | Has unique ID, mutable state, lifecycle |90| **Value Object** | Immutable object defined by its attributes | No ID, compared by value, always valid |91| **Aggregate** | Cluster of entities with a root that enforces invariants | External access only through root, transactional consistency |92| **Repository** | Interface for aggregate persistence | One per aggregate, hides storage details |93| **Domain Service** | Stateless logic spanning multiple aggregates | When logic doesn't belong to a single entity |94| **Domain Event** | Record of something that happened in the domain | Immutable, past tense (OrderPlaced, PaymentReceived) |95| **Factory** | Complex object/aggregate creation | Encapsulates creation logic and invariant enforcement |9697### Aggregate Design Rules98991. **Protect invariants within aggregate boundaries** — All business rules enforced by the aggregate root1002. **Reference other aggregates by ID only** — Never hold direct object references across aggregate boundaries1013. **One transaction per aggregate** — Don't modify multiple aggregates in a single transaction1024. **Design small aggregates** — Smaller = less contention, better scalability1035. **Use eventual consistency between aggregates** — Domain events for cross-aggregate communication104105---106107## 12-Factor App Methodology108109| Factor | Principle | Implementation |110|:-------|:----------|:--------------|111| **I. Codebase** | One codebase tracked in VCS, many deploys | Git repo, branches for environments |112| **II. Dependencies** | Explicitly declare and isolate dependencies | `package.json` + lockfile, no global installs |113| **III. Config** | Store config in the environment | `process.env.*`, never in code |114| **IV. Backing Services** | Treat backing services as attached resources | Database URL as environment variable |115| **V. Build, Release, Run** | Strictly separate build and run stages | CI builds artifact → deploy artifact → run |116| **VI. Processes** | Execute the app as stateless processes | No sticky sessions, no in-memory state between requests |117| **VII. Port Binding** | Export services via port binding | `app.listen(PORT)`, no container-specific coupling |118| **VIII. Concurrency** | Scale out via the process model | Horizontal scaling, not bigger machines |119| **IX. Disposability** | Maximize robustness with fast startup and graceful shutdown | `SIGTERM` handler, connection draining |120| **X. Dev/Prod Parity** | Keep development, staging, and production as similar as possible | Same database, same services, Docker |121| **XI. Logs** | Treat logs as event streams | Write to stdout, let platform aggregate |122| **XII. Admin Processes** | Run admin/management tasks as one-off processes | Database migrations, data fixes as scripts |123124---125126## Event-Driven Architecture127128### Pattern Selection129130| Pattern | Use When | Complexity | Consistency |131|:--------|:---------|:-----------|:-----------|132| **Request/Response** | Synchronous, simple operations | Low | Strong |133| **Event Notification** | Inform other services something happened | Low | Eventual |134| **Event-Carried State Transfer** | Share data without coupling to source | Medium | Eventual |135| **Event Sourcing** | Full audit trail, state reconstruction | High | Strong (per aggregate) |136| **CQRS** | Different read/write models needed | Medium-High | Eventual (between models) |137138### Event Design Principles1391401. **Events are facts** — Something that happened (past tense: `OrderPlaced`, not `PlaceOrder`)1412. **Events are immutable** — Never modify or delete events1423. **Events carry sufficient data** — Include everything consumers need (avoid callbacks)1434. **Events have schemas** — Version and validate event structures1445. **Events are ordered within an aggregate** — Global ordering is optional and expensive145146---147148## Design Principles149150### SOLID — Applied151152| Principle | Description | Violation Smell | Fix |153|:----------|:-----------|:---------------|:----|154| **S**ingle Responsibility | One reason to change | Class does file I/O AND business logic | Split into Repository + Service |155| **O**pen/Closed | Open for extension, closed for modification | `if/else` chain for new types | Strategy pattern, polymorphism |156| **L**iskov Substitution | Subtypes must be substitutable | Subclass throws unexpected exception | Respect base class contract |157| **I**nterface Segregation | Many specific interfaces | God interface with 20 methods | Split into focused interfaces |158| **D**ependency Inversion | Depend on abstractions | Service directly imports Prisma client | Inject Repository interface |159160### Additional Principles161162- **DRY**: Don't Repeat Yourself — Extract shared logic, but avoid premature abstraction163- **KISS**: Keep It Simple — Prefer straightforward solutions over clever ones164- **YAGNI**: You Aren't Gonna Need It — Don't build for hypothetical future requirements165166---167168## Module Structure (DDD-Aligned)169170```171src/172├── domain/ # Core business logic (no framework imports)173│ ├── entities/ # Entities with identity174│ ├── value-objects/ # Immutable value types175│ ├── events/ # Domain events176│ ├── services/ # Domain services177│ └── repositories/ # Repository interfaces (ports)178├── application/ # Use cases / application services179│ ├── commands/ # Write operations180│ ├── queries/ # Read operations181│ └── handlers/ # Command/query handlers182├── infrastructure/ # External concerns (adapters)183│ ├── database/ # Repository implementations184│ ├── messaging/ # Event bus, message queues185│ ├── external-apis/ # Third-party integrations186│ └── config/ # Environment configuration187└── interfaces/ # Entry points (driving adapters)188 ├── http/ # REST/GraphQL controllers189 ├── events/ # Event consumers190 └── cli/ # CLI commands191```192193---194195## Architecture Decision Records (ADRs)196197### When to Write an ADR198199- Choosing between architectural approaches (monolith vs microservices)200- Selecting a technology (PostgreSQL vs MongoDB)201- Establishing a pattern (event sourcing vs CRUD)202- Making a trade-off (consistency vs availability)203204### ADR Template205206```markdown207# ADR-NNN: [Decision Title]208209**Status**: Proposed | Accepted | Deprecated | Superseded by ADR-XXX210**Date**: YYYY-MM-DD211**Context**: [What is the issue? What constraints exist?]212**Decision**: [What was decided?]213**Consequences**: [What are the trade-offs? What becomes easier/harder?]214**Alternatives Considered**: [What was rejected and why?]215```216217---218219## Quick Reference220221| Pattern | When to Use |222|:--------|:-----------|223| Monolith | MVP, small team, simple domain |224| Modular Monolith | Growing team, clear bounded contexts, not ready for distributed |225| Microservices | Large team, independent scaling, domain maturity |226| Event-Driven | Async workflows, decoupling, audit requirements |227| CQRS | Different read/write patterns, high-traffic reads |228| Serverless | Variable load, cost optimization, simple functions |229| Event Sourcing | Audit trail, state reconstruction, complex domain |