Your company has arrived! You might be six-months or six-years old, but you have broken through. Website visits and app usage is pushing your servers to the breaking point. You want to add new features while maintaining 100% uptime, but each time you deploy code you have to bring the servers down to make sure the latest release is live. Meanwhile, every time someone touches the code base, something breaks in an unrelated part of the system. To top it all off, the user authentication system is eating the bulk of system resources, forcing deployment of multiple instances and jacking up your monthly spend.
Sound familiar? It’s an all too typical scenario for companies young and old, as well as internal and external facing applications. And it can all be traced back to a monolith…
My God, It’s Full of Dependencies!
When development teams start to build out a web or mobile application, they often move forward by writing all the business logic, data access logic, and front-end code into a single monolithic application. This isn’t necessarily an issue of bad architecture, as a well designed application can still be a monolith. Monoliths can be 100% homegrown, or they can be an off-the-shelf application like WordPress.
As our story above shows, a monolith introduces a number of potential problems. Having a single code base for your application makes it difficult to introduce incremental changes, since you have to deploy everything all at once. Server management also becomes a major issue since you may have to deploy multiple versions of the application to handle an inefficient feature. You are limited in your ability to reuse code for a feature, such as user login, in multiple applications since the code is tightly coupled with your initial monolith. Monoliths can also grow increasingly fragile as they get larger, since a single bug in your codebase can bring everything to a screeching halt.
Having said all that, a monolith is usually the best way to start a new application, since it allows the team to move quickly from idea to production. Optimizing an application before you know where the problems lie — premature optimization — can result in much lengthier development cycles, burning precious time and money.
The Interchangeable World of The Microservices
This is where microservices enter the picture. Put simply, a microservice is a single application that handles one or more related business functions. The most common example is user account services. You deploy everything associated with this single business need across its own infrastructure. At a minimum, the microservice will have its own dedicated database and servers, and it may even be deployed in its own dedicated network space. Communication with this service is usually handled via a RESTful API. This separation extends to your development team as well, with each service having a dedicated product owner and development team, in addition to a stand-alone feature list, development schedule, and code repository. Ideally, this separation is based on discrete business units within a company; there may be a microservices team for user account services, finance, or reporting.
Using this model, a monolith can be broken up into multiple microservices. This has the potential to solve many of the problems we encounter in monolith architecture. Since a service has it’s own dedicated servers, it’s possible to add additional servers to a microservice that may need a little extra horsepower during times of heavy load. There is no longer a need to redeploy everything as new features are added; just redeploy the affected microservice. Infrastructure becomes more resilient since a bug in a specific service will not bring down everything else. Finally, it becomes much easier to use a single microservice — such as user account services — across multiple applications.
Here Be Dragons!
Sounds great! So why not use microservices everywhere? At their core, microservices are inherently complex and can make life infinitely worse than just sticking with your current monolith. In order to be successful, you must have a mature development process to manage microservices deployment. You can use any process — from waterfall to agile — as long as your process allows you to consistently take a feature from definition through development and into deployment. If every deployment is a nightmare, your team may not be ready for microservices.
Switching to microservices adds much more complexity to your overall application stack. Microservice A need to communicate with Microservice B; how do those microservices go about discovering each other? Microservice B needs to be able to handle error situations that may arise if Microservice A is not responding properly.
There is also a risk of a microservices population explosion. Teams often decide if one microservice is good, then 100 would be great. Or they chop up the monolith too finely, with a multitude of microservices that would be better combined into a few properly focused services. A nice rule of thumb: microservices should be a focused on a business unit, not a specific business action.
Make It So
Before introducing microservices, make sure your team is ready to go, with a well thought-out process that can support this new adventure. Also, start small! Pick one service that allows you to refine your process and infrastructure in a thoughtful manner. After you’ve lived with this service for a while, you can then decide if you want to do another one, with the benefit of lessons learned.
Microservices are not a silver bullet. Like any tool, microservices can be misused in ways that will make things worse for your company. However, with a little foresight and proper planning microservices are a wonderful solution that can make dramatic improvements for any enterprise. Of course, if you need a help with your development process as well as architecting, building and deploying microservices, you can always reach out to Presence for help.
Eric Müller is Director of Technology at Presence.