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.

Presentation Layer UI Β· Controllers Β· REST endpoints Business Logic Layer Domain services Β· Rules Β· Workflows Persistence / Data Access Layer Repositories Β· DAOs Β· ORM Database / Storage RDBMS Β· NoSQL Β· File systems Strict layering: each layer uses only the one directly 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❌ ConsBest For
Simple, well-understoodChange ripple across layersSimple CRUD applications
Good separation of concernsPerformance overhead (pass-through)Enterprise apps with clear layers
Layers replaceable independentlyMonolithic tendenciesTeams organized by technical skill
When NOT to use: When your domain is complex and changes cut across all layers (every business feature requires UI + logic + data changes). In that case, consider vertical slices or domain-based decomposition.

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.

Input Filter A Parse Filter B Transform Filter C Validate Output Each filter: stateless, single-purpose, independently replaceable

Real-world examples: Unix command-line pipelines (cat file | grep pattern | sort | uniq), ETL data pipelines, image processing pipelines, CI/CD build pipelines.

βœ… Pros❌ ConsBest For
Filters are reusable and composableNot suited for interactive applicationsData transformation pipelines
Easy to add/remove/reorder stepsError handling across pipeline is complexETL, stream processing
Filters can run in parallelData format conversion overheadCI/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).

Service A πŸ—„ Own DB Service B πŸ—„ Own DB Service C πŸ—„ Own DB API Gateway / Message Bus

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❌ ConsBest For
Independent deployment & scalingDistributed system complexityLarge teams (>50 devs)
Technology heterogeneity per serviceNetwork latency and partial failuresFrequent independent deployments
Fault isolation (one service fails, others continue)Data consistency is hardDifferent scaling needs per component
Team autonomy (Conway's Law aligned)Operational overhead (monitoring, tracing)Business domains with clear boundaries
When NOT to use: Small teams (<10 devs), simple domains, or when you can't afford the operational complexity. A well-structured monolith is often the right starting point β€” you can extract microservices later when needed.

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.

ComponentResponsibilityExamples
ModelBusiness data and rules, state managementDomain objects, services, repositories
ViewRenders the model to the user, handles displayHTML templates, UI components, JSON serializers
ControllerReceives input, invokes model, selects viewREST controllers, event handlers, routes

3.5 Other Important Patterns

PatternCore IdeaWhen to Use
Client-ServerSeparate requestor (client) from provider (server)Any networked application (web, mobile, APIs)
BrokerIntermediary decouples clients from serversMessage-oriented systems, event-driven architectures
BlackboardShared knowledge base with independent knowledge sourcesAI/ML pipelines, complex problem-solving systems
Plugin / MicrokernelMinimal core + pluggable extensionsIDEs, browsers, extensible platforms
SOACoarse-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.

ADAPTERS (External) Domain Business Logic (Pure, no dependencies) REST API Database Message Q 3rd Party

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)

PatternProblemSolution
Circuit BreakerCascading failures when a service is downStop calling failing services after threshold; fail fast instead
Retry with BackoffTransient failuresRetry with exponential delay + jitter
BulkheadOne failure consuming all resourcesIsolate resources per consumer/service
SagaDistributed transactions across servicesSequence of local transactions with compensating actions on failure
SidecarCross-cutting concerns (logging, auth) in every serviceAttach a helper container alongside each service

Pattern Selection Guide

If you need…Consider…
Simple separation of concernsLayered
Data transformation pipelinePipes & Filters
Independent deployment per teamMicroservices
UI separation from logicMVC / MVVM
Technology-agnostic domainHexagonal / Clean Architecture
Different read/write optimizationCQRS
Loose coupling via eventsEvent-Driven
Extensibility via pluginsMicrokernel