Architecture
Software architecture is the set of significant design decisions about a system's structure, the elements it is composed of, their relationships, and the properties of both. It is defined as much by the constraints it imposes as by the freedom it permits. Following ISO/IEC/IEEE 42010, an architecture is expressed through views that address the concerns of distinct stakeholders.
Architectural Style
An architectural style is a named, reusable pattern of system organisation that defines element types and the rules that govern their interaction, such as layered, microservices, event-driven, or pipe-and-filter. A style is broader than a design pattern: it shapes the whole system rather than a localised problem. Choosing a style commits the system to a particular set of quality-attribute trade-offs.
Architecture Decision Record (ADR)
An ADR is a short document that captures one significant architectural decision, its context, the options considered, the decision taken, and its consequences. ADRs are stored alongside the code so the reasoning behind a choice survives the people who made it. They make architecture an auditable, append-only log rather than tribal knowledge.
Quality Attribute
A quality attribute is a measurable or testable property of a system that indicates how well it satisfies stakeholder needs beyond raw functionality, such as performance, availability, scalability, security, or modifiability. Architecture is the primary lever for quality attributes because they are mostly determined by structure, not by local code. They are specified with concrete scenarios (stimulus, environment, response, response measure) rather than vague adjectives.
Coupling
Coupling is the degree of interdependence between two elements: how much one must know about another to function. Loose coupling lets elements change, deploy, and be reasoned about independently; tight coupling propagates change and failure. Architecture reduces coupling through stable interfaces, dependency inversion, and asynchronous messaging.
Cohesion
Cohesion measures how strongly the responsibilities within a single element belong together. High cohesion means an element has one clear reason to exist; low cohesion mixes unrelated concerns and tends to change for many reasons. The structural goal of good architecture is high cohesion within modules and loose coupling between them.
Layered Architecture
Layered (n-tier) architecture organises a system into horizontal layers - typically presentation, application, domain, and persistence - where each layer depends only on the layer below. It is the default enterprise style because it separates concerns and is easy to reason about. Its risks are the "sinkhole" anti-pattern, where requests pass through layers that add no value, and accidental coupling when layers are bypassed.
Hexagonal Architecture
Hexagonal architecture (Ports and Adapters), introduced by Alistair Cockburn, isolates application logic inside a boundary that communicates with the outside world only through ports (interfaces) implemented by adapters. The same core can be driven by tests, a web controller, or a CLI, and can talk to a real database or an in-memory fake. It makes the application independent of delivery mechanisms and infrastructure.
Clean Architecture
Clean Architecture, formulated by Robert C. Martin, arranges code in concentric rings where source-code dependencies point only inward toward enterprise and application business rules. Frameworks, UI, and databases live in the outermost ring and are treated as plugins. The dependency rule keeps business logic testable and independent of volatile technology choices.
Onion Architecture
Onion architecture places the domain model at the centre, surrounded by domain services, application services, and finally infrastructure and UI on the outside, with all dependencies pointing inward. It is a close relative of Hexagonal and Clean Architecture, sharing the dependency-inversion principle. The aim is to protect the domain from infrastructural churn.
Microservices
Microservices structure an application as a suite of small, independently deployable services, each owning its data and communicating over the network. They enable independent scaling and deployment and let teams work autonomously, at the cost of distributed-systems complexity. They suit organisations with the operational maturity to run many services and a domain that decomposes cleanly.
Monolith
A monolith is a system deployed as a single unit, with all modules sharing one process and usually one database. A well-structured "modular monolith" keeps strong internal boundaries while avoiding the network, consistency, and operational overhead of distribution. Starting with a monolith and extracting services only when a real need appears is a widely recommended default.
Service-Oriented Architecture (SOA)
SOA structures functionality as coarse-grained, reusable services that are discoverable and communicate through a shared messaging layer, historically an enterprise service bus. It predates microservices and emphasises enterprise-wide reuse and orchestration. Microservices are often described as a more fine-grained, decentralised evolution of SOA without a central bus.
Event-Driven Architecture
Event-driven architecture composes a system from producers that emit events and consumers that react to them, decoupled through a broker or log. It enables loose coupling, asynchronous processing, and scalability, but trades away the simplicity of synchronous request/response. Reasoning about end-to-end flow and ordering becomes harder and requires correlation and tracing.
Event Sourcing
Event sourcing persists the full sequence of state-changing events as the source of truth rather than only the current state. Current state is derived by replaying events, which yields a complete audit trail and the ability to rebuild projections. Its costs are schema evolution of events, eventual consistency of read models, and added conceptual complexity.
CQRS
Command Query Responsibility Segregation splits the model that mutates state (commands) from the model that reads it (queries), allowing each side to be optimised and scaled independently. It is frequently paired with event sourcing and read-side projections. CQRS adds complexity and is justified only when read and write workloads or models genuinely diverge.
Domain-Driven Design (DDD)
Domain-Driven Design is an approach that aligns the software model with the business domain through a shared ubiquitous language and explicit modelling of bounded contexts, aggregates, and domain events. Its strategic patterns shape system boundaries; its tactical patterns shape the model inside a boundary. DDD is most valuable in complex domains where the model, not the technology, is the hard part.
Bounded Context
A bounded context is an explicit boundary within which a particular domain model and its ubiquitous language are internally consistent. The same term can legitimately mean different things in different contexts, and integration happens through well-defined contracts such as a context map. It is the central strategic pattern of DDD and a natural candidate boundary for a service.
Aggregate
An aggregate is a cluster of domain objects treated as a single unit for data changes, accessed only through its aggregate root, which enforces the cluster's invariants. Every transaction should modify a single aggregate to keep consistency boundaries clear. Small aggregates reduce contention and map cleanly onto one database transaction.
API Gateway
An API gateway is a single entry point that sits in front of backend services and handles cross-cutting concerns such as routing, authentication, rate limiting, request aggregation, and protocol translation. It shields clients from the internal service topology and lets services evolve behind a stable façade. Overloading it with business logic turns it into a coupling-prone bottleneck.
Backend for Frontend (BFF)
A Backend for Frontend is a dedicated gateway tailored to the needs of one specific client experience, such as a web app or a mobile app. Each BFF aggregates and shapes data for its consumer, avoiding a single generic gateway that must satisfy every client. The pattern trades some duplication for clearer ownership and client-specific optimisation.
Service Mesh
A service mesh is an infrastructure layer that handles service-to-service communication concerns - mutual TLS, retries, timeouts, load balancing, and observability - through sidecar proxies, transparently to application code. It moves resilience and security policy out of each service and into a uniform control plane. Its cost is operational complexity and per-hop latency.
Saga
A saga manages a business transaction that spans multiple services as a sequence of local transactions, each with a compensating action to undo it if a later step fails. It replaces distributed two-phase commit, which does not scale across autonomous services. Sagas come in orchestration (a coordinator drives steps) and choreography (services react to events) variants.
Eventual Consistency
Eventual consistency is a guarantee that, in the absence of new updates, all replicas of a piece of data will converge to the same value over time, without guaranteeing immediate consistency. It is the consistency model most distributed and microservice systems accept in exchange for availability and partition tolerance. Designs must surface and tolerate the window of inconsistency rather than hide it.
CAP Theorem
The CAP theorem states that a distributed data store can simultaneously provide at most two of Consistency, Availability, and Partition tolerance. Because network partitions are unavoidable in practice, real systems effectively choose between consistency and availability when a partition occurs. It frames a fundamental trade-off but is a simplification of the richer PACELC formulation.
Idempotency
An operation is idempotent if performing it multiple times has the same effect as performing it once. Idempotency makes retries safe in distributed systems, which is essential because networks deliver "at least once" far more easily than "exactly once". It is commonly implemented with idempotency keys the receiver deduplicates on.
Resilience
Resilience is a system's ability to keep providing acceptable service in the face of faults, degraded dependencies, and load spikes. It is engineered with patterns such as timeouts, retries with backoff, circuit breakers, bulkheads, and graceful degradation. The goal is to contain failure rather than assume it never happens.
Circuit Breaker
A circuit breaker is a resilience pattern that stops calls to a failing dependency once an error threshold is crossed, failing fast instead of exhausting threads on calls that will time out. After a cooldown it allows trial calls (half-open) to test recovery before closing again. It prevents a single slow dependency from cascading into a system-wide outage.
Bulkhead
The bulkhead pattern isolates resources - such as thread pools or connection pools - per dependency so that the failure or saturation of one cannot consume the capacity needed by others. The name comes from a ship's watertight compartments that stop one flooded section from sinking the vessel. It limits the blast radius of a misbehaving dependency.
Scalability
Scalability is the ability of a system to handle increased load by adding resources. Vertical scaling adds capacity to a single node; horizontal scaling adds more nodes and is the basis of cloud elasticity. Stateless services, partitioned data, and asynchronous processing are the structural enablers of horizontal scale.
Availability
Availability is the proportion of time a system is operational and able to serve requests, usually expressed in "nines" (for example 99.9%). It is improved with redundancy, failover, health checks, and the elimination of single points of failure. It is explicitly traded against consistency under the CAP theorem during partitions.
Fault Tolerance
Fault tolerance is the property of continuing correct operation despite the failure of some components. It is achieved through redundancy, replication, and automatic failover so that no single fault takes the system down. It differs from resilience in emphasising the masking of faults rather than degrading gracefully.
Strangler Fig
The Strangler Fig pattern incrementally replaces a legacy system by routing functionality to a new system feature by feature, until the old system can be retired. New behaviour grows around the legacy like a strangler fig around a tree. It de-risks rewrites by avoiding a single big-bang cutover.
Anti-Corruption Layer
An anti-corruption layer is a translation boundary that protects a bounded context from the model of an external or legacy system, converting between the two so foreign concepts do not leak inward. It keeps the internal model clean when integrating with systems you do not control. It is a key DDD pattern for safe integration.
Sidecar
The sidecar pattern deploys a helper component alongside a primary application in the same unit (for example a pod), extending it with capabilities such as logging, configuration, or proxying without changing the application. Service-mesh data planes are implemented as sidecars. It enables polyglot reuse of cross-cutting functionality.
Twelve-Factor App
The Twelve-Factor App is a methodology of twelve principles for building portable, scalable services suited to cloud platforms, covering config in the environment, stateless processes, explicit dependencies, and disposability. It codifies practices that make applications easy to deploy and scale horizontally. It strongly influenced modern cloud-native architecture.
Cloud-Native
Cloud-native describes systems designed to exploit the elasticity, managed services, and automation of cloud platforms, typically using containers, orchestration, microservices, and declarative infrastructure. The emphasis is on resilience, scalability, and rapid, automated delivery. The CNCF stewards much of the surrounding ecosystem.
Conway's Law
Conway's Law observes that organisations design systems whose structure mirrors their own communication structure. It implies that team boundaries tend to become architectural boundaries, for better or worse. The "Inverse Conway Manoeuvre" deliberately shapes teams to produce a desired architecture.
Architecture Evaluation (ATAM)
The Architecture Tradeoff Analysis Method is a structured, scenario-based technique from the Software Engineering Institute for evaluating an architecture against its quality-attribute requirements before it is built out. It elicits scenarios, identifies architectural approaches, and surfaces sensitivity points, trade-offs, and risks. It turns architectural review into a repeatable, evidence-based activity.
Fitness Function
An architectural fitness function is an automated, objective test of a desired architectural characteristic - such as a layering rule, latency budget, or dependency constraint - that fails the build when the property is violated. It is the core mechanism of evolutionary architecture, making architectural integrity continuously verifiable. Tools like ArchUnit express such rules in code.
Evolutionary Architecture
An evolutionary architecture is one designed to support guided, incremental change across multiple dimensions, protected by fitness functions rather than frozen up front. It treats change as expected and architecture as a living constraint that is continuously validated. The approach rejects the idea that a perfect architecture can be specified once at the start.
Dependency Inversion Principle
The Dependency Inversion Principle states that high-level modules should not depend on low-level modules; both should depend on abstractions, and abstractions should not depend on details. It is the mechanism that lets domain logic stay independent of frameworks and databases. It is the structural foundation of Hexagonal, Onion, and Clean Architecture.
Separation of Concerns
Separation of concerns is the principle of dividing a system so that each part addresses a distinct concern with minimal overlap. It underlies layering, modularity, and the single-responsibility principle, and is the main weapon against accidental complexity. Concerns cleanly separated can be changed, tested, and understood in isolation.
Architectural Drift
Architectural drift is the gradual divergence between the intended architecture and the system as actually built, caused by expedient changes that erode boundaries. Left unchecked it becomes architectural erosion, where the original structure is no longer recognisable. Fitness functions and dependency checks are used to detect and prevent it.
Technical Debt
Technical debt is the implied future cost of choosing an expedient solution now over a better but slower one. Like financial debt it accrues "interest" as the shortcut makes future change harder. Deliberate, recorded debt can be a sound trade-off; reckless, hidden debt silently degrades the architecture.
Read Model (Projection)
A read model, or projection, is a denormalised, query-optimised representation of data built specifically to serve reads, kept separate from the write model. It is central to CQRS and event-sourced systems, where projections are rebuilt by replaying events. It decouples query performance from the constraints of the transactional write schema.
C4 Model
The C4 model is a lightweight technique for visualising software architecture at four levels of abstraction - System Context, Containers, Components, and Code - so each diagram targets a specific audience. It favours a small, consistent notation over heavyweight formalism. It is widely used to keep architecture diagrams understandable and maintainable.