What It Actually Means
Somebody submits a form. The controller takes what was sent, checks it is valid, asks the rest of the system to do the work, and decides what the user sees next. It coordinates rather than doing the work itself.
The Distinction That Matters
A controller should be thin. It handles the request and delegates the actual business rules elsewhere.
The common failure, well known enough to have a name, is the fat controller: business logic written directly into the request handler because that was the quickest place to put it.
Why that costs you money is straightforward. Logic living in a controller is attached to one specific way of arriving at it. When the same rule is needed elsewhere, from a scheduled job, an import, a mobile application or an API, it cannot be reused. It gets copied.
Now the same rule exists twice, and the two versions diverge the first time one is updated and the other is not. That produces the most frustrating category of bug: the system behaves correctly through one route and incorrectly through another, and nobody can see why because both appear to work.
Why You Might Notice
You will not read a controller. You may see the consequence.
The same operation behaves differently depending on how it is done. Adding a customer through the interface applies a rule that the bulk import does not. Cancelling through the admin screen sends an email; cancelling through the API does not.
That symptom nearly always means the rule was written where the request arrived rather than in a shared place. It is worth reporting when you see it, because it is a structural signal rather than an isolated bug, and fixing the underlying cause prevents a category of future problems.
What To Ask
- Is this rule applied everywhere, or only through the interface? Particularly relevant when a system has an API or imports.
- If we add a mobile app later, would the rules still apply? A good answer means the logic lives somewhere reusable.
- Why does this behave differently through the two routes? The question that surfaces duplication.
The Practical Framing
This is not something to specify. It is something the symptoms of are worth recognising.
A system where the same operation behaves consistently regardless of how it is triggered is one where the logic lives in a sensible place. One where behaviour depends on the route taken has rules scattered across request handlers, and every future integration will need them reimplemented and will get some of them slightly wrong.
That is ordinary technical debt, and it is the kind worth mentioning to a supplier, because it is genuinely cheaper to address early than to keep working around.
More terms are in the glossary.