Discussion led by Ayush Gupta
I will start off with quoting this line from the chapter which I think really resonates with the idea of design principles we are discussing:
“When domain logic is embedded in other layers, it becomes hard to see, test, and evolve.”
One bit I really liked was the distinction between Application and Domain layers. The app layer doesn’t do business logic; it orchestrates it. That alone can clean up so much of the mess I’ve seen in bloated service classes.
In the “Smart UI Anti-Pattern” section, Eric describes it as the go-to for small projects, and honestly, it works until it doesn’t. It gets stuff done quickly, but you pay for that speed later in pain: logic that’s impossible to reuse, test, or reason about. This line from the chapter sums it up:
“A system with a Smart UI and a rich domain will never be able to exploit that richness.”
My primary takeaway from this chapter: if we don’t intentionally isolate the domain early on, everything bleeds together, and we miss the objective of domain-driven design. Layering is more than simply code organization; it’s a sign of respect for the model.
Challenge for the Reader
- How are you managing boundaries between app and domain layers — especially in full-stack codebases?
- Have you caught yourself treating the “service class” as a catch-all? What made you realize it?
Thanks for kicking this off, Ayush — I really liked how you phrased this: "Layering is more than simply code organization; it's a sign of respect for the model." That hit home.
I also appreciated the Application vs. Domain layer distinction. It reminded me how tempting it is to treat "service" classes as catch-alls and how quietly dangerous that becomes. The idea that the app layer doesn't do business logic but orchestrates it feels so clarifying once you hear it said aloud.
The "Smart UI" anti-pattern felt familiar too. I've worked on codebases where domain logic hid in React components or API handlers, and it worked fine until it didn't. Reuse and testing became almost impossible without gutting half the flow.
On your question: in a full-stack setting, it's definitely tricky. One thing that's helped me is enforcing clear DTO boundaries and treating anything UI-facing as if it were a third-party client. The moment you start drawing boundaries as if the domain were a separate service (even if it isn't), better decisions tend to follow.