Microservices, Micro-frontends, Big Data – These are just some trends in technology in the past decade that caught fire and the fizzled out or will soon fizzle out. These things didn’t fizzle out because they weren’t useful, they fizzled out in the sense that they were so overblown and overused in the beginning and now folks better understand the use cases, which are dramatically less than originally thought.
A wonderful and pragmatic software development principle, YAGNI (Ya ain’t gonna need it), can certainly be applied when thinking about this trend we saw. Now, people are starting to understand that Microservices is something “ya ain’t gonna need”, especially when you compare the value that they provide vs the complexity that they bring. The idea behind YAGNI is not that something isn’t valuable or useful, but that chances are that its overkill for what you actually need. Microservices absolutely have clear use cases and we should recognize and embrace that value. However, we should also recognize that they are overkill for most companies building applications.
What should I use instead?
If you have some suspicions that “ya ain’t gonna need it” when thinking about microservices, the typical alternative approach folks land on is a monolith. During the rise of microservices, monoliths got a pretty bad wrap for some of their weaknesses and they seem to have a permanent stain on them now. I would argue that this stain is completely unfair, and just as there are clear use cases for microservices, there are clear use cases for building a monolith.
What is a monolith, really?
First, lets define what a monolith actually is and what are the common misconceptions are out there. Monolith implies one thing and one thing only – The entire application is deployed as a single application / There is a single point of scale – which is the indeed the entire application. Monolith DOES NOT mean that all of the code is poorly organized and tightly coupled. It does not mean that it cannot have a clear and efficient CICD pipeline. It does not mean that it cannot be deployed several times a day and have tens if not hundreds of engineers working on it. Are a lot of these things common in monoliths authored by inexperienced software engineering teams? YES! Do they have to be? Absolutely NOT.
What advantages am I going to get out of a monolith?
It doesn’t take long on Google to find a plethora of blog posts that compare the strengths and weaknesses of monoliths vs microservices. Arguably, the weaknesses are pretty unfair and assume the monolith is created in the worst way possible every time. Fortunately, the strengths are usually pretty fair:
- Quick to market – Dramatically less complexity means less overhead, leading to lower effort and quicker time to market
- Simple deployment pipelines
- Simpler and easier to manage observability and traceability
- Simpler to debug and triage issues
What is the better approach with a monolith?
Have you heard the somewhat newer term of Modular Monolith? Its really nothing special… It is simply applying good and foundational software development principles to your monolith. This is where its critical to take note of what monolith truly means and ditch the common misconceptions. In fact, modular monolith isn’t anything new and is really just another re-hashing of SOA (service oriented architecture). Just because you are deploying everything together doesn’t mean you can’t have a strong and high focus on modules (aka services) that make up the application. This is the way that everyone SHOULD be building a monolith. That whole idea of bounded contexts that are so important in microservices…. They are extremely important in a monolith as well!
How does a modular monolith really help me? Why is it better?
The benefits of microservices are clear. Its hard to argue with independent services deployed and managed on their own. These services are highly scalable and reliable in a proper cloud native environment. The question is, are you really losing that with a monolith? An even better question is, do you really even need it? In a lot of applications, you may not even need, and even if you do, you may not be that far from getting there if you build your application right. Building loosely coupled services/modules in your monolith helps you prepare for independently scalable services without introducing the complexity and overhead until you actually need it. Lets take a fantasy football application as an example:
Consider that we build a modular monolith application for a new fantasy football application. We put in the time up front to understand our boundaries and bounded contexts to create some smart services/modules. We take the loosely coupled principle seriously and though all of the services use the same database, they use separate schemas and don’t violate cross schema joins to ensure loosely coupled services. Because of our good discipline in development and the use of a monolith, we are quick to market to get the new app out before football season.
Once football season starts, we see during the week that the traffic in the week leading up to the first Sunday is pretty reasonable but we still decide to scale the monolith to ensure good response times. The week goes smooth and the entire application seems to be scaled appropriately. However, noon on Sunday comes and we start to notice a huge spike in traffic and are required to scale the monolith further to keep up. That following Monday, the engineering team gets really curious and digs to find which API’s drove the need to scale the entire monolith and discover that during the week, most of the application API’s were used as user shuffled their teams day to day. However, Sunday received a giant spike of traffic as games started to take place and the head to head matches were underway with the scores API getting hit hard all day Sunday. This knowledge is certainly interested and the team takes note.
At the end of the season, the product team starts preparing for enhancements and changes for the next season. The engineering team makes a very meaningful and strategic proposal: Breaking out the scoring service/module from the monolith to its own deployable service for season 2. Since the team adopted good practices and kept this as a loosely coupled service in the monolith, breaking it out as a separate service was actually quite simple. It got moved to a new project, new build and deployment pipelines and in some new infrastructure in the cloud. Fast forward to the first week, they see the same traffic trends but then, as anticipated, are able to scale the scoring service dramatically while seeing the rest of the monolith humming along at its same pre-weekend scale. This allowed them to get to market quickly and not have to worry about pre-optimizing their services until actually discovering which services would need to scale the most.
Most companies and most applications are not going to find it practical or pragmattic to take on the overhead of microservices when a well architected modular monolith with loosely coupled services/modules will do. This will keep things much more simple and straightforward in a lot of different ways while still allowing for future paths to break out services in a simple manner, when needed. If you think a monolith isn’t the right approach and feel a strong urge to start with microservices out of the gate, challenge yourself and ask if you truly need all of that complexity. Will your application actually have a size that warrants this? Is your development team big enough to warrant this? Will the traffic load and scalability concerns warrant this? If you are answering yes to these questions, organizing around microservices out of the gate may be for you. Otherwise, consider ditching the complexity the bring and go with a modular monolith.
Want to learn more about Viagio? We’d love to hear from you!