Microservices were popularized by companies with thousands of engineers who needed teams to deploy independently without stepping on each other. The architecture solved their coordination problem brilliantly. Then the pattern trickled down to five-person startups, where it solves nothing and costs everything.
What the split actually costs
Every service boundary you draw converts function calls into network calls. That trade buys independent deployment and scaling, and it charges for them with distributed transactions, versioned internal APIs, service discovery, and debugging sessions that span six logs instead of one stack trace. Operational overhead that a platform team absorbs at a large company lands directly on feature developers at a small one.
The monolith, done properly
The honest alternative to microservices is not spaghetti; it is a modular monolith:
- Organized by business domain, orders, billing, accounts, rather than by technical layer.
- Modules communicate through explicit interfaces, never by reaching into each other's tables.
- One deployable unit, one database transaction model, one place to debug.
Module boundaries maintained with discipline become service boundaries later, if later ever comes, and the migration is tractable precisely because the seams already exist.
Real signals that it is time to split
Split when teams genuinely block each other's deploys despite good module hygiene, when one component's scaling profile is wildly different from the rest, or when a subsystem needs a different runtime or risk posture. Those are concrete, observable pressures. "We might need to scale someday" is not; scale problems are good problems, and you will know vastly more about your system when they arrive.
Architecture is a means of managing change, not a badge. The right amount of distribution is the least amount that solves a problem you can name.