Mastering Separation of Concerns in Node.js
When building simple Node.js applications, it's tempting to write everything inside your routes (`app.get('/users', ...)`). This is often called the "Fat Controller" anti-pattern. As your application grows, this approach becomes unmaintainable. The solution? Layered Architecture.
The Three Pillars
By separating your code into three distinct layers, you create a system that is modular, easy to test, and easy to understand.
1. Controller
The entry point. Handles HTTP requests (req, res), validation, and sends responses. Rule: No business logic here.
2. Service
The brain. Contains business rules, calculations, and coordinates multiple models. Rule: No SQL queries or HTTP objects here.
3. Model
The data layer. Defines schema and interacts directly with the database (SQL/NoSQL). Rule: Just data access.
Dependency Injection (DI)
An advanced but critical concept in this architecture is Dependency Injection. Instead of requiring the Service inside the Controller directly (hard coupling), you pass the Service to the Controller.
This allows you to easily swap the real Service for a "Mock Service" when writing tests, ensuring your unit tests don't accidentally touch the real database.
Pro Tip: Always keep your controllers "skinny". If you see more than 10 lines of code in a controller method, you are likely leaking business logic that belongs in a service.