It’s been a long time since my last Article in January. I apologise for the delay, it’s difficult to find time to just sit down and translate my thoughts into insightful, digestible content. I have so much I want to write about but sometimes there’s so much that I don’t exactly know where to start.
The purpose of this post is intended to help you decide whether you should use monoliths, containers or serverless architectures. Each have their own merits and faults and we’ll discuss each of them in detail throughout the article. The decision should ultimately be made based on the stage of the project you are at and your familiarity with these architectures. A clean architecture will always be better than a messy one, no matter the principles.
The reason I’ve been so busy the last 6 months is because I’ve been helping to migrate our architecture from Monolith -> Containers -> Serverless. We started with a monolith and we are in the final stages of migrating to serverless so hopefully I can provide you with some valuable insight to the challenges we have faced on the journey.
A monolithic architecture is a model wherein all the software is self-contained and most, if not all of the functionality tends to be tightly coupled. If one line of code is to be changed in a monolithic architecture, the entire software must be recompiled and deployed to apply the change. If a team of engineers are working on a monolithic architecture, it can be messy and time consuming to have several deployments a day.
A great thing about monoliths is debugging and testing. Since the software is self contained and components are tightly coupled, it becomes a lot easier to find where a problem originated and you need only run a single suite of tests. A side effect of this, is that if your software has a single fault, your entire monolith is brought down.
Scaling a monolith is notoriously difficult. There are things that you can do to smooth the process. You could place a number of monoliths behind a load balancer. However, a monolith can only really scale vertically. If one small area of your software is using a lot of memory or CPU, you will have to increase the limits across the entire monolith, which can cost a significant amount of money when you get a lot of traffic.
However, if you are building a new idea and you want an MVP (minimal viable product) to show as a proof of concept, a monolith is appears to be the best architecture since it requires the least amount of work to set-up and initially maintain. If you design your code well, it will be easier to migrate from a monolith at a later point. We started with a monolith.
A container architecture is a model wherein your functionality is typically split across different software. If you have two services— one that uses a lot of memory and the other using a lot of CPU — you would most likely put them both in containers and allocated different memory and CPU to each service.
The most common application for containers is a visualised environment being manipulated by an orchestrator. I wrote about this in fairly extensive detail in one of my previous posts, here. I explained all the different tools and support within the micro-service ecosystem. The main benefit of containers for us was the scalability.
Microservices are horizontally scalable my nature. You can scale each service independently depending on the resources that they demand. If your services are well-contained and designed correctly, you can seperate your concerns properly and save plenty of time and money as opposed to a monolith.
Microservices are probably in the middle when it comes to being able to debug and test. There’s a lot of support and growth in the last couple of years. A company called Datawire have created a number of tools to help teams cope with the main obstacles when it comes to maintaining and extending microservice architecture.
If you currently have a monolith that’s starting to become difficult to extend and maintain, your next best bet is most likely a migration to microservices. The reason for this is that migrating to microservices can really help you define your business domains and understand what services you actually need and what resources each are likely to use. We migrated from a monolith to microservices and it really helped us to separate our logic.
There is a use case where you can use monoliths in containers but it’s not extremely common and I don’t personally have experience with this so I’m not going to discuss this.
A serverless architecture is a model wherein your software is executed in individual functions and are heavily decoupled. Serverless shares a lot in common with microservices in that each function is independently and horizontally scalable. You can create a number of functions that act as an entire service.
There is no such thing as a truly serverless architecture since there has to be a server somewhere. However, the functions within a serverless architecture are only ever invoked when they are needed via a cold start. A lot of providers have different rules for these functions but AWS functions live up to 20 minutes after the first invocation and so a lot of developers invoke them every 10 minutes automatically to simulate the effect of a warm function.
There are a few obstacles with serverless and one of these is shared code. If you have a cluster of functions that share some common logic, you will most likely still have to redeploy the cluster of functions with any change within the common logic. It’s almost like redeploying an entire microservice but the main benefit still lies in the independent scaling of each of these functions.
It’s also harder to test and debug serverless functions if something goes wrong somewhere in the architecture. You have software like Datadog and Sentry that help with catching and centralizing errors across the architecture. There is also an incredibly helpful tool called the serverless framework that helps with removing a lot of the boilerplate and setup required to get started with serverless functions.
Serverless still has a way to go to become mature but it’s growing at a staggering rate. If you are currently using a microservice architecture, I would encourage you to explore migrating some of those to the serverless architecture. I would not recommend going straight from a monolith to serverless as you most likely don’t have your business domains defined properly at that point. Since microservices and serverless have a lot in common, it’s easier to make that migration.
I believe that if you’re building a new idea, build a monolith. You get the benefits of speed, maintainability and ease of development/deployment.
Once the monolith becomes hard to maintain or extend, start to consider breaking apart your business domains and discover what services your business might need such as
auth-service and such.
If your microservices are becoming difficult to maintain or the resource allocations are becoming too complex, consider breaking apart your service into functions such as
check-acl-permissions and such. You get a lot more flexibility.
If this article helped you out, or you feel like just buying me a beer, feel free to throw me some change at https://paypal.me/joey. I’d also encourage you to check out some of my other posts.