Why Document Architecture?
Architecture documentation communicates the structure, decisions, and constraints of a system to current and future team members. The goal is not to create exhaustive documents but to produce the right amount of documentation that helps people understand, build, and evolve the system effectively.
Documentation Principles
- Just enough: Document what matters — avoid BDUF (Big Design Up Front) documents that nobody reads
- Living documents: Keep documentation close to code and update it as the system evolves
- Multiple views: Different stakeholders need different levels of detail and perspectives
- Decisions over descriptions: Capture WHY decisions were made, not just WHAT was built
The C4 Model
The C4 model, created by Simon Brown, provides four levels of abstraction for visualizing software architecture. Like maps, you zoom in from a high-level overview to detailed code-level views.
C4 Levels
| Level | Name | Audience | Shows |
|---|---|---|---|
| 1 | System Context | Everyone | How your system fits in the world |
| 2 | Container | Technical people | High-level technology choices and communication |
| 3 | Component | Developers | Components inside a container and their interactions |
| 4 | Code | Developers | Classes, interfaces, and their relationships |
Documentation as Code with Structurizr DSL
// Structurizr DSL - Architecture as code
// workspace.dsl
// This is not TypeScript but shows the documentation-as-code approach
// workspace {
// model {
// customer = person "Customer" "A user of the e-commerce platform"
// admin = person "Admin" "Platform administrator"
//
// ecommerce = softwareSystem "E-Commerce Platform" {
// webapp = container "Web Application" "Next.js" "React, TypeScript"
// api = container "API Gateway" "Express.js" "Node.js"
// orderService = container "Order Service" "Handles order lifecycle"
// paymentService = container "Payment Service" "Processes payments"
// db = container "Database" "PostgreSQL" "Relational database"
// cache = container "Cache" "Redis" "Session and data cache"
// queue = container "Message Queue" "RabbitMQ" "Async communication"
// }
//
// stripe = softwareSystem "Stripe" "Payment processing" "External"
// email = softwareSystem "SendGrid" "Email delivery" "External"
//
// customer -> webapp "Uses"
// webapp -> api "Makes API calls" "HTTPS/JSON"
// api -> orderService "Routes requests"
// api -> paymentService "Routes requests"
// orderService -> db "Reads/writes"
// orderService -> queue "Publishes events"
// paymentService -> stripe "Processes payments" "HTTPS"
// paymentService -> queue "Publishes events"
// }
// }
// TypeScript approach: Generate documentation from code
interface SystemContext {
system: string;
description: string;
users: Array<{ name: string; role: string; interaction: string }>;
externalSystems: Array<{ name: string; purpose: string; protocol: string }>;
}
interface ContainerDiagram {
containers: Array<{
name: string;
technology: string;
purpose: string;
communicatesWith: Array<{ target: string; protocol: string; purpose: string }>;
}>;
}
// Auto-generate from actual code structure
function generateArchitectureDocs(
projectRoot: string
): ArchitectureDocumentation {
const modules = scanModules(projectRoot);
const dependencies = analyzeDependencies(modules);
const apis = extractAPIEndpoints(projectRoot);
return {
systemContext: generateSystemContext(modules, dependencies),
containerDiagram: generateContainerDiagram(modules),
componentDiagrams: modules.map(m => generateComponentDiagram(m)),
apiDocumentation: generateOpenAPISpec(apis),
deploymentDiagram: generateDeploymentDiagram(projectRoot),
};
}
arc42 Template
The arc42 template is a practical and pragmatic architecture documentation framework. It provides 12 sections covering everything from requirements to deployment, but you only need to fill in the sections relevant to your project.
// arc42 sections as a TypeScript structure
interface Arc42Documentation {
// 1. Introduction and Goals
introduction: {
requirements: string[];
qualityGoals: Array<{ goal: string; priority: number; scenario: string }>;
stakeholders: Array<{ name: string; role: string; expectations: string }>;
};
// 2. Architecture Constraints
constraints: {
technical: string[]; // "Must run on AWS", "Must use PostgreSQL"
organizational: string[]; // "Team of 5 developers", "2-week sprints"
conventions: string[]; // "REST APIs", "TypeScript only"
};
// 3. System Scope and Context
context: {
businessContext: SystemContext;
technicalContext: ContainerDiagram;
};
// 4. Solution Strategy
solutionStrategy: {
technologyDecisions: string[];
architecturePatterns: string[];
qualityApproaches: string[];
};
// 5. Building Block View (C4 Levels 2-3)
buildingBlocks: {
level1: ContainerDiagram;
level2: Record;
};
// 6-12: Deployment, Cross-cutting, Decisions, Quality, Risks, Glossary
}
Documentation Best Practices
- Start with decisions: Architecture Decision Records (ADRs) are the most valuable documentation — start there
- Keep it close to code: Store documentation in the repository alongside the code it describes
- Automate what you can: Generate API docs from OpenAPI specs, diagrams from code analysis
- Review documentation: Include documentation updates in code reviews
- Use diagrams wisely: A well-labeled diagram communicates more than pages of text