System Design: Design Principles and Patterns
Master Single Responsibility at system scale, Loose Coupling vs High Cohesion, Domain-Driven Design (DDD), Bounded Contexts, Anti-Corruption Layers, Eventual Consistency & CRDTs, and Read-Heavy vs Write-Heavy system design.
1. Single Responsibility at System Level & Loose Coupling vs High Cohesion
At the architecture level, the Single Responsibility Principle (SRP) dictates that each microservice must encapsulate a single distinct business domain and maintain its own private datastore. High Cohesion ensures related logic lives together, while Loose Coupling ensures services communicate asynchronously via events without fragile dependencies.
System-Level Single Responsibility Principle (SRP) & Private Datastores
System DesignEncapsulating Auth, Orders, and Payments into independent microservice boundaries
Tight Coupling Cascading Failure Hazard vs Loose Coupling Event-Driven Mesh
System DesignReplacing synchronous HTTP chains with asynchronous Kafka/EventBridge event streams
Tight Coupling Hazards
Synchronous RPC chains multiply unreliability.
- Cascading Outages: If Service D has a 1% error rate, upstream services A, B, and C fail
- Deployment Gridlock: Services must be deployed simultaneously due to shared models
- Shared Database Anti-Pattern: Multiple services querying the same SQL database tables
Loose Coupling & High Cohesion
Building autonomous resilient microservices.
- High Cohesion: Order calculations, discounts, and line items live in Order Service
- Asynchronous Events: Order emits "OrderPlaced" event; downstream services react independently
- Database Per Service: Strict zero-sharing of persistence layers
2. Domain-Driven Design (DDD) Basics & Tactical Building Blocks
Domain-Driven Design (DDD) (Eric Evans) aligns software design with complex business domains through an agreed Ubiquitous Language and clear tactical building blocks.
DDD Tactical Building Blocks & Aggregate Consistency Boundary
System DesignAggregate Root, Entities, Value Objects, and Domain Event publishing
1. Entities vs Value Objects
Identity vs Immutable Attributes.
- Entity: Defined by unique identity (e.g. Order ID: "ord_123")
- Value Object: Defined by attributes with no identity (e.g. Money($50, USD)); immutable
2. Aggregate Root
Enforcing transactional consistency.
- Consistency Boundary: Encapsulates child entities and value objects
- All external mutations must pass through the Root methods to guarantee business rules
3. Domain Events
Capturing state changes as events.
- Immutable record of something that occurred (e.g. "PaymentReceivedEvent")
- Published asynchronously to message brokers
Domain-Driven Design (DDD) Order Aggregate Root & Domain Event Dispatcher in TypeScript
A TypeScript aggregate root that encapsulates Order invariants and dispatches domain events on state changes.
Press Run to execute the code and see output here.
3. Bounded Contexts & The Anti-Corruption Layer (ACL) Pattern
A Bounded Context defines the explicit boundary within which a domain model and its ubiquitous language apply. A "User" in the Auth context has a different data model than a "Customer" in the Billing context. When integrating with legacy systems, an Anti-Corruption Layer (ACL) translates foreign schemas to protect the clean domain model.
Bounded Contexts & Anti-Corruption Layer (ACL) Integration Map
System DesignPreventing legacy monolithic schema leaks into modern cloud microservices
Context Mapping Patterns in Microservices
Managing relationships across domain boundaries.
- Anti-Corruption Layer (ACL): Adapter layer translating legacy payloads into clean domain entities
- Shared Kernel: A small, mutually agreed-upon subset of the domain shared between two teams
- Customer-Supplier: Upstream team provides APIs tailored to the downstream team's requirements
4. Eventual Consistency Trade-offs & CRDT Convergence
Distributed systems operating across multiple datacenters sacrifice strict immediate consistency for high availability (CAP Theorem AP / BASE model). Replicas synchronize in the background, achieving Eventual Consistency. Conflict-Free Replicated Data Types (CRDTs) guarantee deterministic convergence without expensive distributed locks.
Eventual Consistency Conflict-Free Convergence with CRDT PN-Counters
System DesignMathematical merge functions resolving concurrent writes across multi-region replicas
BASE vs ACID in Distributed Systems
Trading immediate consistency for global availability.
- Basically Available: System remains operational despite node failures
- Soft State: System state may drift temporarily between replicas
- Eventual Consistency: Replicas converge once updates cease
Conflict-Free Replicated Data Types (CRDTs)
Lock-free mathematical consistency.
- Commutative & Associative: Update order does not affect the final result
- PN-Counter: Tracks positive increments and negative decrements separately
- Used in: Collaborative editors (Figma, Google Docs), Redis Enterprise, and chat apps
Conflict-Free Replicated Data Type (PN-Counter CRDT) in Node.js
A PN-Counter CRDT implementation that merges concurrent increments and decrements without conflicts.
Press Run to execute the code and see output here.
5. Read-Heavy vs Write-Heavy System Design
System design requires tailoring storage and compute engines to the expected Read-to-Write ratio of the application.
Read-Heavy vs Write-Heavy Architectural Paradigms Comparison
System DesignContrasting CDN edge caching and read replicas against LSM-Tree sequential logs and Kafka write buffering
Read-Heavy Optimizations (Twitter, Wikipedia)
Minimizing read latency across high query volumes.
- Multi-Tier Caching: In-memory Redis + CDN Edge caching (CloudFront)
- Read Replicas: Horizontally scaling read-only database replicas
- Denormalized CQRS: Precomputing views into search engines (Elasticsearch)
Write-Heavy Optimizations (IoT, Financial Ledgers)
Maximizing ingestion throughput without disk I/O bottlenecks.
- LSM-Trees (Cassandra/RocksDB): Appending writes sequentially to Memtable and WAL
- Write Buffering: Ingesting into Kafka message queues and flushing in bulk batches
- Sharding: Partitioning writes across nodes by Device ID or Hash
Knowledge Check
1. What is the definition of High Cohesion and Loose Coupling in system design?
2. What role does an Anti-Corruption Layer (ACL) play in Bounded Contexts?
3. What characterizes an Aggregate Root in Domain-Driven Design (DDD)?
4. How do Conflict-Free Replicated Data Types (CRDTs) achieve eventual consistency?
5. What architectural pattern is primary in Read-Heavy systems (e.g. Twitter Feed)?