It made sense at the time.
So did 3-tier applications and monoliths.

Controller → Service → Repository.
It’s everywhere. It’s predictable. And every bootcamp teaches it.

But that doesn’t mean it’s always the right choice.

Let’s talk about when layering helps… and when it just gets in the way.


The Case for Layers

Layers exist for a reason: separation of concerns.

  • Controllers handle inputs and outputs (HTTP, CLI, etc.)
  • Services hold business logic
  • Repositories deal with data storage

This structure keeps things clean. Each part has a job.
On paper, it makes code easier to test and safer to change.


Where It Falls Apart

In real-world systems, the layer cake starts to crumble.

You Write Layers That Just Pass Data

js
// controller
export const getUser = (req, res) => {
  const user = userService.getUserById(req.params.id)
  res.send(user)
}

// service
const getUserById = (id) => {
  return userRepository.getById(id)
}

// repository
const getById = (id) => {
  return db.users.find((user) => user.id === id)
}

Three files. No real logic. Just pass-throughs.


One Change Touches Three Files

Need to add a field or flag?
You’re now editing controller, service, and repository just to wire it through.

Tests Become Glue Validation

You’re not testing actual behavior.
You’re testing that functions delegate correctly.


What Can We do

Don’t follow a pattern just because it looks clean.

Instead:

  • Collapse layers when there’s no meaningful logic to separate
  • Group code by feature, not by type
  • Use vertical slices to keep related code close together
  • Let real behavior and complexity guide your structure

Vertical Slice vs Layered

Layered architecture stacks everything by role:
UI → Logic → Database

Vertical slices cut by feature:
Auth, Orders, Notifications

Each slice contains only what it needs that is input handling, logic, and data.

It reduces file-hopping and helps the code evolve more naturally.


When Layers Still Make Sense

Layered architecture can still work well when:

  • You have meaningful business logic separated from data access
  • The application is stable and layering prevents coupling
  • You’re on a large team with strict role boundaries

But if you're on a small team, building fast, or mostly doing CRUD?

Favor clarity. Not ceremony.


The Takeaway

Layered architecture is a tool, not a rule.

Sometimes, one well-named function is better than splitting logic across three files “because architecture.”

The goal is working software. Not perfect structure.


You Can Check Them Out Too

some cool interesting stuff