Context drives decisions. No pattern is universally good or bad. The best architecture is not the most elegant — it's the one that best serves its purpose while remaining maintainable and evolvable.
Every architectural decision trades off:
| Vertex | Maximized By | Cost |
|---|
| Simplicity | Monolith, sync communication, single DB | Scalability limits |
| Flexibility | Microservices, event-driven, plugins | Complexity overhead |
| Performance | Caching, denormalization, optimized code | Maintainability |
Balance strategies: start simple; add complexity as needed; measure before optimizing; use abstractions to defer decisions; evolve incrementally.
SHOULD read CONTEXT.md at repo root before proceeding — use its vocabulary verbatim; never substitute synonyms.
SHOULD scan docs/adr/ for decisions in the area under analysis — respect accepted ADRs; do not re-litigate closed decisions.
If neither exists, proceed without them. Do not create these files unprompted.
MUST consider team and scale context before recommending patterns.
Team context:
| Context | Prefer | Avoid |
|---|
| Small team | Monolith, vertical slices, shared DB | Microservices, complex abstractions |
| Multiple teams | Service boundaries, API contracts | Shared state, tight coupling |
Scale context:
| Context | Prefer | Reasoning |
|---|
| Startup / early | Monolith first, vertical scaling | Optimize for development speed |
| Enterprise | Service mesh, horizontal scaling | Optimize for operational scale |
Quality attributes to surface:
- Performance: response time (p50/p95/p99), throughput, resource utilization
- Scalability: horizontal, vertical, elastic
- Reliability: uptime, MTBF, MTTR; patterns = circuit breakers, retries, redundancy
- Maintainability: readability, modularity, testability; patterns = Clean Architecture, DDD, SOLID
Use weighted matrix for comparing alternatives. Weight factors based on context priorities.
| Option | Consistency | Flexibility | Scalability | Complexity | Cost | Total |
|---|
| Option A | 5 | 2 | 3 | 2 | 3 | 15 |
| Option B | 3 | 5 | 4 | 3 | 3 | 18 |
| Option C | 2 | 3 | 5 | 1 | 2 | 13 |
MUST list criteria and weights before scoring. MUST justify weights against stated context.
Use ADR for any decision that would be expensive to reverse.
Write to docs/adr/NNNN-<slug>.md — NNNN = next available number zero-padded to 4 digits; slug = lowercase-hyphenated title. Create docs/adr/ if absent.
For the full ADR template (frontmatter + sections) and supersede mechanics, read references/adr-template.md.
Branch by Abstraction — create abstraction over current implementation → implement new solution behind abstraction → switch → remove old.
Strangler Fig — identify boundary → implement new solution for new features → gradually migrate old features → retire old system.
Parallel Run — implement new solution → run both old and new → compare results → switch when confident.
| Type | Examples | Payment Strategy |
|---|
| Design | Missing abstractions, tight coupling | Refactoring sprints |
| Code | Duplication, complexity, poor naming | Continuous cleanup |
| Test | Missing tests, flaky tests | Test improvement |
| Documentation | Missing docs, outdated diagrams | Documentation sprints |
Metrics: debt ratio = debt work / total work (target < 20%); interest rate = extra effort caused by debt; debt ceiling = maximum acceptable debt.
Big Ball of Mud — no clear structure, everything depends on everything. Remedy: identify boundaries, extract modules, establish interfaces.
Distributed Monolith — services must deploy together, sync chains, shared DBs. Remedy: merge related services, async communication, separate DBs.
Golden Hammer — one solution for all problems, force-fitting patterns. Remedy: learn alternatives, evaluate objectively, prototype options.