Software architectures should not be pre-determined. The big ball of mud and the monolith architectural styles are definitively out of fashion, and for good reason. Microservices are highly popular today; there are many other well-known and proven architectures though. In the book Building Evolutionary Architectures by Ford et. al., the strengths and weaknesses of layered architectures, modular monoliths, microkernels, event-driven architectures, brokers, mediators, service-oriented architecture (SOA), “serverless” and the current favorite, microservices, are cleanly articulated. Computer scientist Ralph Johnson, one of the co-authors of the landmark book Design Patterns: Elements of Reusable Object-Oriented Software, now famously stated "Architecture is about the important stuff. Whatever that is."
Software architectures are defined by their “-ilities.” The obvious ones come to mind, like usability, scalability, portability, maintainability, durability, and adaptability. Then there are the less-known ones that are becoming disproportionately dominate in an era of persistent cyber threat, including traceability, provability, survivability and one that doesn't actually have an -ility ending at all, standards compliance. All well-known architectural patterns are characterized by their –ilities, and each will score differently depending upon the set of -ilities that a solution looks to emphasize. For example, most professionals will argue that the maintainability of a big ball of mud is far worse than the maintainability of a service-oriented architecture.
Microservice architecture is the most popular presently, and it is often coupled with the Cloud Native descriptor. Cloud Native is not the first, and not the last unfortunately, horrible term crafted by software engineers to inaccurately describe something. Very few of the Cloud Native frameworks are restricted to running in the cloud, and there are hundreds of easily accessible examples of Cloud Native Computing Foundation (CNCF) projects running locally and even in embedded environments. The Cloud Native moniker has become a bit of a marketing term, losing a shared and succinct meaning that makes the descriptor more problematic than valuable. Let’s just focus on microservice and forgo the Cloud Native descriptor here as we ponder this question:
Is a microservice architecture the right choice for every business problem?
For each microservice architecture there is likely a monolith, a serverless, and other architectural options available to realize the solution. The heterogeneity of software cannot and should not be reduced to “if it isn’t a microservice architecture, then it isn’t of value.” Yet, this attitude does exist, it is dangerous, and reducing all software problems to a singular architectural quantum can foil the best of intentions.
Predetermining software architecture is dangerous. All architectures do not and cannot equally maximize each of the –ilities. For example, layered architectures most often failed because the notion of a “domain” was nascent, so adding a new domain feature meant touching multiple layers. It meant that changing the way an order fulfillment routine works meant all layers had to be adjusted. The result: layered architectures typically failed to support evolvability.
In contrast, microservices pivoted by design to focus on the domain construct, pushing the underlying technical implementation to the background behind a highly decoupled architecture. This is a powerful metaphor, so long as the cardinal rule isn’t violated: no service must ever know or understand or behave in a way that assumes an implementation detail of another service. The theory goes, you can rip and replace one service with another service. Returning to Ford et. al., “The main goals of microservices are isolation of domains via physical bounded context and emphasis on understanding the problem domain.”
The domain-centric focus gives microservices amazing evolvability, but in practice the idea of “share nothing” becomes difficult for many teams. It’s poor practice to spin up a database within a container for obvious reasons, and too often teams are tempted to share a database schema between microservices. Sometimes teams fail to recognize they are making assumptions that tears at the architectural fabric, and in the worst-case scenario some teams are just plain sloppy. Whatever the reason, once the share-nothing principles that give microservices their power are violated evolvability becomes brittle. Unintentional coupling like this does occur, and it erodes the benefits of this architectural style. From tooling automation to frameworks, sometimes stretching back into the CI/CD pipeline itself, entanglement is a very real risk that must be managed by the development team, not just the software architect(s).
Looking beyond unintentional coupling, there is an architectural characteristic where microservices are often a poor architectural choice, transactionality. Service-based architectures offer a larger service granularity and naturally gravitate toward the shared database schema that many teams introduce anyways into their microservice architecture. Service-based architectures integrate a service bus that eases the burden of adding or changing out a dependency service, and work exceptionally well for modernizing decaying software solutions spanning the whole enterprise architecture.
Ultimately, architecture is about selecting the best worst design because for every set of –ilities where an architectural design shows strength, there is another set of –ilities that are far from optimal. As the cyber threat environment continues to evolve and become more dire, we see several –ilities commonly associated with cyber resilience that can no longer be compromised, especially traceability, and that is particularly challenging in large-scale microservice ecosystems.
In an era of software modernization, the microservice is the gold standard, but it should never be predetermined. It can be a risky architecture to adopt when the development team fails to fully appreciate the solution domain given that architectural quanta of the style is predicated upon a clear understanding of that domain. Remember, there is nothing wrong with considering and consciously choosing another architectural style when the underlying strengths of microservice architectures fail to align to solution goals. There is no silver bullet when it comes to software architecture!