Software Architecture Patterns - The Decision Maker's Handbook
V1
Back to handbooks index

Software Architecture Patterns: The Decision Maker's Handbook

Enterprise-grade architecture guidance focused on trade-offs, organizational constraints, and operational reality.

Principal Architect View Pragmatism over Hype No Silver Bullet Complete - Modules 1 to 6
i
Acknowledgement: This handbook is being delivered module-by-module. This iteration includes the Table of Contents and Module 1. Every recommendation is framed as a trade-off: there is no universally best architecture, only context-appropriate decisions.
!
Core framing: Conway's Law applies in practice: system architecture mirrors communication structure. Team topology and size can drive architecture as strongly as latency targets, throughput, and data constraints.

Table of Contents

This handbook is structured as a decision system, not a trend catalog.

Module 1: The Monolith & The Modular Monolith

Module 2: Microservices Architecture

Module 3: Event-Driven Architecture (EDA)

Module 4: Serverless Architecture (FaaS)

Module 5: The Architect's Decision Matrix

Module 6: Common Pitfalls & Anti-Patterns

Module 1: The Monolith & The Modular Monolith

Tip
Executive summary: If your organization is small and your domain is tightly coupled, a well-structured monolith is usually the fastest and safest path to product-market fit. Complexity should be paid only when your scale and team topology force you to pay it.

The Standard Monolith

A standard monolith is a single codebase deployed as a single deployment unit, usually backed by a shared database. Runtime boundaries are process boundaries, not network boundaries.

Real-world analogy: Think of a high-performing restaurant kitchen run by one team in one room. The grill station, pastry station, and plating station are specialized, but they can coordinate instantly without radio calls, shipping queues, or customs checks.

  • What you gain: Simple local development, one CI/CD pipeline, easy refactoring across features, and strong transactional consistency.
  • What you sacrifice: As the codebase and team grow, release coordination can become painful and deployment windows become risk-heavy.

The Modular Monolith

The modular monolith keeps the deployment simplicity of a monolith while introducing strict internal boundaries so parts of the system evolve with high autonomy.

Why the comeback is real: Many organizations overpaid for premature microservices and are now consolidating. The modular monolith recovers delivery speed by removing network overhead while preserving clear domain ownership and future extraction options.

Real-world analogy: Instead of splitting one building into many distant offices connected by highways, you build fireproof departments in the same building with controlled doors and documented handoff rules.

How to enforce strict boundaries in one codebase

  • Package by business capability: Organize modules around domains (Billing, Catalog, Identity), not technical layers only.
  • Use explicit module contracts: Each module exposes a small public API and hides internal implementation.
  • Ban cross-module backdoor access: Disallow direct imports to internal folders via lint rules and architecture tests.
  • Use separate schemas/tables by module where practical: Shared database engine is acceptable, but ownership boundaries must be explicit.
  • Prefer domain events internally: Publish in-process events between modules to reduce tight coupling.
  • Treat module boundaries as service boundaries: If a module cannot be extracted later without a rewrite, boundaries are too weak.

Illustrative boundary contract (conceptual)

// Modular monolith layout (single deployable, strict boundaries)
src/
  modules/
    billing/
      public-api.ts      // only import entry point for other modules
      application/
      domain/
      infrastructure/
      internal/          // inaccessible outside billing
    catalog/
      public-api.ts
    identity/
      public-api.ts

// Rule: cross-module imports must use modules/*/public-api.ts only

When to Use

  • Early-stage startups: Speed of iteration matters more than horizontal autonomy.
  • Small teams (under 15 engineers): Communication overhead of distributed systems usually outweighs benefits.
  • Highly coupled data domains: Strong consistency and transactional workflows are easier and safer.
i
Conway's Law in action: A single cross-functional team generally maps well to a modular monolith. Forcing microservices onto a small team often creates coordination debt without business upside.

Cost Profile

Explicit costs (easy to see):

  • Low infrastructure cost: fewer runtimes, fewer data stores, smaller platform footprint.
  • Low DevOps complexity: one pipeline, one deployment artifact, simpler observability baseline.

Hidden costs (often ignored until later):

  • Deployment blast radius: one bad release can impact the full product surface.
  • Downtime pressure during growth: deployment windows and rollback strategies become more critical as revenue and traffic rise.
  • Scaling mismatch: hot paths and cold paths scale together even when only one domain needs extra capacity.
  • Team contention risk: as headcount grows, merge conflicts and release coordination can slow delivery.
Decision Rule Module 1

Start with a modular monolith by default unless you can prove independent scaling and independent deployment are urgent constraints today, not hypothetical constraints for next year.

Module 2: Microservices Architecture

Microservices break a system into independent, deployable services aligned to business capabilities. Each service should own its data and API contract, often resulting in polyglot persistence across the estate.

