System Design Principles
Priority: P0 (CRITICAL)
Workflow: Evaluate Architecture for New Feature
- Identify bounded contexts and module boundaries
- Name the data owner and define dependency direction (outer layers depend on inner)
- Select communication pattern (sync REST, async event, or hybrid) and failure behavior
- Validate CAP trade-offs only for distributed components
- Record boundary, trade-off, and rollback in an ADR
For a failing synchronous dependency, keep the critical path explicit: timeout and circuit-break the dependency, return a defined degraded/fallback result where safe, and move non-critical notifications to an asynchronous event.
Architectural Principles
- SoC: Divide into distinct sections per concern.
- SSOT: One source, reference elsewhere.
- Fail Fast: Fail visibly when errors occur.
- Graceful Degradation: Core functional even if secondary fails.
Modularity & Coupling
- High Cohesion: Related functionality in one module.
- Loose Coupling: Use interfaces for communication.
- DI: Inject dependencies, don't hardcode.
See implementation examples for dependency flow diagrams.
Common Patterns
- Layered: Presentation -> Logic -> Data.
- Event-Driven: Async communication between decoupled components.
- Clean/Hexagonal: Core logic independent of frameworks.
- Statelessness: Favor stateless for scaling/testing.
- Monolith first: Start modular-monolith; split a service out only when a module needs independent scaling, release cadence, or ownership.
Distributed Systems
- CAP: Apply only to behavior during a network partition in a distributed data system. See CAP & Consistency Patterns; consistency, availability, and partition tolerance are not product labels or uptime percentages.
- Idempotency: Preserve one intended effect for retries of the same business operation. Use the idempotency contract, not “without side effects” or a fresh key per transport attempt.
- Circuit Breaker: Fail fast on failing services. See Resilience Patterns.
- Eventual Consistency: State a freshness/convergence objective, how it is measured, and behavior when it is missed; do not promise a generic convergence time.
Documentation & Evolution
- Design Docs: Write specs before major implementations.
- Versioning: Version APIs/schemas for backward compatibility.
- Extensibility: Use Strategy/Factory for future changes.
References
Anti-Patterns
- No god classes: Single Responsibility — one reason to change per module.
- No blanket synchronous-coupling ban: choose synchronous, asynchronous, or hybrid communication from the boundary's consistency, latency, failure, and coupling requirements. A bounded synchronous transaction can protect an immediate invariant; independent notifications may remain asynchronous. State the trade-offs and failure behavior.
- No premature abstraction: Design for current load; scale when proven needed.