An architecture pattern is a proven, reusable solution schema for a recurring structural problem. Patterns are not recipes β they're templates that must be adapted to your specific context. Each pattern has trade-offs; no pattern is universally "best."
3.1 Layered Architecture
The most widely known architecture pattern. The system is organized into horizontal layers, each providing services to the layer above it and consuming services from the layer below.
Strict vs. Relaxed layering: In strict layering, each layer can only call the layer immediately below it. In relaxed layering, a layer can call any lower layer. Strict layering provides better encapsulation but can lead to "pass-through" methods that add nothing. Most real systems use a mix.
| β Pros | β Cons | Best For |
|---|---|---|
| Simple, well-understood | Change ripple across layers | Simple CRUD applications |
| Good separation of concerns | Performance overhead (pass-through) | Enterprise apps with clear layers |
| Layers replaceable independently | Monolithic tendencies | Teams organized by technical skill |
3.2 Pipes and Filters
Data flows through a pipeline of processing steps (filters), connected by pipes. Each filter performs a single transformation and is independent of the others.
Real-world examples: Unix command-line pipelines (cat file | grep pattern | sort | uniq), ETL data pipelines, image processing pipelines, CI/CD build pipelines.
| β Pros | β Cons | Best For |
|---|---|---|
| Filters are reusable and composable | Not suited for interactive applications | Data transformation pipelines |
| Easy to add/remove/reorder steps | Error handling across pipeline is complex | ETL, stream processing |
| Filters can run in parallel | Data format conversion overhead | CI/CD, media processing |
3.3 Microservices
An architectural style where the system is composed of small, independently deployable services, each owning its own data and communicating via lightweight mechanisms (typically HTTP/REST or messaging).
The key principle is each service owns its own data. Services do not share databases. This enables independent deployment but introduces the challenge of data consistency across services.
| β Pros | β Cons | Best For |
|---|---|---|
| Independent deployment & scaling | Distributed system complexity | Large teams (>50 devs) |
| Technology heterogeneity per service | Network latency and partial failures | Frequent independent deployments |
| Fault isolation (one service fails, others continue) | Data consistency is hard | Different scaling needs per component |
| Team autonomy (Conway's Law aligned) | Operational overhead (monitoring, tracing) | Business domains with clear boundaries |
3.4 Model-View-Controller (MVC)
Separates an application into three interconnected responsibilities: the Model (data and business logic), the View (presentation), and the Controller (input handling). This separation allows the UI to change without affecting the business logic, and vice versa.
MVC originated in Smalltalk in the late 1970s and has evolved into many variants (MVP, MVVM, MVI). The core idea remains: separate what you show from what you compute from how you control the flow.
| Component | Responsibility | Examples |
|---|---|---|
| Model | Business data and rules, state management | Domain objects, services, repositories |
| View | Renders the model to the user, handles display | HTML templates, UI components, JSON serializers |
| Controller | Receives input, invokes model, selects view | REST controllers, event handlers, routes |
3.5 Other Important Patterns
| Pattern | Core Idea | When to Use |
|---|---|---|
| Client-Server | Separate requestor (client) from provider (server) | Any networked application (web, mobile, APIs) |
| Broker | Intermediary decouples clients from servers | Message-oriented systems, event-driven architectures |
| Blackboard | Shared knowledge base with independent knowledge sources | AI/ML pipelines, complex problem-solving systems |
| Plugin / Microkernel | Minimal core + pluggable extensions | IDEs, browsers, extensible platforms |
| SOA | Coarse-grained services with standardized interfaces (ESB) | Enterprise integration across legacy systems |
Hexagonal Architecture (Ports & Adapters)
The domain/business logic sits at the center, completely isolated from external concerns. It communicates with the outside world through ports (interfaces defined by the domain) and adapters (implementations that connect to specific technologies).
For example, a OrderRepository port is defined in the domain. A PostgresOrderRepository adapter implements it for PostgreSQL. Switching to MongoDB means writing a new adapter β the domain doesn't change.
CQRS (Command Query Responsibility Segregation)
Separate the read model (queries) from the write model (commands). Instead of using the same data model and database for both reads and writes, you optimize each independently. Often paired with Event Sourcing.
- Command side: Validates and processes state changes. Optimized for consistency.
- Query side: Serves read requests from denormalized views. Optimized for performance.
- Sync: Events propagate from command side to query side (eventual consistency).
Event-Driven Architecture
Components communicate by producing and consuming events β notifications that something happened. This decouples producers from consumers (producers don't know or care who consumes the events).
- Event Notification: A lightweight signal that something occurred (e.g., "OrderPlaced"). Consumers react to it.
- Event-Carried State Transfer: Events carry the data needed so consumers don't need to call back to the source.
- Event Sourcing: Store the full history of events as the source of truth, not the current state.
Resilience Patterns (for Distributed Systems)
| Pattern | Problem | Solution |
|---|---|---|
| Circuit Breaker | Cascading failures when a service is down | Stop calling failing services after threshold; fail fast instead |
| Retry with Backoff | Transient failures | Retry with exponential delay + jitter |
| Bulkhead | One failure consuming all resources | Isolate resources per consumer/service |
| Saga | Distributed transactions across services | Sequence of local transactions with compensating actions on failure |
| Sidecar | Cross-cutting concerns (logging, auth) in every service | Attach a helper container alongside each service |
Pattern Selection Guide
| If you need⦠| Consider⦠|
|---|---|
| Simple separation of concerns | Layered |
| Data transformation pipeline | Pipes & Filters |
| Independent deployment per team | Microservices |
| UI separation from logic | MVC / MVVM |
| Technology-agnostic domain | Hexagonal / Clean Architecture |
| Different read/write optimization | CQRS |
| Loose coupling via events | Event-Driven |
| Extensibility via plugins | Microkernel |