Architecture patterns¶
System Design Concepts¶
System design encompasses the fundamental concepts and patterns used to build scalable, reliable, and maintainable distributed systems. These concepts are essential for architects designing large-scale applications.

Core Concepts Explained¶
1. Scalability
The ability of a system to handle increased load by adding resources.
- Vertical Scaling (Scale Up): Adding more power (CPU, RAM) to existing machines
- Horizontal Scaling (Scale Out): Adding more machines to the pool
- Key Metrics: Requests per second, concurrent users, data volume
Vertical: [Small Server] → [Large Server]
Horizontal: [Server] → [Server] + [Server] + [Server]
2. Load Balancers
Distribute incoming traffic across multiple servers to ensure no single server is overwhelmed.
- Algorithms: Round Robin, Least Connections, IP Hash, Weighted
- Types: Layer 4 (Transport) vs Layer 7 (Application)
- Examples: NGINX, HAProxy, AWS ALB/NLB
3. Object Storage
Scalable storage for unstructured data like images, videos, and backups.
- Characteristics: Flat namespace, metadata-rich, highly durable
- Use Cases: Static assets, backups, data lakes
- Examples: AWS S3, Google Cloud Storage, Azure Blob
4. Message Queues
Asynchronous communication mechanism that decouples producers from consumers.
- Benefits: Decoupling, buffering, load leveling
- Patterns: Point-to-point, Publish-Subscribe
- Examples: RabbitMQ, Amazon SQS, Apache Kafka
5. Microservices
Architectural style where applications are composed of small, independent services.
- Principles: Single responsibility, loose coupling, independent deployment
- Communication: REST, gRPC, message queues
- Challenges: Distributed tracing, data consistency, service discovery
6. Caching
Storing frequently accessed data in fast storage to reduce latency and database load.
- Levels: Browser, CDN, Application, Database
- Strategies: Cache-aside, Write-through, Write-behind
- Invalidation: TTL, Event-based, Manual
- Examples: Redis, Memcached, Varnish
7. Database
Persistent storage systems optimized for different data models and access patterns.
| Type | Examples | Best For |
|---|---|---|
| Relational | PostgreSQL, MySQL | Structured data, ACID transactions |
| Document | MongoDB, CouchDB | Flexible schemas, JSON data |
| Key-Value | Redis, DynamoDB | Simple lookups, caching |
| Wide-Column | Cassandra, HBase | Time-series, write-heavy workloads |
| Graph | Neo4j, Neptune | Relationships, social networks |
8. CAP Theorem
States that a distributed system can only guarantee two of three properties simultaneously:
- Consistency (C): All nodes see the same data at the same time
- Availability (A): Every request receives a response
- Partition Tolerance (P): System continues despite network failures
| System Type | Guarantees | Examples |
|---|---|---|
| CP | Consistency + Partition Tolerance | MongoDB, HBase |
| AP | Availability + Partition Tolerance | Cassandra, DynamoDB |
| CA | Consistency + Availability | Traditional RDBMS (single node) |
9. Rate Limiting
Controls the number of requests a client can make in a given time period.
- Algorithms: Token Bucket, Leaky Bucket, Fixed Window, Sliding Window
- Purpose: Prevent abuse, ensure fair usage, protect resources
- Implementation: API Gateway, Application middleware
10. Partitioning (Sharding)
Dividing data across multiple databases to improve performance and scalability.
- Horizontal Partitioning: Rows distributed across shards
- Vertical Partitioning: Columns split into different tables
- Strategies: Range-based, Hash-based, Directory-based
11. CDN (Content Delivery Network)
Geographically distributed servers that cache content closer to users.
- Benefits: Reduced latency, decreased origin load, DDoS protection
- Content Types: Static assets, streaming media, API responses
- Examples: Cloudflare, Akamai, AWS CloudFront
12. Stream Processing
Real-time processing of continuous data streams.
- Use Cases: Real-time analytics, fraud detection, IoT data
- Patterns: Event sourcing, CQRS
- Examples: Apache Kafka Streams, Apache Flink, AWS Kinesis
Putting It All Together¶
When designing a system, these concepts work together:
flowchart TB
Users[Users] --> CDN[CDN]
CDN --> LB[Load Balancer]
LB --> API[API Gateway]
API --> RL[Rate Limiter]
RL --> MS1[Microservice 1]
RL --> MS2[Microservice 2]
MS1 --> Cache[Cache Layer]
MS2 --> Cache
Cache --> DB[(Database)]
MS1 --> MQ[Message Queue]
MQ --> MS2
DB --> Shard1[(Shard 1)]
DB --> Shard2[(Shard 2)]
style CDN fill:#90EE90
style LB fill:#FFD700
style Cache fill:#ADD8E6
style MQ fill:#FFB6C1
System-Level Architecture Patterns¶
System-level architecture patterns define how entire systems, services, and components are organized and communicate with each other. These patterns address concerns like scalability, reliability, maintainability, and distributed system challenges.
1. Event-Driven Architecture¶
Overview: Components communicate through events rather than direct calls. Events represent something that happened in the system.
flowchart LR
ServiceA[Service A] -->|publishes event| EventBus[Event Bus]
EventBus -->|delivers event| ServiceB[Service B]
EventBus -->|delivers event| ServiceC[Service C]
EventBus -->|delivers event| ServiceD[Service D]
style EventBus fill:#FFD700
style ServiceA fill:#90EE90
style ServiceB fill:#ADD8E6
style ServiceC fill:#ADD8E6
style ServiceD fill:#ADD8E6
Key Components: - Event Producers: Generate and publish events - Event Consumers: Subscribe to and process events - Event Bus/Broker: Routes events between producers and consumers - Event Store: Optionally persists events for replay
When to Use: - Real-time systems requiring immediate responses - Microservices that need loose coupling - Systems with complex workflows - Applications requiring audit trails
Pros: - Loose coupling between components - High scalability and responsiveness - Easy to add new consumers - Natural audit trail
Cons: - Complex debugging (async flow) - Event ordering challenges - Potential for event storms
2. Microservices Architecture¶
Overview: Application is decomposed into small, independent services that communicate over well-defined APIs.
flowchart TB
Client[Client Application] --> Gateway[API Gateway]
Gateway --> UserService[User Service]
Gateway --> OrderService[Order Service]
Gateway --> PaymentService[Payment Service]
Gateway --> NotificationService[Notification Service]
UserService --> UserDB[(User DB)]
OrderService --> OrderDB[(Order DB)]
PaymentService --> PaymentDB[(Payment DB)]
NotificationService --> MessageQueue[Message Queue]
style Gateway fill:#FFD700
style UserService fill:#90EE90
style OrderService fill:#ADD8E6
style PaymentService fill:#FFB6C1
style NotificationService fill:#DDA0DD
Key Characteristics: - Single Responsibility: Each service owns a specific business capability - Decentralized: Independent deployment and scaling - Technology Agnostic: Services can use different tech stacks - Fault Tolerant: Failure in one service doesn't crash the system
When to Use: - Large, complex applications - Multiple development teams - Different scaling requirements per feature - Need for rapid, independent deployments
Pros: - Independent scaling and deployment - Technology diversity - Team autonomy - Fault isolation
Cons: - Operational complexity - Network latency overhead - Data consistency challenges - Testing complexity
3. Monolithic Architecture¶
Overview: All components of an application are packaged and deployed as a single unit.
flowchart TB
Client[Client] --> LoadBalancer[Load Balancer]
LoadBalancer --> App1[Monolithic App Instance 1]
LoadBalancer --> App2[Monolithic App Instance 2]
LoadBalancer --> App3[Monolithic App Instance 3]
App1 --> Database[(Shared Database)]
App2 --> Database
App3 --> Database
subgraph "Monolithic Application"
UI[UI Layer]
Business[Business Layer]
Data[Data Layer]
end
style LoadBalancer fill:#FFD700
style Database fill:#ADD8E6
When to Use: - Small to medium applications - Simple business logic - Limited team size - Rapid prototyping
Pros: - Simple deployment and testing - Easy debugging - Better performance (no network calls) - Simpler development initially
Cons: - Difficult to scale specific components - Technology lock-in - Large codebase becomes unwieldy - Deployment of small changes affects entire system
4. Service-Oriented Architecture (SOA)¶
Overview: Services communicate through well-defined interfaces and protocols, typically with enterprise service bus.
flowchart TB
Client1[Web Client] --> ESB[Enterprise Service Bus]
Client2[Mobile Client] --> ESB
Client3[Partner API] --> ESB
ESB --> Service1[Customer Service]
ESB --> Service2[Inventory Service]
ESB --> Service3[Billing Service]
ESB --> Service4[Reporting Service]
Service1 --> DB1[(Customer DB)]
Service2 --> DB2[(Inventory DB)]
Service3 --> DB3[(Billing DB)]
Service4 --> DataWarehouse[(Data Warehouse)]
style ESB fill:#FFD700
style Service1 fill:#90EE90
style Service2 fill:#ADD8E6
style Service3 fill:#FFB6C1
style Service4 fill:#DDA0DD
Key Principles: - Service Contracts: Well-defined interfaces - Service Autonomy: Services control their own logic - Service Reusability: Services can be reused across applications - Service Composability: Services can be combined to create new functionality
When to Use: - Enterprise environments - Legacy system integration - Need for service reuse across multiple applications - Governance and compliance requirements
5. Client-Server Architecture¶
Overview: Clients request services from servers, which process requests and return responses.
flowchart LR
Client1[Web Browser] --> Server[Web Server]
Client2[Mobile App] --> Server
Client3[Desktop App] --> Server
Server --> AppServer[Application Server]
AppServer --> Database[(Database)]
AppServer --> FileSystem[File System]
style Server fill:#FFD700
style AppServer fill:#90EE90
style Database fill:#ADD8E6
Variants: - 2-Tier: Client directly communicates with database - 3-Tier: Client → Application Server → Database - N-Tier: Multiple intermediate layers
When to Use: - Traditional web applications - Database-driven applications - Need for centralized data management
6. Peer-to-Peer (P2P) Architecture¶
Overview: Nodes act as both clients and servers, sharing resources directly with each other.
flowchart LR
Peer1[Peer 1] <--> Peer2[Peer 2]
Peer2 <--> Peer3[Peer 3]
Peer3 <--> Peer4[Peer 4]
Peer4 <--> Peer1
Peer1 <--> Peer3
Peer2 <--> Peer4
style Peer1 fill:#90EE90
style Peer2 fill:#ADD8E6
style Peer3 fill:#FFB6C1
style Peer4 fill:#DDA0DD
When to Use: - File sharing systems - Blockchain networks - Distributed computing - Systems requiring high availability without central points of failure
Pros: - No single point of failure - Highly scalable - Cost-effective (no central infrastructure)
Cons: - Security challenges - Difficult to maintain consistency - Network complexity
7. Pipe and Filter Architecture¶
Overview: Data flows through a series of processing stages (filters) connected by pipes.
flowchart LR
Input[Raw Data] --> Filter1[Parse Data]
Filter1 --> Filter2[Validate Data]
Filter2 --> Filter3[Transform Data]
Filter3 --> Filter4[Enrich Data]
Filter4 --> Output[Processed Data]
style Input fill:#FFD700
style Filter1 fill:#90EE90
style Filter2 fill:#ADD8E6
style Filter3 fill:#FFB6C1
style Filter4 fill:#DDA0DD
style Output fill:#98FB98
When to Use: - Data processing pipelines - Stream processing - Batch processing systems - ETL (Extract, Transform, Load) operations
Pros: - Easy to understand and modify - Reusable filters - Parallel processing possible - Good for batch processing
Cons: - Not suitable for interactive systems - Overhead of data transformation between filters
8. Serverless Architecture¶
Overview: Application logic runs in stateless compute containers managed by cloud providers.
flowchart TB
Client[Client] --> Gateway[API Gateway]
Gateway --> Function1[Lambda Function 1]
Gateway --> Function2[Lambda Function 2]
Gateway --> Function3[Lambda Function 3]
Function1 --> Database[(Managed Database)]
Function2 --> Storage[Object Storage]
Function3 --> Queue[Message Queue]
Event[Event Source] --> Function1
Schedule[Scheduled Event] --> Function2
style Gateway fill:#FFD700
style Function1 fill:#90EE90
style Function2 fill:#ADD8E6
style Function3 fill:#FFB6C1
When to Use: - Event-driven applications - Unpredictable or sporadic traffic - Rapid prototyping - Cost optimization for low-traffic applications
Pros: - No server management - Automatic scaling - Pay-per-use pricing - Fast deployment
Cons: - Vendor lock-in - Cold start latency - Limited execution time - Debugging challenges
9. Architecture Pattern Comparison¶
| Pattern | Scalability | Complexity | Cost | Best For |
|---|---|---|---|---|
| Monolithic | Limited | Low | Low | Small apps, prototypes |
| Microservices | High | High | High | Large, complex systems |
| SOA | Medium | Medium | Medium | Enterprise integration |
| Event-Driven | High | Medium | Medium | Real-time systems |
| Client-Server | Medium | Low | Low | Traditional web apps |
| P2P | High | High | Low | Distributed systems |
| Serverless | Auto | Low | Variable | Event-driven, sporadic load |
Choosing the Right Pattern¶
Consider These Factors:
- Team Size & Expertise
- Small teams: Monolithic or Client-Server
-
Large teams: Microservices or SOA
-
System Complexity
- Simple: Monolithic
-
Complex: Microservices or Event-Driven
-
Scalability Requirements
- Low: Monolithic
-
High: Microservices, Event-Driven, or Serverless
-
Performance Requirements
- Low latency: Monolithic
-
High throughput: Event-Driven or Microservices
-
Budget Constraints
- Limited: Monolithic or Serverless
- High: Microservices or SOA
Application-level UI Patterns¶
What distinguishes MVC, MVP, MVVM, MVVM-C, and VIPER architecture patterns from each other?
These architecture patterns are among the most commonly used in app development, whether on iOS or Android platforms. Developers have introduced them to overcome the limitations of earlier patterns. So, how do they differ?
-
MVC, the oldest pattern, dates back almost 50 years
-
Every pattern has a "view" (V) responsible for displaying content and receiving user input
-
Most patterns include a "model" (M) to manage business data
-
"Controller," "presenter," and "view-model" are translators that mediate between the view and the model ("entity" in the VIPER pattern)
-
These translators can be quite complex to write, so various patterns have been proposed to make them more maintainable
1. MVC (Model View Controller)¶
The Model-View-Controller pattern separates an application into three interconnected components.
flowchart LR
User([User]) --> View[View]
View -->|notify| Controller[Controller]
Controller -->|update| Model[Model]
Model -->|get data| View
style View fill:#90EE90
style Controller fill:#FFB6C1
style Model fill:#ADD8E6
Components: - Model: Manages data and business logic - View: Handles the user interface and presentation - Controller: Mediates between Model and View, handles user input
2. MVP (Model View Presenter)¶
The Model-View-Presenter pattern is similar to MVC but with a different flow of communication.
flowchart LR
User([User]) --> View[View]
View -->|notify| Presenter[Presenter]
Presenter -->|update| View
Presenter -->|update| Model[Model]
Model -->|get data| Presenter
style View fill:#90EE90
style Presenter fill:#FFFF99
style Model fill:#ADD8E6
Components: - Model: Manages data and business logic - View: Handles the user interface (passive) - Presenter: Contains presentation logic, mediates between View and Model
3. MVVM (Model View View-Model)¶
The Model-View-ViewModel pattern uses data binding to connect the View and ViewModel.
flowchart LR
User([User]) --> View[View]
View -->|Data binding| ViewModel[View Model]
ViewModel -.->|Notify| View
ViewModel -->|update| Model[Model]
Model -.->|Notify| ViewModel
style View fill:#90EE90
style ViewModel fill:#FFFF99
style Model fill:#ADD8E6
Components: - Model: Manages data and business logic - View: Handles the user interface with data binding - ViewModel: Exposes data and commands for the View, handles presentation logic
4. MVVM-C (Model View View-Model Coordinator)¶
MVVM-C extends MVVM by adding a Coordinator to handle navigation and flow control.
flowchart TB
Coordinator[Coordinator] -->|control| MVVM
subgraph MVVM ["MVVM Flow"]
User([User]) --> View[View]
View -->|Data binding| ViewModel[View Model]
ViewModel -.->|Notify| View
ViewModel -->|update| Model[Model]
Model -.->|Notify| ViewModel
end
style View fill:#90EE90
style ViewModel fill:#FFFF99
style Model fill:#ADD8E6
style Coordinator fill:#FFB6C1
Components: - Model: Manages data and business logic - View: Handles the user interface with data binding - ViewModel: Exposes data and commands for the View - Coordinator: Manages navigation and application flow
5. VIPER (View Interactor Presenter Entity Router)¶
VIPER is a more complex pattern that separates concerns into five distinct components.
flowchart LR
User([User]) --> View[View]
View -->|Data binding| Presenter[Presenter]
Presenter -.->|Notify| View
Presenter -->|update| Interactor[Interactor]
Interactor -.->|Notify| Presenter
Interactor -->|manage| Entity[Entity]
Entity -.->|notify| Interactor
Router[Router] -->|manage| Presenter
style View fill:#90EE90
style Presenter fill:#FFFF99
style Entity fill:#ADD8E6
style Router fill:#FFB6C1
style Interactor fill:#DDA0DD
Components: - View: Handles the user interface - Interactor: Contains business logic - Presenter: Handles presentation logic and formatting - Entity: Basic data models - Router: Handles navigation and module assembly
Pattern Comparison¶
| Pattern | Complexity | Testability | Separation of Concerns | Best Use Case |
|---|---|---|---|---|
| MVC | Low | Medium | Good | Simple applications |
| MVP | Medium | High | Very Good | Applications requiring high testability |
| MVVM | Medium | High | Very Good | Applications with complex UI binding |
| MVVM-C | High | High | Excellent | Large applications with complex navigation |
| VIPER | Very High | Excellent | Excellent | Enterprise applications with complex business logic |
Coding Project Architecture Patterns¶
Structure¶
Monorepo Structure¶
A monorepo (monolithic repository) contains multiple projects in a single repository. Benefits include:
-
Shared Dependencies: Easier to manage common libraries and dependencies
-
Atomic Changes: Changes across multiple projects can be made in a single commit
-
Unified Tooling: Consistent build tools, linting, and testing across all projects
-
Simplified Dependency Management: No version conflicts between projects
Best Practices:
-
Use workspace tools (Lerna, Nx, Rush, or built-in workspace support)
-
Establish clear project boundaries and ownership
-
Implement consistent coding standards and tooling
-
Use automated dependency graph analysis
Polyrepo Structure¶
Multiple repositories, each containing a single project or small set of related projects.
Benefits:
-
Independent Releases: Each project can be versioned and released separately
-
Clear Ownership: Specific teams own specific repositories
-
Reduced Repository Size: Smaller, more focused repositories
-
Access Control: Granular permissions per repository
Layers¶
Core Layer¶
Base abstractions, interfaces, and protocols.
Contents:
-
Domain models and entities
-
Business logic interfaces
-
Data access abstractions
-
Common utilities and helpers
-
Configuration interfaces
-
Event definitions and contracts
Characteristics:
-
No external dependencies
-
Framework-agnostic
-
Highly testable
-
Contains business rules and domain logic
Implementation Layer¶
Concrete implementations and high-level public utilities.
Contents:
-
Service implementations
-
Repository implementations
-
Data transfer objects (DTOs)
-
Utility classes and functions
-
Business logic implementations
-
Event handlers and processors
Characteristics:
-
Depends on core layer only
-
Contains framework-specific code
-
Implements interfaces defined in core
-
Orchestrates business workflows
Integration Layer¶
Third-party service integrations.
Contents:
-
External API clients
-
Database implementations
-
Message queue integrations
-
Cloud service connectors
-
Third-party library wrappers
-
Infrastructure adapters
Characteristics:
-
Isolates external dependencies
-
Provides consistent interfaces to external services
-
Handles authentication and authorization
-
Manages connection pooling and retries
Testing Layer¶
Test implementations and testing utilities.
Contents:
-
Unit tests for all layers
-
Integration tests
-
End-to-end tests
-
Test doubles and mocks
-
Test utilities and fixtures
-
Performance and load tests
Testing Pyramid:
-
Unit Tests: Fast, isolated, test single components
-
Integration Tests: Test interactions between components
-
End-to-End Tests: Test complete user workflows
-
Contract Tests: Verify API compatibility between services
Best Practices: - Maintain high test coverage for core business logic - Use test doubles for external dependencies - Implement test automation and CI/CD integration - Separate test data from test logic