Layered Architecture
Layered (N-tier) architecture organizes code into horizontal layers — Presentation, Application, Domain, Infrastructure — with dependencies flowing in one direction.Architecture Layers
Key Characteristics
- Separation of concerns is the primary benefit
- Presentation → Application → Domain → Infrastructure: the standard clean architecture
- Strict layering prevents spaghetti dependencies at the cost of some verbosity
- Domain layer is the core: no framework, no database, just business logic
- Repository pattern abstracts persistence from the domain layer
- Transaction scripts (CRUD) can use a simple 3-tier without a rich domain layer
Best Practices
Do
- Enforce layer boundaries via automated architecture tests
- Keep the domain layer free of framework imports
- Use the Application layer for transaction management
Don't
- Allow the presentation layer to call the infrastructure layer directly
- Put domain logic in controllers or repository implementations
- Use strict layering when a CRUD service has no meaningful domain
Microservices Architecture
Microservices decompose applications into small, independently deployable services aligned to business capabilities, communicating over APIs or events.Core Principles
- Single responsibility: One bounded context per service
- Independent deployability: Services can be deployed without affecting others
- Decoupled data stores: Each service owns its data
- Conway’s Law: Services map to team boundaries
Key Components
API Gateway
Unified entry point with auth, rate limiting, routing
Service Mesh
Handles cross-cutting: mTLS, circuit breaking, observability (Istio, Linkerd)
Event Bus
Async communication between services (Kafka, RabbitMQ)
Service Registry
Dynamic service discovery (Consul, Eureka)
Microservices Best Practices
Do:- Own one database per service — never share schemas
- Implement circuit breakers for all inter-service calls
- Use correlation IDs for distributed tracing across services
- Apply the Saga pattern for distributed transactions
- Create a distributed monolith by sharing databases
- Call services synchronously in a long chain (cascading failures)
- Adopt microservices without container orchestration capability
Serverless Architecture
Serverless (FaaS) runs code in response to events without managing servers. Cloud providers handle scaling, patching, and availability automatically.Key Characteristics
- Functions are stateless: No shared memory between invocations
- Cold start: First invocation after idle period incurs startup latency (~100ms-2s)
- Event-driven: Functions respond to HTTP, queues, storage events
- Pay per invocation: Economic for sporadic workloads
- Auto-scaling: From zero to thousands of concurrent executions
Serverless Patterns
- API Gateway + Lambda
- Event Processing
- Step Functions
- Edge Functions
REST API backed by Lambda functions for stateless request handling.
Best Practices
Do
- Keep function handlers thin — business logic in a separate module
- Use Step Functions for multi-step orchestration
- Monitor cold starts and set concurrency limits
Don't
- Put long-running processes (>15 min) in Lambda functions
- Share state between Lambda invocations via in-memory variables
- Ignore timeout limits for database-heavy operations
Service-Oriented Architecture (SOA)
SOA structures enterprise systems as interoperable services communicating over a shared bus (ESB). It is the predecessor to microservices, emphasizing reuse and governance.ESB (Enterprise Service Bus)
Central integration backbone providing:- Routing: Message routing based on content or rules
- Transformation: Schema and protocol conversion
- Orchestration: Multi-service workflow coordination
- Protocol Mediation: SOAP, REST, MQ, FTP interoperability
SOA vs Microservices
| Aspect | SOA | Microservices |
|---|---|---|
| Communication | ESB (smart pipe) | API Gateway (dumb pipe) |
| Services | Coarse-grained | Fine-grained |
| Data | Shared databases | Database per service |
| Governance | Centralized | Decentralized |
| Standards | SOAP/WSDL/WS-* | REST/gRPC/Events |
Distributed Systems Patterns
Building distributed systems means accepting the Eight Fallacies of Distributed Computing (network is reliable, latency is zero, etc.).Core Patterns
Leader Election
Raft consensus powers etcd (Kubernetes), CockroachDB, TiKV
Consistent Hashing
Minimizes resharding in distributed caches (Redis Cluster)
Gossip Protocol
Membership and failure detection in clusters (Cassandra)
Saga Pattern
Coordinates distributed transactions across services
Idempotency Pattern
Idempotency is mandatory for any retried distributed operation.Distributed Systems Best Practices
Do:- Add correlation IDs to every distributed call
- Implement idempotency keys for all mutation operations
- Use exponential backoff with jitter for retry logic
- Implement distributed tracing (OpenTelemetry)
- Assume the network is reliable or latency is consistent
- Design synchronous long chains across services
- Use distributed transactions (2PC) — use sagas instead
Client-Server Architecture
Client-Server separates consumers (clients) from resource providers (servers). The fundamental model underlying HTTP, REST, databases, and most networked software.Architecture Patterns
Key Characteristics
- Stateless servers (HTTP) scale horizontally; sticky sessions break horizontal scaling
- Load balancers distribute requests; session affinity can be required by stateful servers
- Three-tier: presentation (browser), logic (API server), data (database)
- WebSockets upgrade HTTP to bidirectional persistent connection
- gRPC uses HTTP/2 multiplexing for low-latency RPC
- Connection pooling at the database tier is critical for performance at scale
Best Practices
Do
- Design servers to be stateless for horizontal scalability
- Use connection pooling at the database layer
- Implement health checks for load balancer integration
Don't
- Store session state in server memory in multi-instance deployments
- Ignore connection pool exhaustion under load (causes cascading failures)
- Mix client and server concerns in a single deployable
Cloud Design Patterns
Cloud design patterns address reliability, scalability, and cost challenges in cloud-native systems.Resilience Patterns
Circuit Breaker
Circuit Breaker
Prevents cascade failures
Bulkhead
Bulkhead
Isolates failuresIsolate resource pools (thread pools, connection pools) per consumer to prevent cascading failures.
Retry with Jitter
Retry with Jitter
Handles transient faultsExponential backoff with jitter prevents thundering herd when services recover.
Sidecar
Sidecar
Externalizes cross-cutting concernsDeploy logging, proxy, config as companion containers alongside application containers.
Strangler Fig
Strangler Fig
Incremental legacy modernizationIncrementally replace legacy system by routing new traffic to new services while old system continues to run.
Best Practices
Do
- Implement circuit breakers for all external service calls
- Use Bulkhead to isolate critical from non-critical resource pools
- Apply Strangler Fig for safe legacy system modernization
- Implement health endpoint monitoring (/health and /ready)
Don't
- Retry without exponential backoff and jitter (thundering herd)
- Share thread pools between slow third-party calls and critical user-facing paths
- Skip health endpoint implementation — orchestrators need it to route traffic correctly