It’s becoming common knowledge that companies want to put their software in consumers’ hands as soon as possible. This is the reason development teams never have enough time to launch new software or add new features to existing applications. Managers started using different frameworks for managing software development in order to maximize the productivity and efficiency of their development teams. Plenty of developers already use Scrum in their everyday work while others at least heard about it or use similar Agile frameworks. Since this is not an article on Agile we won’t be going into the details.
The way we work also makes an impact on the architecture of the software we build. There’s quite a popular motto in startups: Move fast and break things, except that we want to move fast and not break anything while having bug-free software with great quality of the code. All jokes aside, it’s hard to move fast when you have 15 developers working on 15 different features of the same backend application at the same time. Those applications, built as a single unit, are often called monoliths.
A typical monolith has three parts: a database, a user interface, and a server-side application. Also, the word monolith is sometimes used to describe just the server-side application that is built as a single unit while that type of software architecture is called monolithic architecture. The majority of applications have been initially developed as monoliths, just think about all those MVPs and POCs that small teams built over time. Some of them became successful applications and monolithic architecture was no longer a suitable option for them.
Imagine the scenario where another greenfield project started 1 year ago and the new application has just been released. In other words, the maintenance of the software is now a very important task. However, the business wants to add new features to attract more users. In the meantime, existing users reported a few bugs. The development team is now expected to maintain existing features and add new features at the same time. Usually, old team members work on bug fixing and maintenance until new team members have a good understanding of the codebase so they can help. At the same time, new hires are exploring the codebase and starting with the implementation of new features. It isn’t a surprising fact that a monolith can easily become hard to maintain. For instance, it’s not hard to fall in a trap of highly coupled code when new developers are working on a huge codebase without an appropriate introduction.
Sometimes, we all write dirty code to get the job done and dream about refactoring in the future which unfortunately won’t happen because there will probably be no time. That code can be dangerous when somebody starts to use it as an example of the solution for a particular problem. Adding new features also results in adding more tests. More unit and integration tests will make deployment pipelines slower, hence adding trivial features or a bug fix becomes a very time-consuming task. Compromising the quality of software by removing tests just to speed up the deployment process is not an option. All of the above strongly affects our everyday work and development experience. Business is not happy when development is slow and developers are not happy when slow development is a result of the poor codebase. There is no single reason for a situation like this, but it’s clear that monolithic architecture has some drawbacks in this case.
The user reported a bug in our system which resulted in another ticket with an accurate description of what’s happening and how to reproduce it. The ticket isn’t classified as a top priority so nobody picked it up immediately but it’s somewhere on the board and it’s visible in the current sprint. The ticket will remain on the board in the next sprint and it looks like it won’t reach the Done column anytime soon. The development team planned the sprint and all of the most important tickets are assigned to developers while the rest of them are in the To do column and somebody should pick them up when they finish work on the top priority tickets. Nobody is picking up an unassigned bug ticket because there is no clear ownership of features, modules or software in general. In situations like this, team members can easily start to look at features like short term projects in sprint represented with text on the ticket. In reality, the feature is an improvement to the software which gives extra value to the user. It’s part of our product and we should take ownership of it. Every team member should have ownership of at least one part of the product while the team owns the product as a whole. Ownership implies responsibility, the bug would be fixed much sooner if there was clear ownership defined.
It’s hard to define ownership when everyone is working on the same server-side application. There is no clear distinction between different parts of the platform and everyone is editing everything. It reminds me of diffusion of responsibility, a sociopsychological phenomenon where a person is less likely to take responsibility when others are present. Everyone thinks that somebody else will fix the bug.
The stories above are outlining a few disadvantages of the monolithic architecture. However, it doesn’t mean that we have to completely avoid monolithic architecture and immediately start with a different software architecture like microservices. It’s easier to start with a monolith, solve the problem and switch to microservices later when the software and the team are ready for the change. Switching from a monolithic architecture to microservices is not a trivial task but it can be extremely beneficial for the business.