The reason your monolith is a mess is because your organization has low standards on code quality and doesn't value it. It is not willing to invest in it, and probably your department didn't acquire the skills and habits to produce clean code in cheap manner. The developers who are used to good code usually leave you out of frustration. No one likes to be unproductive, especially productive people.
> We need to convert to microservices.
Sounds like a cool shiny new approach enabling better scaling and organization.
> We need to refactor this mess.
Sounds like complaining, why is it a mess anyways?
These two things may essentially be doing the same thing, organizing/breaking up the code logically, one just might sound more appealing to management.
“grug wonder why big brain take hardest problem, factoring system correctly, and introduce network call too”
I agree to split into services where “you’r have to do that anyway”.
But adding services where part A of the monolith needs to use part B where a library would do the job seems odd.
If you are trying to solve a specific scaling issue, then sure, but this is rare.
The schema and generated classes could be a shared common library that different teams can work on (maybe with some architecture obersight)
Or if using schema-less each library “knows” it’s own json formats
Then you get nice things like atomic transactions across multiple “services”. You also have no network concerns.
You can pull out microservices for things that need special attention. Such as a spikey-load service that might need to run as a lambda.
Version management is a solved problem. Use your languages package manager and semantic versions.
I concede you need to stick to one language. Ish. You have C FFIs. A .NET app could reference a dll written in C++ or Rust. But yeah not as flexible as services. Although there are inbetween things like RPC.
So now you have in practice is a distributed monolith, with brittle, ad-hoc dependencies between services. A symptom is that most features require touching many MS.
It's much easier to start with a monolith and refactor it into microservices later than it is to refactor microservices written in different languages by different teams into a single codebase.
You could, of course, create this as a service. And then make possibly hundreds of calls to this service to generate a single web page.
Or, you can provide a library that does this, and the calls are cheap, reliable, and predictable.
Of course, if it is a service, the caller would locally the cache the information needed to make all the calls, do a batch call to the service, and then backfill in all the links. This then precludes generating and sending the page as you go, and creates the possibility for an explosion in complexity if a simple change in requirements that causes the arguments for the URL generation to be dependent on another service/library call.
Not everything should be a service call.
If you build a car and send each team off to find the best parts in isolation and screw them together, you don't have the best car, you likely have something that doesn't even drive, because the parts don't fit. The performance of a system is in the interaction of its parts, not the sum of the performance of its parts taken individually.
Teams can never operate independently because it only ever makes sense to improve a part if it improves the functioning of the entire system. The whole problem with the microservices approach it that it optimizes the wrong thing.
It's absolutely necessary for very large organizations though. The alternative of trying to centrally plan the IT operations of an organization of, say, 500,000, gets to be quickly intractable.
Groups try to do it with frameworks like SAFe and while that may help a little bit, in the end you need to treat different parts of the organization as individual silos that are able to control and execute on their specific mission set within the wider org. Otherwise the complexity of the problem set they're dealing with makes it impossible to do anything without breaking other systems or teams.
I think serverless is fantastic on the other hand[1]. I had a web application where I was parsing shapefiles to then import them into SQL Server. These files could be massive and take longer to process than they took to upload. As a result I figured that it might make more sense to create a serverless function in Azure to parse them once they were uploaded to blob storage. This was very easy to implement and transparent. If you are using something like Azure and want efficient ways to process your data without doing it all in your monolithic application and blocking your users, or creating a thread in the background which makes me a little uncomfortable, then serverless is a godsend.
I think Microservice architecture if I had to pin where it might make sense would be for APIs. I would then emphasize on versioning each microservice API. If you do a microservice architecture for APIs you can update parts of your API without taking the whole beast down (unless you use something like Erlang or slots in the case of Azure Web Apps, where it forwards new requests to new slot). I think this might be a reasonable use case for microservices. For a normal website though, I think monolithic with some serverless helper functions (if needed) is probably good enough otherwise.
[1] Note: Let's not confuse microservices for serverless, because it's not necessarily the same thing, although some people use serverless to achieve the microservice architecture, serverless functions can do so much more!
Someone with a monolith that embeds the database could claim those who use MySQL failed to achieve modular monolithic.
For some reason, I feel this is somewhat of a scapegoat and fails in practice. But I don't have enough experience.