DISCLAIMER: I’m not a fan of monoliths per se but I’m against the common idea that monoliths are the absolute evil regardless.
There was a time, and it was less than a decade ago, in which software developers (and architects) were subliminally suggested that the best way to build scalable web applications was to create compact, resource minimal packages (i.e., ASP.NET applications) with no session, fully stateless and using distributed caching tools if some state was strictly necessary.
Those components were monoliths in the sense that they were made of a single codebase, large as appropriate, resulting in a single deployable small module. A monolith, therefore, is not as simple as a stateless function, but is enough to represent a business context.
In addition, security, testing and logging all happen in a single environment. Most database operations remain in the same space and can be easily made transactional. The technology stack is the same across the entire application.
NOTE: I’m not a supporter of the individual developer right to choose the (pet) technology to use to build code. The technology stack is chosen on a per-application (actually, bounded context) basis.
So, what’s objectively problematic with monolithic software?
For sure, it represents a single point of failure. But how really painful is this point? Being the application a single block with tightly connected parts, an issue that arises anywhere may kill the entire application. Really?
Let me go with an example I know very well. We have a monolith made of at least three logically distinct pieces. We didn’t go with a service-friendly (OK, microservices solution) just to keep all in a single place and avoid latency, logging, security and transactional issues. Now suppose an update break one of them, and it happened. In our monolith, though, the other two components kept working blissfully.
In which way it would have been different with microservices? A broken microservices is still a broken microservice. By applying the magical Circuit Breaker pattern all you may possibly get is the UI that autonomously changes to disable the links to the broken piece.
We’re a fairly reactive team and when something breaks, we must intervene and fix quickly—it’s part of our business, and monolith or microservice makes no relevant difference.
Within a monolith, instead, is more likely than in a microservice to create hidden dependencies, especially when the complexity grows over time. Agreed. This is a matter of self-discipline and skills rather than architecture. A modular monolith, written according to the principles of the DDD layered architecture, doesn’t have hidden dependencies by design and each module is the same as a microservice. I dare say that a modular monolith is a microservice application containerized in a single codebase and app service.
Is monolithic software difficult to scale?
Let’s be honest: this is a hard one to answer in general terms. The real question is another: is the application difficult to scale? How do you measure “scale”? And, more importantly, do you need to scale now? Sometimes a simple and relatively cheap increase of database resources does the job. Sometimes not and a complete rearchitecting may be necessary. But, again, it can be as minimalistic as adding a bus and/or a distributed cache somewhere or just a front cache. It doesn’t have to be splitting into a myriad of micro components. Blindly done, it a remedy worse than the disease.
Microservices are network of monoliths. It doesn’t match your definition of microservices? OK, by microservices you mean FaaS and serverless and cloud-native? OK, but allow that it’s a different story and a different paradigm. If so, please, don’t call it microservices.