Monolith
Simple deployment surface, but boundaries are often accidental unless deliberately enforced.
A monolith can be elegant or chaotic. A microservice system can be well-bounded or painfully distributed. The more useful progression is often monolith, then modular monolith, then microservices only when the boundaries and operational need are both proven.
Many Java teams inherit a single deployable application and feel pressure to split it immediately. But if the internal boundaries are weak, the split just exports confusion into the network. A modular monolith is often the most responsible middle step.
A plain monolith packages everything together, often with one deployable unit and one operational surface. A modular monolith keeps that deployment simplicity but enforces stronger internal module boundaries. Microservices add independent deployment and operational isolation, but they also add distributed systems costs: latency, retries, observability, consistency, contracts, and platform overhead.
The usual healthy path is to build strong internal modules first. If those modules later need independent scaling, release cadence, ownership, or runtime isolation, a microservice split becomes far less risky.
Simple deployment surface, but boundaries are often accidental unless deliberately enforced.
One deployment, strong internal modules, and a much better training ground for future distribution.
Independent deployability and isolation, but with real distributed systems costs that only pay off when the need is real.
| Option | Main strength | Main risk |
|---|---|---|
| Monolith | Operational simplicity | Boundary erosion and tight coupling |
| Modular monolith | Strong internal structure with simple deployment | Requires discipline because the compiler and runtime do not enforce every module rule automatically |
| Microservices | Independent deployment and scaling | Distributed coordination, consistency, and platform complexity |
package org.javaomnibus.ecommerce.orders;
public interface OrderApplicationApi {
OrderSummary place(PlaceOrderCommand command);
OrderSummary find(String orderId);
}
package org.javaomnibus.ecommerce.shipments;
public interface ShipmentApplicationApi {
ShipmentSummary plan(String orderId);
}