Hermes Wiki

Layered (N-Tier) Architecture

Concept

Layered architecture — also called N-tier — is the default shape most applications start as, whether or not anyone deliberately designed it: the codebase is split into horizontal layers (typically presentation, business logic, and data access), each with one responsibility, and each layer only allowed to call the layer directly below it. A higher layer can use services in a lower layer, but a lower layer never calls back up — that one-directional dependency rule is the entire point of the pattern, since it's what keeps business logic from becoming entangled with UI concerns or persistence details.

"Layered" and "N-tier" are frequently used interchangeably but describe two related-but-distinct things. Layers are a logical/code-organization concept — presentation code, business logic code, and data-access code can live as three layers inside a single deployable process. Tiers are a physical/deployment concept — whether those layers actually run on physically separate machines (a web tier, an app tier, a database tier) or are colocated. A classic three-tier deployment maps one tier to each layer, but it's entirely possible to have three logical layers deployed as a single tier (a monolith with clean internal layering) or layers split across more tiers than layers for scaling reasons. Conflating the two is a common source of confusion when a team says "we're moving to microservices" but really means "we're splitting one tier into several," without touching the internal layering at all.

Tradeoffs

Aspect Benefit Cost
Testability Business logic can be tested in isolation from the database or UI by mocking the layer below it Only true if the layering is actually respected — see the common pitfall below
Maintainability A change to how data is persisted (switching databases, adding caching) is contained to the data layer and shouldn't ripple into business logic A change to business logic that needs new data (a new column, a new query shape) still requires touching all three layers together
Team scaling Clear, well-understood mental model — most engineers already know it, low onboarding cost A feature that touches presentation, business logic, and data access simultaneously requires coordinating across whichever teams own each horizontal layer, which gets worse as team count grows against a small number of layers
Enforcement Simple to reason about in principle (one direction of dependency) The pattern is a convention, not a compiler-enforced boundary — nothing stops the presentation layer from reaching straight into the data layer except discipline and code review, and that discipline erodes under deadline pressure

The team-scaling row is the tradeoff most often underweighted at adoption time: layered architecture organizes code by technical concern (what kind of code this is) rather than by business capability (what feature this serves), which is efficient for a small team but becomes a coordination bottleneck once ten feature teams are all making changes that cut across the same three horizontal layers.

When to use / when not to

  • Use it as the default for a straightforward CRUD-style application, especially early on — most frameworks (a typical MVC web framework, a typical ORM-backed service) already assume this shape, so fighting it for a different pattern adds cost with no clear payoff yet.
  • Use it when the team is small enough that cross-layer coordination on a single feature isn't a real bottleneck — the classic failure mode (see Tradeoffs above) only bites once team count grows.
  • Reach for a business-capability-first split — vertical slices, modules with their own presentation/logic/data per feature (see Modular Monolith), or eventually microservices — once most changes are cutting across all three layers for a single feature and coordinating that across teams is the actual bottleneck, not a hypothetical one.
  • Don't add layers beyond what's needed "for scalability" without a concrete tier that actually needs independent scaling — an extra tier that's always deployed and scaled 1:1 with the others adds latency (an extra network hop) and operational surface for no real benefit.
  • Don't assume layering alone gives you testability or maintainability — those only materialize if the layers are actually enforced; a codebase that's nominally layered but riddled with cross-layer shortcuts gets none of the benefit and all of the ceremony.

Common pitfall

The "architecture sinkhole" anti-pattern: layers that exist on paper but aren't actually enforced by anything except convention, so requests punch straight through from presentation to data access with no real business logic in between, or — worse — the presentation layer reaches directly into the data layer, skipping business logic entirely "just this once" under deadline pressure. Once that happens, business rules end up scattered wherever it was fastest to add them (a controller, a database trigger, a UI component), the layering diagram stops matching reality, and the very testability/maintainability benefits the pattern was adopted for evaporate — while still paying the full cost of maintaining the pretense of layers. This is a discipline problem, not a technology problem: nothing about layered architecture prevents it, and nothing except code review and dependency-direction linting stops it from creeping in.

Engineering Lens

The judgment call worth defending in a design review isn't "we use layered architecture" as a static fact — it's being explicit about which axis is actually driving the decision: is this about code organization (layers), physical scaling (tiers), or team boundaries? Those are three different problems that layered architecture bundles together by default, and a system that's outgrown the pattern usually shows the symptom on exactly one of those three axes first (often team coordination, well before physical scaling becomes the real constraint). The stronger answer is naming which axis is currently the bottleneck and picking the next architecture deliberately in response to that specific pressure — a business-capability split for team-coordination pain, independent tier scaling for a genuine hot spot — rather than migrating away from layering wholesale because it's fashionable to.

Sources

Hermes Wiki