🔙 All posts

4 Architectural Fundamentals Developers Can't Ignore

The compact, practical guide to four pillars of software architecture: Characteristics, Decisions, Components, and Styles—what they are, how to use them, and how to trade them off.


Planted October 29, 2024

Last tended August 01, 2025

4 Architectural Fundamentals Developers Can’t Ignore

We ship features, but we run systems. Architecture connects the two. Here’s a concise field guide to four fundamentals you’ll use on every project.


The 4 Fundamentals (and how to apply them)

1) Architectural Characteristics (the non-functional drivers)

These shape everything else. Pick a few that truly matter for your context and make them measurable.

CharacteristicTypical Metric (example)
Performancep95 latency ≤ [PLACEHOLDER] ms
ScalabilitySustains [PLACEHOLDER]x traffic with ≤ [PLACEHOLDER]% error rate
ReliabilitySLO: 99.9% success; MTTR < [PLACEHOLDER] mins
SecurityZero critical vulns; least-privilege access reviews quarterly
Maintainability/EvolvabilityLead time < [PLACEHOLDER] days; change failure rate < [PLACEHOLDER]%
Operability/ObservabilityAlerting on SLO burn; logs + traces for critical paths

Use: Write 3–5 targets, review them before big design choices, and test against them in CI or load tests.


2) Architectural Decisions (make trade-offs explicit)

Bias to reversible choices early; document the rest with lightweight ADRs.

Minimal ADR template:

# ADR [NUMBER]: [DECISION]
Date: [YYYY-MM-DD]
## Status
Proposed | Accepted | Superseded by ADR [N]
## Context
What problem are we solving? Constraints? (e.g., latency SLO, team size)
## Options
- Option A: [PLACEHOLDER]
- Option B: [PLACEHOLDER]
## Decision
We chose [OPTION].
## Consequences
Positive: [PLACEHOLDER]
Negative (risks/debt): [PLACEHOLDER]

Good practice

  • Record why not chosen for major options.
  • Link ADRs to tickets and docs.
  • Revisit when assumptions change (new scale, new team, new SLOs).

3) Logical Components (boundaries before boxes)

Decompose by business capability first; keep components highly cohesive and loosely coupled.

Checklist

  • Clear purpose in one sentence.
  • API/contract defined (inputs, outputs, errors, SLAs).
  • No bidirectional dependencies.
  • Data ownership is explicit.
  • Observability baked in (logs, metrics, traces).

Example decomposition (e-commerce)

  • Catalog (owns products)
  • Ordering (owns orders)
  • Payments (owns payments, talks to PSP)
  • Fulfillment (owns shipments)

4) Architectural Styles (choose by constraint, not fashion)

Start simple; evolve when signals appear.

StyleWhat it isUse whenWatch out for
Layered MonolithOne deployable, clear layers (UI, domain, data)Small team, fast iterationHidden coupling, “ball of mud” without module boundaries
Modular MonolithOne deployable, strong module boundariesNeed domain boundaries + easy opsEnforce boundaries (linters/CI) or they erode
MicroservicesMany small, independently deployable servicesTeam autonomy + wildly different scaling profilesDistributed complexity, eventual consistency, higher ops cost
Event-DrivenAsync via events/queuesLoose coupling, audit trails, integrationsDebugging flows; need idempotency and schema governance
Hexagonal (Ports & Adapters)Domain core decoupled from I/OTestability, multiple adapters (DBs, queues)Over-abstracting when scope is tiny
ServerlessFunctions + managed servicesSpiky traffic, minimal opsCold starts, local dev friction

Evolution path

  • From monolith to modular monolith to microservices when you see: team bottlenecks, divergent scaling, or change blasts across modules.

Putting it together (quick workflow)

  1. Define 3–5 characteristics with targets.
  2. Sketch components by capability; write contracts.
  3. Choose style that best satisfies step 1 with least complexity.
  4. Capture decisions with ADRs.
  5. Prove it: add load tests/chaos drills against your targets.
  6. Evolve when pain signals persist after local fixes.

Common pitfalls (and fixes)

  • Accidental complexity > essential complexity → Start with a modular monolith.
  • Hand-wavy “ilities” → Quantify SLOs and test them.
  • Tribal knowledge → ADRs + diagrams-as-code in repo.
  • Tight coupling via database sharing → Private data per component; communicate via APIs/events.
  • Over-engineered abstractions → YAGNI; prefer reversible decisions.

Key Takeaways

  • Let business characteristics drive structure and tech.
  • Make trade-offs explicit with ADRs.
  • Design cohesive components with clear ownership.
  • Pick the simplest style that meets your targets; evolve deliberately.

Next Steps

  • Identify and measure 3–5 characteristics for your current system.
  • Add an /adr folder and write ADR 000: “Record architecture decisions”.
  • Map your system into 4–8 components with owners and contracts.
  • Run a lightweight load test against your SLO targets.

Resources

  • Watch the video on YouTube
  • Software Architecture Patterns — Mark Richards
  • Building Evolutionary Architectures — Ford, Parsons, Kua
  • The Twelve-Factor App and Google SRE concepts (SLOs, error budgets)

Part of my YouTube tutorial series. Subscribe to my channel.

Like what you see?

I send out a (semi) regular newsletter which shares the latest from here and my reading from around the web. Sign up below.

    Your next read?