Software Architecture
Vocabulary for solution architects and senior engineers: architectural patterns, design principles, system decomposition strategies, and the language of trade-off discussions.
- Monolith /ˈmɒnəlɪθ/
A software application deployed as a single unit where all components share the same process, codebase, and database. Simpler to develop and deploy initially; harder to scale and maintain as complexity grows. Variants: modular monolith (clear internal boundaries, single deployment), distributed monolith (microservices in name, but tightly coupled).
"Our monolith has served us well for five years, but independent team deployments are now impossible — a bug in the billing module blocks shipping the user profile feature. We're planning a gradual extraction using the strangler fig pattern."
- Microservices /ˈmaɪkroʊˌsɜːrvɪsɪz/
An architectural style where the application is a collection of small, independently deployable services, each owning its own data and communicating over the network (typically REST or gRPC). Benefits: independent deployment, scalability per service, technology diversity. Costs: network complexity, distributed transactions, operational overhead.
"Microservices fixed our deployment bottleneck — the payments team now ships 5 times per day without coordinating with the 12 other teams. The cost is our distributed tracing system to debug cross-service failures."
- Event-Driven Architecture /ɪˈvent ˈdrɪvən ˈɑːrkɪtektʃər/
An architectural pattern where services communicate through events (messages describing something that happened). Producers emit events; consumers react to them independently. Decouples producers from consumers — the emitter doesn't know who handles the event. Common infrastructure: Kafka, RabbitMQ, AWS EventBridge. Enables loose coupling and independent scaling.
"We moved to event-driven architecture for order processing — when an order is placed, the OrderPlaced event is emitted. The inventory service, notification service, and analytics pipeline each consume it independently. Adding a new consumer is a one-service change, not a change across the whole system."
- CQRS (Command Query Responsibility Segregation) /siː kjuː ɑːr es/
A pattern separating the write model (commands: create, update, delete) from the read model (queries). The write model focuses on data consistency and validation; the read model is optimised for query performance (often denormalised). Can use separate databases. Often combined with event sourcing.
"CQRS solved our reporting problem — the write database is a normalised PostgreSQL store optimised for transactions; the read model is an Elasticsearch index optimised for complex queries. The event bus synchronises them asynchronously."
- Saga Pattern /ˈsɑːɡə ˈpætərn/
A pattern for managing distributed transactions across multiple services without a global ACID transaction. A saga is a sequence of local transactions, each publishing an event that triggers the next. If a step fails, compensating transactions undo the previous steps. Types: choreography (event-driven, no central coordinator), orchestration (a saga orchestrator directs each step).
"The order fulfilment saga coordinates five services: payment, inventory, warehouse, shipping, and notification. If the warehouse step fails, compensating transactions refund the payment and release the inventory reservation."
- Circuit Breaker /ˈsɜːrkɪt ˈbreɪkər/
A stability pattern that prevents cascading failures: wraps calls to an external dependency and "opens" (stops making calls) when failures exceed a threshold. States: Closed (normal), Open (failing fast — no calls made), Half-Open (probing whether the dependency has recovered). Named after the electrical circuit breaker. Implemented by: Resilience4j, Hystrix, Polly.
"The recommendation service had no circuit breaker — when the ML inference API slowed down, all request threads stacked up waiting, eventually exhausting the thread pool and taking down the recommendation service. A circuit breaker would have failed fast and returned cached recommendations instead."
- Strangler Fig Pattern /ˈstræŋɡlər fɪɡ ˈpætərn/
A migration strategy for incrementally replacing a legacy system with a new one. New functionality is built alongside the old system; a routing layer (the "strangler vine") progressively redirects traffic to the new system as it grows. The legacy system is strangled department by department until it can be switched off. Avoids a high-risk "big bang" rewrite.
"We're using the strangler fig to migrate off the 12-year-old Ruby monolith. Each quarter we extract one domain — user management is now its own service. By the end of next year, only the core checkout flow remains in the monolith."
- Domain-Driven Design (DDD) /dəˈmeɪn ˈdrɪvən dɪˈzaɪn/
An approach where software structure and language reflect the business domain. Key concepts: Ubiquitous Language (shared vocabulary between engineers and domain experts), Bounded Context (a boundary within which a model is consistent and unified), Aggregate (a cluster of objects treated as a single unit for data changes), Domain Events, Anti-Corruption Layer.
"Our DDD approach means the payments service's model of a Customer is intentionally different from the CRM's model — they share an ID but the bounded contexts define what properties are relevant. An anti-corruption layer translates between them."
- Bounded Context /ˈbaʊndɪd ˈkɒntekst/
A DDD concept: the boundary within which a particular model (its terms, rules, and invariants) is consistent and valid. The same concept (e.g., "User") can have different meanings in different bounded contexts (in Payments: a billing entity with payment methods; in Identity: a security principal with credentials; in Analytics: an anonymous session subject).
"We had a God Object User model used by every service — it had 80 fields and was a constant source of merge conflicts. DDD bounded contexts helped: each service now owns its own User model with only the properties relevant to its domain."
- Anti-Corruption Layer (ACL) /ˈænti kəˈrʌpʃən ˈleɪər/
A pattern that isolates a new service from a legacy system by translating between their different models at the boundary. The ACL prevents the legacy system's model and language from "corrupting" the new clean model. Useful during strangler fig migrations and when integrating with third-party systems with different terminology.
"The payment gateway uses the term "transaction" for what we call an "order attempt" — the ACL translates between our domain model and the gateway's model. Our service never knows about gateway-specific concepts; the ACL handles all translation."
- SOLID Principles /ˈsɒlɪd ˈprɪnsɪpəlz/
Five object-oriented design principles: Single Responsibility (a class has one reason to change), Open/Closed (open for extension, closed for modification), Liskov Substitution (subtypes must be substitutable for their base types), Interface Segregation (many specific interfaces over one general), Dependency Inversion (depend on abstractions, not concretions). A guiding framework for maintainable code.
"The God class violated Single Responsibility — it handled database access, business logic, validation, and email sending. Refactoring to SOLID extracted each concern into its own class, making unit testing possible and deployment risk manageable."
- Coupling and Cohesion /ˈkʌplɪŋ ænd koʊˈhiːʒən/
Coupling: the degree of interdependence between modules. Low (loose) coupling is desirable — changes in one module don't cascade to others. Cohesion: the degree to which elements within a module belong together. High cohesion is desirable — a module does one thing well. The goal: high cohesion within modules, low coupling between them.
"The billing and user modules were highly coupled — a schema change in the users table required changes in billing, shipping, and analytics. We decoupled them through events: billing subscribes to UserUpdated events instead of querying the users table directly."
- API Gateway /eɪ piː aɪ ˈɡeɪtweɪ/
A server that acts as an entry point for all client requests, routing them to the appropriate microservice. Handles cross-cutting concerns: authentication, rate limiting, SSL termination, request logging, response caching, API versioning, and protocol translation. Examples: AWS API Gateway, Kong, Nginx, Traefik.
"The API gateway handles authentication for all 30 microservices — services no longer need to validate JWTs themselves. Adding a new security requirement (e.g., blocking requests from specific IP ranges) is a gateway configuration change, not a code change across 30 services."
- Sidecar Pattern /ˈsaɪdkɑːr ˈpætərn/
A service mesh pattern where a proxy container is deployed alongside each service container in the same pod/host. The sidecar handles cross-cutting infrastructure concerns: service discovery, load balancing, mTLS, observability, and circuit breaking — without the service needing to implement them. Envoy is the most common sidecar proxy; Istio and Linkerd are common service meshes built on Envoy.
"With a sidecar, our 30 services each have an Envoy proxy handling mTLS, distributed tracing, and retry logic. The application code is completely unaware — it makes plain HTTP calls, and the sidecar handles encryption and observability."
- Hexagonal Architecture /hekˈsæɡənəl ˈɑːrkɪtektʃər/
Also called Ports and Adapters. The core domain logic (hexagon centre) is isolated from all external dependencies (databases, APIs, message queues, UIs). Each external system connects through a port (interface) and an adapter (implementation). The domain never imports framework or infrastructure code — it depends only on abstractions. Enables testing the domain in isolation.
"Hexagonal architecture means our order domain has zero framework imports — we test the entire business logic with in-memory repositories and fake event publishers. Swapping the database or the message broker is a one-file change with no impact on the domain tests."
- CAP Theorem /kæp ˈθɪərəm/
In a distributed system, you can guarantee at most two of three properties simultaneously: Consistency (all nodes see the same data at the same time), Availability (every request receives a response), Partition Tolerance (the system continues operating despite network splits). Since network partitions are unavoidable, the real trade-off is CP (consistent, may be unavailable during partition) vs AP (available, may return stale data during partition).
"Our shopping cart uses an AP store — during a network partition, users can still add to their cart (availability) but two simultaneous sessions might briefly see different cart contents (eventual consistency). For checkout, we switch to a CP store — we cannot allow two users to purchase the last item."
Quick Quiz — Software Architecture
Test yourself on these 16 terms. You'll answer 10 multiple-choice questions — each shows a term, you pick the correct definition.
What does this term mean?