> if you can’t design a modular monolith, you can’t design a set of microservices.
I somewhat disagree:
Yes, it is possible to design a modular monolith, but thinking about the system in terms of a "minimum viable service" (but keep an eye on "viable", otherwise you can easily get into the "interaction problem") makes it much easier.
This is very similar to how you can write programs with no implicit state in a imperative programming language, but doing this in a pure functional programming language such as Haskell is much easier.
Unless we are planning to deploy them all individually to an expensive serverless platform like Lambda, the coordination challenges and overprovisioning are going to more than outweigh whatever architectural benefit you reap (in human-centred development, micro services are solving an entirely different problem - Conway's Law)
What problem would it solve? They're still part of a larger system ultimately. Sure, smaller codebases with more focused scope can be good for e.g. human individuals and LLMs, but there's multiple ways to achieve that that don't require a network boundary.
Microservices are about separate deployment. Regarding separating the development/maintenance of components, you can achieve that in a monolith by composing it out of corresponding modules/libraries with defined APIs. That’s good practice anyway.
All have its space.
Small team, do monolith or you'll stop moving.
Big teams, be wary of Conway's law, and don't fight it, probably some services will emerge.
In other words, if you can’t design a modular monolith, you can’t design a set of microservices.