Understand the pros and cons of microservices and monolithic architectures and how they impact developer productivity and quality of software.
Today, where “software is eating the world” and every company is becoming a tech company, a business is only as strong as its technology.
How your company approaches software development can have an impact on how well you serve your customers, how efficient your employees are, and how agile your organization is.
For this reason, it’s of vital importance to make the right architectural choices early in the software development life cycle, as these decisions can have a lasting impact down the road.
There are endless ways to architect a software application that might be suitable for your business. However, the most popular architectures tend to fall into one of two categories: monolithic or microservices.
Understanding these different approaches is one of the keys to building and maintaining quality software products efficiently.
Let’s review each approach and see how they impact developer productivity and the quality of the software being built.
What is a Monolithic Architecture?
The word “monolith” was originally used by Ancient Greeks to describe a single, mountain-sized block of stone. Though the word is used more broadly today, the idea remains the same – a monolithic software product is a single, indivisible unit that will generally grow to a large size.
In a typical client-server architecture, a monolithic product lives on the server, where it handles HTTP requests, executes logic, and interacts with the database. It contains a single executable that performs all of the server-side functions for an application.
For example, to update the behavior of a product page, a developer would access the same code base as they would to add a new customer service feature, or to change the functionality of a promotional carousel. In a monolith, everything is managed and served from the same place. The size and simplicity of monolithic software products are both their strengths and their weaknesses.
Many modern websites and applications began with monolithic architectures. Amazon.com, for example, was a monolith back in 2001. While the site was built with a two-tier architecture, it was extremely tightly-coupled and behaved like one large monolith.
How Monolithic Architectures Help Productivity
The primary benefit of a monolithic application is the simplicity of its infrastructure, which can make it faster to deploy and scale.
To deploy a monolithic application, only one file or directory has to be handled. This makes deployment fairly straightforward. Since the entire application’s codebase is in one place, only one environment has to be configured to build and deploy the software. In most cases, this means less time spent figuring out how to deploy and deliver your application to your end users.
Monoliths are a convenient way to start a new software project with minimal concern for setup on a server or cloud environment. While the complexity may grow over time, appropriate management of the code base can help maintain productivity over the lifetime of a monolithic application.
How Monolithic Architectures Hurt Productivity
Monolithic applications tend to become more cumbersome over time. Without close attention to how code is being written and maintained, a monolith can become dangerously brittle. This magnifies each bump in the road for your business as new challenges and demands arise for your products.
On the development side, monoliths can hinder agility. As mentioned prior, monolithic applications are very tightly coupled and can become a complex web of code as the product evolves. Thus, it can be extremely difficult for developers to manage over time.
“An evolving system increases its complexity unless work is done to reduce it.” – Meir Lehman
Also, it is common for each developer to understand only part of a monolith, meaning very few developers can explain the entirety of the application. Since monoliths must be developed and deployed as one unit, it can be difficult to break up development efforts into independent teams. Each code change must be carefully coordinated, which slows down development.
This situation can be intimidating to new and seasoned developers alike, who would prefer to not have to wrangle a massive code base that has evolved over the years. As a result, more time is spent finding the correct line of code, and making sure it doesn’t have side effects. Thus, less time is spent writing new features that actually improve the product.
Developers who are accustomed to modern development environments may be disappointed with the rigidity of monoliths, which are generally confined to their original technology stack. Adopting new technology in a monolith can mean rewriting the whole application, which is a costly and time-intensive endeavor that doesn’t always lead to forward progress.
Monoliths are common because they are simpler to begin building than their alternative, microservices. However, this simplicity may be paid for later if the application is revealed to be fragile to growth and change, and the convenience of a simple deployment procedure comes with the cost of technical debt.
The Bottom Line on Monolithic Architectures
It isn’t a bad idea to build a monolithic application, but it is a bad idea to let a monolithic application grow out of control.
Monoliths are agile at the start, allowing a business to get a product off the ground quickly. However, more consideration should be given to the architecture of the application when more time is being spent fixing existing code rather than building new features.
After a certain point, you should consider whether a microservices architecture might be more appropriate.
What is a Microservices Architecture?
While a monolith is a single, large unit, a microservice architecture uses small, modular units of code that can be deployed independently of the rest of a product’s components.
There are many ways to build a microservices architecture, but most of them share some fundamental characteristics:
- Microservices components are modular, so each service can be built, updated, and deployed independently of any other code.
- Each microservice is only responsible for a specific purpose or task.
- Microservices receive requests, process them, and send a response.
- Microservices abstract away implementation details, only exposing a (hopefully) well-documented interface, so APIs can be consumed in a consistent way, regardless of how exactly the service is built.
Netflix is the prime example of an application that uses microservices.
Netflix’s original product – a website that allowed you to select DVDs to be delivered to your mailbox – began as a monolithic application that was built and managed with a traditional development model by a single team of over 100 engineers.
As the company transitioned to a product that delivers streaming content to millions of viewers all over the world 24 hours a day, Netflix evolved to a microservices architecture that facilitates receiving content from various sources, getting it into its systems, processing it, and distributing it to users seamlessly.
Each day, Netflix’s API receives hundreds of millions of calls, which are passed around between microservices in order to accomplish a task. When you click the play button on a movie, you might be triggering a chain of five API calls which keep track of playback, collect content for the user interface, manage streaming, and more.
Netflix also leverages serverless architectures, which fit well with microservices, to encode this content, backup files, secure their assets, and monitor their IT environment. See the video below for more on how Netflix uses serverless.
How Microservices Help Productivity
Microservices allow developers to work quickly and freely, and focus on the specific product function that they’re working on.
Compartmentalizing code into cleaner, smaller units makes it easier for new team members to understand what the code does in a particular microservice, and hit the ground running. The developer does not need to parse the implementation of another microservice, but just be aware of its purpose and interface. This abstraction minimizes the size of the codebase a developer would need to store in his or her working memory.
Since microservices are isolated from each other, they can be deployed separately. This means when a change is made to only one service, that service can be redeployed alone instead of alongside the entire application. Less coordination between developers is needed to make edits to the code base, and therefore products can be improved and delivered to customers more quickly.
Cloud platforms like Amazon Web Services also make it easy to serve, reuse, and scale microservices. Serverless offerings like AWS Lambda helps developers scale their microservices horizontally, which can be difficult for an application that wasn’t designed for it.
Separate microservices are less susceptible to the unexpected side effects of running code because these side effects are minimized when passed between services, since only the desired information is communicated. This separation also means that if one microservice fails, others will continue to work (though interdependencies can still be problematic if not handled proactively).
Since microservices are small and flexible, they don’t require a long-term commitment to a single technology stack. Developers can typically select their preferred programming languages, databases, and other tools if they are the best solution to the problem to be solved.
And with infrastructure as code, where you can deploy and configure your infrastructure by writing code, you can more easily define and manage how microservices interact with each other, further enhancing productivity.
How Microservices Hurt Productivity
While microservices architectures are generally more agile than monoliths, the complexity introduced by microservices provides its own set of challenges.
Since microservices require combining multiple pieces of an application – all of which might be managed by different teams of developers, DevOps, and product managers – the organizational dynamics must undergo a big change. Teams need to be able to handle the gamut of decisions, planning, and implementation that entail the software development life cycle, and this must occur at a high level across multiple teams.
Similarly, each team must be responsible for their own operations, configuration, deployment, and monitoring, which increases overall effort as compared to a monolithic environment. Each microservice will require its own infrastructure, dedicated continuous integration and delivery pipeline, and monitoring processes. Across all developers and teams involved, this can result in wasted effort and time.
As a developer, making changes to your code can be more of a hassle as well. Because you have less control over the other microservices that you do not maintain, another microservice may need to be changed to support something you are doing, which can add time to the overall development process. In a monolith, you could change the relevant code yourself. But with microservices, you might have to contact other developers and teams to make the change for you, especially if the microservice is written using a language and stack you are unfamiliar with. This communication can be cumbersome without proper processes in place. It will also require the new functionality to not affect the existing functionality, as there could be other microservices that rely on the existing functionality. Versioning becomes an absolute necessity with microservices.
Though microservices are separate, their interdependencies can be a liability if not properly managed. Because microservices may communicate over a network, there is more of a chance that something will go wrong, such as a lost HTTP request, as compared to an API call that a monolith might make.
The agility gained by having smaller, separate services can be lost in the complexity of the architecture. For this reason, it’s important to put a thorough amount of thought into a microservices architecture before executing it.
The Bottom Line on Microservices
A microservices approach offers an agile development experience for developers and potentially improved software products for end users. Ideally, this translates into a higher level of efficiency, increased flexibility, reduced maintenance costs, reduced technical debt issues, and more revenue for the business.
However, it is important to remember that adopting a microservice architecture isn’t something that will magically solve the problems that come with a complex monolithic code base. While more modular code will make it easier to maintain, a microservices architecture has to be implemented carefully and correctly.
Making a Choice
You should choose the software architecture that matches your software development needs and developer culture.
A monolithic architecture might be the right choice for your business if you need to get your application built quickly. In general, monolithic architectures require minimal upfront investment in figuring out integrations, dependencies, automation, and other environmental factors.
Microservices can be a great solution if a monolith has gotten too big or complicated, but they can also be a good starting point. You may want to take advantage of a microservice architecture from the outset to ensure flexibility in your products.
Though microservices are often viewed as a fix for a monolith gone wrong, a poorly-implemented microservice architecture can suffer all of the shortcomings of a monolith, but with the added complexity of managing these separate, independent services. Designing a microservices architecture should be handled with care by experienced hands, and shouldn’t be employed just because it’s a new, hot trend.
Keep in mind that “monolithic” and “microservice” are high-level terms that encapsulate a potentially infinite number of architectures. You should experiment with your exact implementation to determine what matches your business’s capabilities while maintaining internal productivity.
If you take the time to find what architecture works best for you right now, it could save you months or even years of time, money, and stress down the road.
Like this post? It likes you too. 🙂 Please share it using the share buttons to the left. Then join our mailing list below, follow us on Twitter @thorntech, and join our Facebook page for future updates.