God I hate modern web sometimes
God I hate modern web sometimes
Seems more a system design failure to me.
But why choose, just do all three at the same time! Actually you don't even have to choose, it will naturally happen when transitions are never fully completed... So before you know it you're stuck with a partially integrated legacy monolith which talks to a legion of half-baked microservices and emits events processed by arcane workflow engines orchestrating lambda execution.
First build the thing that works, and only if it's really necessary, split it up in separate (networked) parts. You won't have to deal with unreliable network communication, or coordinate on a breaking API change with several teams when a simple search/replace on several function definitions and calls suffices.
For example, if you utilize asynchronous queues everywhere, instead of something like a shared-memory mutex, it's relatively straightforward to turn that into some kind of networked queue system if you need to. Pretty much every language has a decent enough queue implementation available.
Functions and handlers should not care where data comes from, just that they have data, and a queue is the abstraction of that very idea. Yes, you lose atomicity but atomicity is generally slow and more problematic has a high amount of coupling.
I don’t agree that being out of sync is the main downside of microservices; the main downside is that anything hitting the network is terrible. Latency is high, computers crash, you have to pay a cost of serialization and deserialization, libraries can be inconsistent, and zombie processes that screw up queues. Having stuff in-process being non-synchronized wouldn’t even hit my top five.
ETA:
I should be clear; obviously there are times where you want or need synchronization, and in those cases you should use some kind of synchronization mechanism, like a mutex (or mutex-backed store e.g. ConcurrentHashMap) for in-process stuff or a SQL DB for distributed stuff, but I fundamentally disagree with the idea that this should be the default, and if you design your application around the idea of data flow, then explicit synchronization is the exception.
The more you have globally interconnected and out of sync states, the less predictable your system is.
The solution is to be as hierarchical, as tightly scoped, as functional and as transactional as you can.
That's how you tackle complexity and create intelligent systems: https://benoitessiambre.com/entropy.html
You can make asynchronous code predictable if you utilize something like TLA+, or treat the code as a protocol system.
Microservices is exactly the same concept except in the micro economy of a single organization. Each team is like Microsoft, OpenAI, Google, etc. You don't coordinate with them, you deal with what they give you. Like it or not.
I expect the earlier statement confused microservices with a multi-process application.