Layered Architecture and the Modular Monolith
A layered application separates responsibilities—for example, transport/controller, application service, domain logic, and persistence. The separation is valuable only when dependencies remain intentional; a pile of folders does not automatically create good architecture.
A modular monolith deploys as one application while enforcing boundaries between domains. It can provide strong transaction support, simple local calls, and straightforward debugging. Modules should expose narrow interfaces and own their data access rather than reaching into one another's internal tables.
For an early product, this is often a practical baseline. You can scale stateless instances horizontally and move a module to a separate service later if there is a clear reason such as independent scaling, ownership, deployment, or fault isolation.
- A modular monolith can have clear boundaries without network calls.
- Enforce module ownership and dependency direction.
- Extract services only when the benefits justify distributed-systems costs.
When is extracting a module into a microservice most justified?