Layered architecture splits a system into horizontal layers — usually Presentation, Application, Domain, Data — where each layer only depends on the one below. It's the classic enterprise layout you'll meet in nearly every Java EE, Spring, ASP.NET, or Django app. Easy to understand, easy to teach, and surprisingly easy to misuse.
← Back to ArchitectureShow a new engineer the folder structure and they immediately know where things live. controllers/, services/, repositories/. Every framework's official tutorial uses some version of it.
Spring, ASP.NET, Django, Rails, NestJS — every major framework has annotations, scaffolds, and conventions for layered code. @Controller, @Service, @Repository map directly.
If presentation talks only to the service layer, you can add a new front end (REST, GraphQL, gRPC, CLI) without touching domain or data. If services talk only to repository interfaces, swapping the persistence backend is bounded.
Domain entities become bags of getters and setters; all the behavior leaks into "services" that read fields and decide. The "domain" layer ends up with no domain in it. Sound familiar? This is the layered pattern's most common failure.
Antidote: push behavior back onto entities. account.debit(amount) instead of service.debit(account, amount).
Controllers query the DB directly "just for this one endpoint." Repositories return ORM entities that the controller serializes straight to JSON, leaking schema to clients. Without enforcement, the lines blur and the architecture stops paying off.
If you organize top-level by layer (controllers/, services/, repositories/), the billing module is smeared across all three folders. Reading "what does billing do?" requires opening three places. Modular monoliths flip this — top-level by feature, layers inside each module.
"I need to add this logic somewhere — services, I guess?" Result: 5,000-line service classes orchestrating everything because nobody knew where else to put it. The pattern doesn't tell you when to split a service, so most teams don't.
Adding one field can mean updating: DTO → controller → service → mapper → entity → repository → DB schema. Six edits to add one column. Many teams quietly relax strict layering for this reason.
Web servers, app servers, database — deployed on different machines. The browser hits a load balancer, which hits app servers, which hit the DB. Still the basis of most web architectures, even ones that call themselves something else.
Presentation-layer patterns within layered architecture. MVC (Model-View-Controller) is the workhorse for server-rendered apps. MVVM binds views to view-models for data-binding-heavy clients (WPF, Vue). MVP adds a presenter that drives passive views.
Closed: a layer can only call the one directly below. Strictest; most boilerplate.
Open: a layer can call any layer below it. Practical; risks turning into a free-for-all.
Reasonable default for:
Reach instead for hexagonal / clean when the domain is rich, long-lived, and has to outlive multiple infrastructure choices. Reach for modular monolith organization when multiple bounded contexts coexist — slice top-level by feature, then keep layers inside each feature.