I feel like microservices are specifically chosen because they work best with lots of churn. You can throw away the code. You only need to learn only the code in your service. It is an architecture (often) chose not for it's technical merits but rather how it works in high-churn environments.
The point for "microservices" to me is to separate the components of an integrated system to achieve scaling factors independent of other related but not directly coupled parts of the system.
Most systems in my experience don't really benefit from separation of the entire application domain into a set of independent systems. Most use cases don't benefit from decoupling a request/response in a series of asynchronous calls across 20 different APIs.
So, most systems can and should be implemented as a simple abstracted interface inside a single application stack. But then, no one ever gets promoted/hired/funded to build the most optimal solution.
> The same exact results can be yielded by OOP interfaces and implementations, so I unfortunately don't feel this is a valid argument for microservices.
I'm not sure about this, there's so much going on in most software, a lot of the ruin comes from the dependencies around your code, like libraries and frameworks. Let's take web development as an example.
Suppose you need to query the database in some legacy project - well, it doesn't have a framework that supports proper logging of each query/parameter for debugging, it doesn't have any codegen capabilities, it has a wonky connection pool implementation. And yet, if you want to work within the same codebase, you have to use it. What could take a bit of codegen and an hour of work now can take close to a day, all because you're pigeonholed into using what's already there for "consistency".
Suppose instead you now want to have a task queue. Well, instead of RabbitMQ or something of the like being used, instead you have to work with what's present - a bunch of pre-existing abstractions and a DB centric implementation (with arguably poor documentation) that the business requirements have largely outgrown, so now you'll need to hack around the existing code, hope that you break nothing there, all while attempting to create something passable (which may or may not be viable with this approach, depending on the use case).
And doing logging? Well, maybe the team didn't do structured logging or log shipping, so you have to be very frugal with the logs, or spend time setting up Logrotate or an alternative for that monolithic app, just so you can turn on some additional logging and make sure that the eventual rollout actually works.
Well, what about the actual database or maybe tests? Be prepared that the test framework will be somewhat out of date, some of the test utilities won't quite fit what you'll try to do and perhaps your current ORM and DB choices won't really work well with the idea of letting integration tests test actual DB statements and migrations against a DB instance that would be setup for the tests and torn down automatically afterwards (say, a PostgreSQL/MariaDB container somewhere, as opposed to MS SQL or Oracle), so you won't be able to test every schema migration that easily.
You might even run into a situation where you need to run a relatively recent runtime (say JDK 11) but the project is stuck on an older release (JDK 8), whereas migrating everything isn't going to be done for now. So you can't do what you need now, because the libraries don't support your runtime. Worse yet if the monolithic project has dozens of business use cases, whereas the bit of code that's preventing the migration is needed for just one or two of them.
I won't even get into instrumentation and scaling parts of the total solution up or down, or things like configuration, since that'd make this needlessly long.
I think that microservices indeed are a good choice for mitigating some of these issues, by untying your hands - the impact of issues is lessened, to a per-service basis. An individual service might therefore rot and this rot could be addressed separately, without slowing everything else down. Even to the point where the old implementation can be thrown out and rewritten, if that's ever needed.
However, microservices come at a possibly huge operational and complexity cost otherwise, to the point where they might either make the project late, hard to work with, or unfeasible altogether. And it's hard to know which approach will be the best for any given situation. Starting out with monoliths makes sense, because most smaller projects will never need to be split up, but when you need to do that, you will really need to. Modular monoliths (e.g. feature flags for enabled/disabled bits of functionality) can be an intermediate step.
In an ideal world, programming language module systems would be enough. We don't live in a perfect world.
Really true, ownership is a huge part of microservices. I have been on teams that have adopted orphaned services, then been called into meetings to advise on use of a service I am barely aware of.
It is a really easy way to make your employees overwhelmed, but you can always hire someone else to take ownership once they quit.
One idea of Micro services is that you can rewrite the entire service. There are more combinations of libraries, frameworks and languages then there are programmers. Most programmers however has a favourite stack that they are 10x more productive in.
That adds a lot of overhead when employees inherit a pet project