Software Design and Architecture Patterns
Table of Contents
Overview
This document explores the key software design and architecture patterns that defined enterprise software development in 2021. The year marked a significant acceleration in cloud-native adoption, microservices maturity, and the formalization of architecture decision-making processes. Organizations increasingly moved beyond simple containerization toward sophisticated distributed systems patterns that emphasized resilience, observability, and developer experience.
Background
The software architecture landscape in 2021 was shaped by several converging forces:
- The pandemic-driven acceleration of digital transformation
- Kubernetes reaching mainstream production adoption
- Growing complexity of distributed systems requiring better tooling
- Increased focus on developer productivity and platform engineering
- Service mesh technologies maturing for production use
- The rise of GitOps and infrastructure as code as standard practice
Key Concepts
Microservices Patterns
Domain-Driven Design (DDD) Alignment
2021 saw stronger integration between DDD concepts and microservices boundaries:
- Bounded Contexts as service boundaries became the standard approach
- Context Mapping patterns (Anti-Corruption Layer, Open Host Service) guided integration
- Aggregates defined transaction boundaries within services
- Domain Events enabled loose coupling between contexts
Service Decomposition Strategies
| Strategy | Description | When to Use |
|---|---|---|
| Strangler Fig | Gradually replace monolith components | Legacy modernization |
| Business Capability | Align services to business functions | Greenfield projects |
| Subdomain-based | Follow DDD subdomains | Complex domains |
| Team-oriented | Conway's Law alignment | Large organizations |
Data Management Patterns
- Database per Service: Each microservice owns its data store
- Saga Pattern: Distributed transactions across services using choreography or orchestration
- CQRS: Command Query Responsibility Segregation for read/write optimization
- Event Sourcing: Storing state changes as immutable event sequences
Event-Driven Architecture
Core Patterns
Event Notification
Simple events signaling that something occurred, allowing subscribers to query for details:
OrderPlaced { orderId: "12345", timestamp: "2021-12-01T10:00:00Z" }
Event-Carried State Transfer
Events containing all necessary data, reducing service coupling:
OrderPlaced {
orderId: "12345",
customer: { id: "c789", name: "..." },
items: [...],
total: 150.00
}
Event Sourcing
Persisting domain events as the source of truth:
AccountCreated -> FundsDeposited -> FundsWithdrawn -> FundsDeposited
Message Broker Technologies (2021 Landscape)
| Technology | Strengths | Use Cases |
|---|---|---|
| Apache Kafka | High throughput, durability, replay | Event streaming, log aggregation |
| RabbitMQ | Flexible routing, mature ecosystem | Task queues, RPC |
| AWS SNS/SQS | Managed, scalable | Cloud-native applications |
| NATS | Lightweight, fast | Edge computing, IoT |
| Pulsar | Multi-tenancy, tiered storage | Large-scale streaming |
Eventual Consistency Handling
- Idempotency Keys: Ensuring operations can be safely retried
- Outbox Pattern: Reliable event publishing with transactional guarantees
- Inbox Pattern: Deduplication of incoming messages
- Compensation Events: Undoing operations in saga failure scenarios
Cloud-Native Design
The Twelve-Factor App (Extended)
The original twelve factors remained foundational, with additional emphasis on:
- Codebase: One codebase tracked in revision control, many deploys
- Dependencies: Explicitly declare and isolate dependencies
- Config: Store config in the environment
- Backing Services: Treat backing services as attached resources
- Build, Release, Run: Strictly separate build and run stages
- Processes: Execute the app as stateless processes
- Port Binding: Export services via port binding
- Concurrency: Scale out via the process model
- Disposability: Maximize robustness with fast startup and graceful shutdown
- Dev/Prod Parity: Keep development, staging, and production similar
- Logs: Treat logs as event streams
- Admin Processes: Run admin/management tasks as one-off processes
Beyond Twelve-Factor (2021 Additions)
- API First: Design APIs before implementation
- Telemetry: Built-in observability (metrics, traces, logs)
- Security: Zero-trust, secrets management, mTLS
- Authentication: Externalized identity management
Service Mesh Architecture
Service meshes (Istio, Linkerd, Consul Connect) provided:
- Traffic Management: Load balancing, circuit breaking, retries
- Security: mTLS, authorization policies
- Observability: Distributed tracing, metrics collection
- Traffic Splitting: Canary deployments, A/B testing
Observability Pillars
Observability
|
+----------------+----------------+
| | |
Metrics Traces Logs
(Prometheus) (Jaeger) (ELK/Loki)
| | |
+----------------+----------------+
|
Dashboards
(Grafana)
Architecture Decision Records (ADRs)
Purpose and Benefits
ADRs document significant architectural decisions in a lightweight, version-controlled format:
- Context Preservation: Why decisions were made
- Onboarding: New team members understand history
- Governance: Track decision approval and review
- Evolution: Decisions can be superseded with references
ADR Template (Michael Nygard Format)
# ADR-001: Use Event Sourcing for Order Management ## Status Accepted ## Context We need to maintain a complete audit trail of all order state changes and support temporal queries for compliance reporting. ## Decision We will implement event sourcing for the Order aggregate, storing all domain events in an append-only event store. ## Consequences - Complete audit trail of all changes (positive) - Ability to rebuild state at any point in time (positive) - Increased complexity in read model management (negative) - Need for event versioning strategy (negative) - Team requires training on event sourcing patterns (negative)
ADR Lifecycle States
| State | Description |
|---|---|
| Proposed | Under discussion |
| Accepted | Approved for implementation |
| Deprecated | No longer recommended |
| Superseded | Replaced by another ADR |
ADR Tooling
adr-tools: CLI for managing ADR filesLog4brains: Architecture knowledge base from ADRsStructurizr: C4 model integration with decisions
Implementation
Recommended Project Structure
project/
├── docs/
│ └── adr/
│ ├── 0001-record-architecture-decisions.md
│ ├── 0002-use-postgresql-for-persistence.md
│ └── 0003-adopt-event-driven-messaging.md
├── services/
│ ├── order-service/
│ ├── inventory-service/
│ └── notification-service/
├── infrastructure/
│ ├── kubernetes/
│ └── terraform/
└── shared/
├── events/
└── contracts/
Technology Stack Recommendations (2021)
| Layer | Technology Options |
|---|---|
| Container Orchestration | Kubernetes, ECS, Nomad |
| Service Mesh | Istio, Linkerd, Consul Connect |
| Message Broker | Kafka, RabbitMQ, Pulsar |
| API Gateway | Kong, Ambassador, Traefik |
| Observability | Prometheus + Grafana, Datadog, New Relic |
| Secrets Management | HashiCorp Vault, AWS Secrets Manager |
| CI/CD | GitHub Actions, GitLab CI, ArgoCD |
| Infrastructure | Terraform, Pulumi, CDK |
Anti-Patterns to Avoid
- Distributed Monolith: Microservices with tight coupling and synchronous dependencies
- Nano-services: Over-decomposition leading to excessive network overhead
- Shared Database: Multiple services accessing the same database schema
- Big Ball of Mud: Lack of clear boundaries and responsibilities
- Golden Hammer: Using one pattern for all problems
- Resume-Driven Development: Choosing technologies for career advancement over project needs
References
- Newman, Sam. "Building Microservices" 2nd Edition (2021)
- Richardson, Chris. "Microservices Patterns" (2018)
- Kleppmann, Martin. "Designing Data-Intensive Applications" (2017)
- Nygard, Michael. "Documenting Architecture Decisions" (2011)
- Vernon, Vaughn. "Implementing Domain-Driven Design" (2013)
- The Twelve-Factor App: https://12factor.net/
- Cloud Native Computing Foundation: https://www.cncf.io/
- ADR GitHub Organization: https://adr.github.io/
Notes
- The shift from "microservices as default" to "right-sized services" reflected growing maturity
- Platform engineering emerged as a discipline to manage infrastructure complexity
- GraphQL federation gained traction for API gateway patterns
- WebAssembly (Wasm) began appearing in edge computing and serverless contexts
- Supply chain security (SBOM, signing) became critical after high-profile incidents
- Internal developer platforms (IDPs) reduced cognitive load on application teams