Chapter 9. Foundations
Background before the individual styles: the fundamental patterns architecture evolved through, and the hard realities (fallacies and extra challenges) that distributed architectures introduce over monolithic ones.
Fundamental patterns
- Big Ball of Mud — the absence of any discernible structure, named after the 1997 Foote & Yoder anti-pattern paper. A haphazard, sprawling, spaghetti-code system with information shared promiscuously and structure eroded beyond recognition. It makes change increasingly hard and suffers in deployment, testability, scalability, and performance. Few architects intend to create one; many projects drift into it through lack of governance around code quality and structure.
- Unitary architecture — the original state where software and hardware were a single entity (early mainframes), gradually splitting as needs grew (e.g. separating data into its own system).
- Client/server (two-tier) — separates technical function between frontend and backend. Variants by era:
- Desktop + database server — rich desktop UI with data on a standalone DB server reachable over standard protocols; presentation on the desktop, heavy computation on the DB.
- Browser + web server — even thinner clients (browsers) over web server → DB server; wider distribution inside and outside firewalls.
- Three-tier — popular in the late 1990s: industrial DB tier, application-server tier, and a generated-HTML/JavaScript frontend.
Monolithic vs distributed: the fallacies of distributed computing
Eight assumptions that quietly break distributed architectures because they all rely on the network:
- The network is reliable — it isn’t.
Service Bcan be healthy whileService Acan’t reach it, or a request gets no response. This is why timeouts and circuit breakers exist; the more a system leans on the network, the less reliable it potentially becomes. - Latency is zero — a local method call is nanoseconds/microseconds; a remote call (REST, messaging, RPC) is milliseconds. You must know your production average round-trip latency, and especially the 95th–99th percentile — the “long tail” is what kills performance. At ~100 ms/request, chaining 10 service calls adds ~1,000 ms; an average of 60 ms can hide a 95th percentile of 400 ms.
- Bandwidth is infinite — irrelevant in a monolith, but breaking a system into services means lots of inter-service chatter. Stamp coupling — a service returning 45 attributes (500 KB) when the caller needs only the name (200 bytes) — at 2,000 requests/second is ~1 Gb of bandwidth for one call out of hundreds. Fixes: private endpoints, field selectors, GraphQL, consumer-driven contracts (CDCs), internal messaging. The principle: pass the minimal data needed.
- The network is secure — VPNs and firewalls lull you into forgetting that every endpoint of every deployment unit must be secured. The attack surface grows by magnitudes versus a monolith, and securing every endpoint (even for inter-service calls) is another reason synchronous distributed architectures run slower.
- The topology never changes — routers, switches, firewalls, and appliances change constantly. A “minor” 2 a.m. network upgrade can invalidate all your latency assumptions and trigger timeouts/circuit breakers. Stay in constant contact with ops and network admins.
- There is only one administrator — large companies have dozens of network admins. Knowing who to talk to about latency or topology changes reflects the coordination overhead distributed architectures demand and monoliths don’t.
- Transport cost is zero — not latency, but actual money. Distributed architectures cost significantly more (extra hardware, servers, gateways, firewalls, subnets, proxies). Analyse current capacity, bandwidth, latency, and security zones before committing.
- The network is homogeneous — most companies run multiple network hardware vendors, which don’t always integrate seamlessly. Packets occasionally get lost, looping back into fallacies #1, #2, and #3.
Other distributed considerations
- Distributed logging — a monolith has one log; distributed systems have dozens to hundreds in different places and formats, making root-cause analysis hard. Consolidation tools like Splunk help but only scratch the surface.
- Distributed transactions — monoliths get ACID commits/rollbacks for free. Distributed systems rely on eventual consistency — the trade-off being high scalability/performance/availability at the cost of data consistency and integrity. Managed via transactional sagas (event sourcing for compensation, or finite state machines) and BASE transactions: Basic availability, Soft state (data in transit / temporarily inconsistent), Eventual consistency. BASE is a technique, not software.
- Contract maintenance and versioning — a contract is the behaviour and data agreed between client and service. Maintenance is hard because services are decoupled and owned by different teams; version deprecation and its communication models are especially complex.
Source
Mark Richards & Neal Ford, Fundamentals of Software Architecture, Chapter 9.