A monolithic application architecture
To understand a monolithic architecture, let’s take an example of a new banking application. Suppose you are starting a new banking business and you want to develop an application to support the checking and saving account business functions at this new bank. You developed a single application that carries out all banking transaction functions. Now, your business is increasing and you want to offer your customers investment opportunities, so you make necessary enhancements to your application and add features to support investment functions. You made adjustments to the application architecture so that both investment and banking transactions can be supported, which increases some load on the application as well, so you change the size of your application servers and database servers so that the additional load can be handled.
With this successful launch of an investment portfolio, banks now need to offer home loans and auto loans to customers, so you have to make necessary adjustments to the application and add these new features to it, as well as enhance the current architecture. Everything is part of the same application, and it is taking the load of all four business segment users.
These kinds of applications, which are performing more than one function, are considered monolithic applications. Here is a more formal definition of a monolithic application.
An application is considered monolithic if it is responsible to carry out not just a particular task but also completing all the required steps needed for a business function. Usually, in these applications, the user interface and code required to access the data are packaged together and these applications are self-contained.
In our banking application, you can see that the same application is responsible for performing banking, investment, and loan functions, so this is classified as a monolithic application. In fact, a single business function can also be classified as a monolithic application if it is carrying out multiple tasks, such as accepting banking applications, opening a bank account, creating customers, generating bank statements, funding bank accounts, and managing credits and debits for accounts.
Now that you have an understanding of what a monolithic application is, let’s try to understand what the problems are with being monolithic. Let’s take an example, In 2020–2021, due to the COVID-19 pandemic, the US government cut down the interest rates to almost zero, which had an impact on the mortgage rates, and homeowners started refinancing their homes due to these lower mortgage rates. Subsequently, banks started getting a lot more home loan applications than at any time in history. To handle such traffic demand, we would need to scale up our application, but scaling just the home loan part of our application is not possible because our entire business functions are deployed as a single monolithic application. Therefore, if you are scaling the home loan segment of an application, you are scaling the entire application, and that’s not a very good usage of our resources.
Figure 2.1 – An example of my bank’s monolithic application architecture
Another impact of the pandemic was that a lot of small businesses faced challenges and needed money to keep running their payroll. Therefore, the US government launched a specific Paycheck Protection Program (PPP) through which a business could apply for a loan to keep their employees on the payroll. This was a new program for small business banking customers, so banks immediately needed to make a change to their application to support these loan applications. However, making sudden changes isn’t easy for our monolithic application, due to the large code base supporting multiple business functions, and making these kinds of rapid changes would risk the stability of the application. Also, the deployment of this change would cause a system outage for investment, auto, and home loan customers who have nothing to do with PPP. So, here, we see multiple issues due to the monolithic nature of our banking application, one being application stability and another one being an outage in the non-relevant business sections.
The following are some of the disadvantages of having a monolithic architecture:
- The size of the code base is big, and it takes time for developers and test engineers to understand the code and business functionality. Code complexity also increases over time.
- Due to the large code base size, code compile time is higher and developers spend a lot of time building source code even for small changes they are making, which indirectly reduces productivity.
- Application components are tightly coupled with each other and, usually, splitting those dependencies can be tough, and sometimes, those dependencies are circular.
- Application code is not very reusable, as everything is part of the same application.
- Monolithic applications can also be difficult to scale when different modules have conflicting resource requirements – for example, one module needs high CPU demand while another module needs to do a lot of disk operations, so you have to scale both, as you have a single application.
- Monolithic applications cause reliability issues in an application because a memory leak in one part of it can bring it down entirely.
- Monolithic applications cause downtime to an entire application, so if you are making a change to one part of it as a single deployment unit, it will be deployed altogether, causing downtime to other modules.
- Monolithic applications are difficult to test, as making a change to one module can cause issues in another module, as everything is part of the same code base, and at times, you don’t know the ripple effects of a change. So, testing these applications is difficult and requires quality engineers to test the entire application, instead of just that particular change.
- Monolithic applications are usually big and you are tied to a single technology stack, as rewriting these applications isn’t easy, due to the large code base and complexity involved.
- Due to the large size of an application, deployment time and application startup time is large, and automating testing is not easy and feasible.
- Managing changes with a monolithic application is difficult, as a lot of coordination is needed between teams so that the changes do not conflict, and one team/developer doesn’t override the changes of another.
Now that we understand why it is challenging to have a monolithic application, let’s go ahead and see how we can solve these challenges using a microservices architecture.