History and context
Why monoliths gained a bad reputation
The failure mode is not one deployment. It is unrestricted dependency.
Controller
-> Shared Service
-> Another Shared Service
-> Repository
-> Any TableWhat microservices buy and what they cost
They buy
- Independent deployment
- Independent scaling
- Harder data boundaries
- Team autonomy
They cost
- Network failure modes
- Eventual consistency
- Distributed tracing
- Message delivery concerns
- More infrastructure
The modular monolith middle path
Business-first solution structure
src/
Platform.Api/
Modules/
Catalog/
Catalog.Domain/
Catalog.Application/
Catalog.Infrastructure/
Orders/
Orders.Domain/
Orders.Application/
Orders.Infrastructure/
Pricing/
Pricing.Domain/
Pricing.Application/
Pricing.Infrastructure/Keep important rules close to the domain
public sealed class Order
{
public OrderStatus Status { get; private set; }
public void Confirm()
{
if (Status != OrderStatus.Pending)
throw new InvalidOperationException(
$"Cannot confirm order in {Status} state.");
Status = OrderStatus.Confirmed;
}
}Use internal events before network services
public sealed record OrderConfirmed(
long OrderId,
int ShopId,
IReadOnlyCollection<OrderConfirmedLine> Lines);An in-process event can decouple modules conceptually. It does not need a broker until asynchronous delivery or deployment independence becomes a real requirement.
Database ownership still matters
catalog.product
catalog.category
sales.order
sales.order_line
pricing.sales_offer
pricing.sales_offer_targetSharing one PostgreSQL server is not permission to ignore ownership. Cross-module updates should go through contracts, because database coupling is often harder to remove than code coupling.
When should a module become a service?
Strong reasons include independent scaling, reliability isolation, separate team ownership, a different technology requirement, or regulatory separation. "We may become large" is not a sufficient engineering requirement.
Business value and practical considerations
Pros
- Simple deployment
- Easier transactions
- Low infrastructure overhead
- Clear domain boundaries
- Future extraction path
Considerations
- Boundary discipline is social + technical
- One deployment remains shared
- Independent scaling is limited
- Database access must be governed
References
Primary documentation used for terminology and current platform guidance: