Architectural Decision Records: Capture Why Your Code Is the Way It Is
Every seasoned engineer has experienced the "archaeology phase" of a project. You’re looking at a specific abstraction—perhaps a custom implementation of a message queue or a strict hexagonal architecture in a small microservice—and you find yourself asking: Why is the code structured this way?
You check the git blame. The commit message simply says "initial implementation" or "refactor." You search Slack, only to find a three-year-old thread that ends with "Let’s hop on a call to finalize this." The context is gone. The engineers who made the choice have moved on, and you are left to maintain a system whose foundational logic is a mystery.
In software engineering, code tells you what the system does. Tests tell you if it works. But only Architectural Decision Records (ADRs) tell you why it exists in its current form. Without them, your codebase becomes a collection of "Chesterton’s Fences"—structures you’re afraid to change because you don’t understand why they were built in the first place.
The "Why" Problem in Software Engineering
The most expensive part of software development isn't writing code; it's understanding it. As systems grow, the delta between the code's current state and the developer's mental model widens.
Code Tells You What, Not Why
Modern programming languages are expressive, but they are limited to functional intent. A line of code like retry_strategy = ExponentialBackoff(max_attempts=5) tells you the mechanism. It does not tell you that you chose 5 attempts because the downstream legacy API has a specific rate-limiting window that resets every 60 seconds. Documentation often focuses on "how to use" rather than "why we built it like this."
Decisions Get Lost in Slack Threads and Meetings
Architectural decisions are often the byproduct of high-bandwidth, ephemeral communication. A design doc might be written in Notion, discussed in a Zoom call, and finalized in a private Slack channel. Six months later, that Notion doc is outdated, and the Slack history is buried under thousands of unrelated messages. This fragmentation of context is the primary driver of technical debt.
New Team Members Ask the Same Questions
Onboarding a senior engineer involves more than just teaching them the tech stack. It involves transferring the "lore" of the codebase. Why do we avoid using ORMs in the billing service? Why did we choose Kafka over RabbitMQ? When these answers aren't documented as architectural decision records, senior engineers spend 30% of their time acting as human search engines for historical context.
The Anatomy of an Architectural Decision
What Are Architectural Decision Records (ADRs)?
An ADR is a short text file that captures a significant architectural decision, its context, and its consequences. Unlike a 50-page Design Document that covers an entire project, an ADR is focused, immutable (once finalized), and version-controlled alongside the code.
The ADR Format
While there are many variations, a standard ADR usually follows the "Nygard" template:
- Title: Short and descriptive (e.g., "Use PostgreSQL for Metadata Storage").
- Status: Proposed, Accepted, Deprecated, or Superseded.
- Context: What is the problem? What are the constraints? What alternatives were considered?
- Decision: What are we doing?
- Consequences: What is the "tax" we pay for this? What do we gain?
Examples of Good ADRs
A good ADR doesn't just justify the "best" choice; it explains why a seemingly "worse" choice was made due to specific constraints. For instance, an ADR might explain: "We are using a monolithic repository (Monorepo) despite our team size because our deployment pipeline currently lacks the sophisticated versioning required for cross-repo dependency management."
When to Write an ADR
You shouldn't write an ADR for every pull request. Save them for "one-way door" decisions—choices that are difficult or expensive to reverse. Examples include:
- Choosing a primary database or message broker.
- Defining the communication pattern (REST vs. gRPC vs. GraphQL).
- Selecting a core framework (e.g., choosing FastAPI over Django).
- Adopting a specific testing or deployment strategy.
To see how these decisions manifest in a real-world system, you can explore repowise's architecture, which details how we handle complex codebase intelligence.
Mining Git History for Implicit Decisions
The challenge for most teams is that they already have a massive codebase with zero ADRs. You can't go back in time to document every decision made over the last three years—but the information is there, hidden in your git history.
Large Commits Often Contain Decisions
When a developer changes 50 files and swaps out a library, that is a physical manifestation of an architectural decision. By analyzing commit density and "churn," we can identify inflection points where the architecture shifted.
Migration Patterns Reveal Architecture Choices
If a codebase shows a steady migration of files from a services/ directory to a domain/ directory, it's a clear signal of a shift toward Domain-Driven Design (DDD). Even if no one wrote it down, the git history "remembers" the intent.
Dependency Changes Signal Strategy Shifts
The addition of a library like Zod or Pydantic signals a decision to move toward schema-driven development and runtime validation. Tracking when these dependencies enter a codebase—and which files they touch first—allows us to reconstruct the "why." You can see this in action by viewing the FastAPI dependency graph demo, which visualizes how core libraries anchor a system.
Git Intelligence & Decision Mining
How repowise Detects Architectural Decisions
At repowise, we believe that documentation should be a byproduct of development, not a chore. Our platform uses "Git Intelligence" to bridge the gap between silent code and documented intent.
Analyzing Commit Patterns
repowise doesn't just look at the code; it mines the history. By correlating commit messages with structural changes, it identifies "High-Impact Decisions." If a commit message discusses "performance" and is accompanied by a change in the database indexing strategy, repowise flags this as a potential architectural pivot.
Identifying Decision Points
Using PageRank and community detection on the dependency graph, repowise identifies the "gravity centers" of your code. When changes happen at these centers, they are likely architectural. Repowise monitors these points to detect when the fundamental "contract" of a module changes.
Generating Decision Records Automatically
Using LLMs (OpenAI, Anthropic, or local Ollama), repowise can synthesize these findings into draft ADRs. It looks at the "before" and "after" of a major refactor, reads the associated PR descriptions and commit logs, and generates a structured record of the change. This provides a "cold start" for teams who want to document their architecture but don't know where to begin.
Using the get_why() MCP Tool
One of the most powerful features of repowise is its integration with the Model Context Protocol (MCP). This allows AI agents like Claude Code, Cursor, or Cline to access your codebase's "wisdom" directly.
The get_why() tool is specifically designed to answer architectural questions. It doesn't just grep for strings; it queries the synthesized wiki and decision records.
Natural Language Queries: "Why JWT over sessions?"
Instead of hunting through docs, you can ask your AI agent:
"Looking at the auth module, why did we decide to use JWTs instead of stateful sessions?"
The agent calls get_why(), which looks up the relevant ADRs, ownership maps, and historical context stored in repowise. It might respond: "We adopted JWTs in ADR-012 to support our migration to a multi-region deployment where a centralized session store would introduce unacceptable latency."
Path-Based Lookup
You can query specific paths to understand their history. Running get_why(path="src/lib/db") returns a dashboard of decisions affecting that directory, including its health score, recent hotspots, and the original rationale for its structure. This is particularly useful when exploring auto-generated docs for FastAPI or other complex frameworks.
Decision Health Dashboard
Repowise provides a "Freshness Score" for your documentation. If the code in a module has changed significantly but the associated ADRs haven't been updated, the health score drops. This alerts the team that their "source of truth" is drifting from reality.
{{IMAGE: mcp-get-why-output | MCP TOOL: GET_WHY | A terminal-style interface showing a JSON response from an MCP tool. Command: "get_why(topic='database_migration')". Output: { "decision": "Migrate to pgvector", "rationale": "Requirement for semantic search in v2.1", "alternatives": ["Pinecone", "Elasticsearch"], "consequences": ["Unified backup strategy", "Increased RAM usage"], "confidence": 0.92 }. Header: "REPOWISE MCP SERVER - TOOL: GET_WHY". All text in muted teal-gray on dark charcoal. Heavy grain texture.}}
Building an ADR Practice
Tools like repowise provide the foundation, but a successful ADR practice requires a cultural shift.
Start With What repowise Generates
Don't start from a blank page. Use the live examples generated by repowise to see how it documents existing repositories. Use the auto-generated summaries as a baseline, then refine them.
Add Manual ADRs for Business Decisions
While repowise is great at detecting technical shifts, it can't always know the business reason behind a choice. If you're choosing a vendor because of a specific compliance requirement (like HIPAA or GDPR), create a manual ADR to capture that context.
Review ADR Health Regularly
Treat ADRs like code. During sprint retrospectives or architecture reviews, check the "Decision Health Dashboard." If a decision is no longer valid, mark it as Superseded and link to the new record. This creates a clear lineage of how the system evolved.
ADR Templates and Best Practices
To make the process seamless, we recommend keeping your ADRs in a /docs/adr folder in your repository. Use a simple Markdown format:
# ADR 005: Use Vite for Frontend Tooling
## Status
Accepted
## Context
Our current Webpack build takes 45 seconds for HMR (Hot Module Replacement),
significantly slowing down developer velocity.
## Decision
We are migrating to Vite to leverage native ESM-based HMR.
## Consequences
- Faster dev start times (< 2 seconds).
- Requires updating some legacy CommonJS dependencies.
- Build process now uses Rollup under the hood.
Best Practices:
- Keep it brief: 1-2 pages maximum.
- Be honest about downsides: Every architectural choice is a trade-off. If there are no downsides, it’s not an architectural decision; it’s just a "best practice."
- Link to code: Use relative links to the files or modules most affected by the decision.
Key Takeaways
Architectural Decision Records are the "black box flight recorder" of your software project. They ensure that the wisdom gained during the design phase isn't lost to time. By combining a disciplined manual practice with the automated intelligence of an ADR tool like repowise, you can ensure your team spends less time asking "Why?" and more time building.
- Code is the what, ADRs are the why.
- Context is fragile: Document it where the code lives.
- Use Git Intelligence: Leverage tools like repowise to mine historical decisions and keep documentation fresh.
- AI-Ready: Use MCP tools like
get_why()to make your architecture searchable by AI agents.
Ready to see the "why" behind your code? Explore the hotspot analysis demo to see how repowise identifies the most critical parts of your architecture automatically.
FAQ
Q: How many ADRs should a project have? A: A typical mature project might have 20–50 ADRs. If you have hundreds, you’re likely documenting implementation details rather than architecture.
Q: Should I use a specialized ADR tool? A: You can start with a simple CLI tool or Markdown files. However, platforms like repowise add value by linking those records to git history, dependency graphs, and AI agents.
Q: How do I handle "shadow" decisions? A: Shadow decisions are choices made implicitly without discussion. Repowise helps catch these by flagging structural changes that lack corresponding documentation.