The Concept

Real-world analogy: Think of an airport ecosystem. Security, baggage, boarding, fueling, and air traffic control are specialized organizations with their own systems and operating procedures. The system scales because each unit is autonomous, but coordination overhead is constant and non-trivial.

The Trade-offs

Fallacies of Distributed Computing are not theory: the network is not reliable, latency is not zero, bandwidth is finite, topology changes, and transport has cost. Every cross-service call is an operational risk surface.

!
Brutal truth: Microservices are an organizational scaling strategy first, and only secondarily a technical scaling strategy. If teams are not truly independent, you will buy complexity without delivery benefits.

When to Use

Cost Profile

Explicit costs:

Hidden costs:

Module 3: Event-Driven Architecture (EDA)

EDA lets services communicate asynchronously by publishing and consuming events through brokers like Kafka, RabbitMQ, or AWS EventBridge, instead of chaining synchronous REST calls for every interaction.

The Concept

Real-world analogy: A newsroom wire feed. A central feed publishes breaking events; finance, sports, and regional desks each consume and act based on their own priorities and timelines.

Choreography vs. Orchestration

i
Pragmatic pattern: Use choreography for broad fan-out domain notifications; use orchestration for long-running business workflows where auditability and deterministic recovery are mandatory.

When to Use

Cost Profile

Explicit costs:

Hidden costs:

Module 4: Serverless Architecture (FaaS)

Serverless architecture uses fully managed ephemeral compute (such as AWS Lambda or Azure Functions) with managed services for storage, messaging, and identity. Teams ship business logic while the platform handles most infrastructure operations.

The Concept

Real-world analogy: Hiring an on-demand specialist crew instead of running a full-time factory. You pay only when they are actively doing work, which is excellent for bursty demand and expensive for constant heavy throughput.

The Trade-offs

When to Use

Cost Profile

Explicit costs:

Hidden costs:

Module 5: The Architect's Decision Matrix

Use this matrix as a starting point. Then adjust for your constraints: regulatory requirements, uptime targets, budget, team skill profile, and migration horizon.

Architecture Team Size Required Deployment Complexity Scalability Infrastructure Cost (Low Traffic vs High Traffic) Best Real-World Use Case
Monolith / Modular Monolith Small to medium (3-15 engineers) Low initially; medium at larger codebase size Good vertical scaling; selective horizontal scaling with effort Low at low traffic; moderate at high traffic SaaS products finding product-market fit with tightly coupled domains
Microservices Large (50+ engineers, multiple autonomous teams) Very high Excellent independent scaling by domain High at low traffic; very high at high traffic due to platform overhead Large platforms with independent team ownership and release autonomy requirements
Event-Driven Architecture Medium to large (15+ engineers) High Excellent for burst handling and decoupled throughput Medium at low traffic; high at high traffic E-commerce, fintech, telemetry, and real-time processing pipelines
Serverless (FaaS) Small to medium (2-20 engineers) Low-to-medium for simple systems; medium at scale Excellent auto-scaling for bursty workloads Very low at low traffic; can become very high at sustained high traffic Event-driven backends, workflow automation, APIs with volatile demand
Decision Heuristic CIO/CTO Lens

Choose the cheapest architecture that safely satisfies your next 18 to 24 months of business and team constraints. Re-architect with evidence, not anticipation.

Module 6: Common Pitfalls & Anti-Patterns

Most architecture failures come from mismatch: organizational readiness and workload reality do not match the chosen pattern.

1) The Distributed Monolith

Teams split services physically but keep them logically coupled. Deployments still need lockstep coordination, and one service outage cascades through the graph.

Typical symptoms:

Why it hurts: You pay distributed-system costs without gaining deployment independence.

2) Resume-Driven Development

Organizations adopt Kubernetes, service mesh, and microservices because they are fashionable, not because business constraints demand them.

Typical symptoms:

Why it hurts: Architecture prestige is mistaken for product leverage; teams spend budget on complexity instead of customer outcomes.

3) Ignoring the Database

Compute is split into services while data remains in one shared, tightly coupled database. Service boundaries become cosmetic.

Typical symptoms:

Why it hurts: True autonomy requires data ownership boundaries. Without them, you get the coordination pain of both monolith and microservices.

4) Premature Scale Architecture

Teams over-engineer their initial architecture to handle anticipated scale that never materializes. This trades velocity for hypothetical future headroom.

Typical symptoms:

Why it hurts: Premature optimization of architecture increases time to first learning, burns runway on speculation, and locks you into designs that may be wrong for the actual product shape that emerges. Start simple; complexity is always cheaper to add than to remove.

!
Final warning: There is no best architecture, only fit-for-purpose architecture. Conway's Law is non-negotiable: if team communication patterns do not support your target architecture, the implementation will drift toward the org chart, not your diagram.