The return of the majestic monolith
Microservices are all the rage. But should they be? Here's why microservices should be used when needed instead of by default and why a monolith app is better suited to your software architecture.
It’s the break between years. Christmas, the heralding of the New Year and some time off from work. And that means, sun, beach, bbq’s, beers, air conditioning and having a bit more free time than usual. I’ve found myself on YouTube a lot, and doing a lot of reading and watching people on YouTube reading blogs and then doing discussion such as The Primagen (who produces a lot of awesome stuff btw).
What got me started on this was watching the excellent documentary series that’s been produced on open source that has had a big impact on the tech industry in the way that applications are built and run. I’ve seen a lot of them (like the kubernetes one), but specifically this one recently:
I liked this documentary for a number of reasons. Firstly the actual video footage, way they conduct the interviews and I really, really like the story telling. The way people could tell their stories was very well done and as the audience, I felt I was able to connect with them and feel what they were feeling as they told their story. After that the YouTube algorithm got to me, and I started getting fed more relevant content to this video which was this one. Both of which resonated with me.
I am fully aware that in the tech community DHH says a lot of controversial things. Or rather, things that many feel are controversial. But a lot of people are speaking from the comfort of hiding behind their keyboards and are being armchair activists in some cases. In one example, the amount of flak DHH got about his cloud exit was nuts I think. So much was said about it, but there were many truths in his commentary and opinion that were worth considering. Him and Jason have been in business for 20 years and Rails is also 20 years old this year. You don’t spend two decades in business and make decisions like that lightly, and you certainly don’t make them without a lot of research. Listening to him and Kelsey Hightower riff on and talk about this exact topic was a really interesting discussion, but I particularly loved the passion and grounded answers DHH was giving to the various questions from Kelsey and the audience. Despite being considered to have many unpopular opinions, I actually really respect DHH for his comments and way he goes about his business in building successful businesses with carefully considered approaches to tech choices.
But of all that I’ve watched and seen talked about as well as read in the past 3 weeks or so, it was this opinion that has stuck with me. I won’t quote because it’s been said in various ways, but this is my interpretation of it (on the topic of monoliths - i.e. ruby on rails).
Most people, businesses, platforms and organisations don’t need microservices and the complexity they bring. Much of the work that an application needs to do can be done in a monolith. Rails’ primary focus is to bring developer happiness and productivity to allow them to focus on the customer and build out meaningful apps that people want to use.
Creating microservices (a.k.a. “service oriented architecture”) adds significant complexity and latency to the product as now when you need to perform a task, you need to make a network call, and a network call is orders of magnitude slower than another function or class in the same app.
Sure, you have companies that are enormous, like the FAANGs but most companies will never need that kind of scale and they can get a really really long way with just a single monolith.
And I 100% agree with this sentiment. And it actually reminded me of another awesome talk I watched many years ago on “Scaling to your first 10 million users” which was an incredible talk and I highly recommend a watch.
In the talk, it’s discussed how you might scale a monolith as your load increases, and it’s not until you get to 1 MILLION users that it’s suggested to break out your architecture a little bit to support it.
This screenshot is provided in the talk and it refers to what your architecture could look like at 1 million users. Notice that the bulk of the work is still the monolith, but there are some auxiliary services like functions and NoSQL databases that are used to support some of the enormous load. And these are only introduced once the usage of your app is really well established.
Intermission: A bit of background on me in case you didn’t already know… I got into software development by learning ruby and rails online using a video course and then started going to meetups and eventually found an entry level job as a developer. So I started with Ruby and Rails and so my opinion may be a bit biased but I will always have a soft spot for Ruby.
In the past 9 years of my career from Rails, I went to Go and React (class based component with lifecycles that seemed to be deprecated/changed every 15 minutes - yuck!), then dabbled in VueJS for a bit before returning to React and Node for a good three or so years. I then spent a lot of time developing backends on AWS such as AppSync (managed graphQL), lambda, and containers. More recently I worked a lot in Go and React, and found myself really loving Go, but loathing the bloat from create-react-app so I went looking for alternatives. At first I found and did enjoy Vite for a bit, but that was really just (what felt like) a lightweight react. Then I tried Next.JS for a bit and was just “meh” about. I kept feeling like Vercel were waiting to pounce at any time on my credit card. After watching a lot of Primeagen on YouTube, I got stuck into HTMX and Go with Templ for a while which was a breath of fresh air! No more node! But even still, it felt like I was just having to do too much. I was just experimenting, but I wanted to try to get an idea up quickly and test it with a few friends.
Then I saw that documentary above, and after a YouTube vortex, I saw this. The Rails 7 demo where DHH (again!) does the quick demo of the 15 minute blog, although it’s a bit longer now. And WOW, what a breath of fresh air.
I had mostly worked in Rails 4 back in the day, then dabbled with 5 and 6 when they came out, but there was so much javascript in there, especially with webpack and so forth. When I saw that video, I thought I’d give Rails another look.
It has been truly awesome for me to build stuff with Ruby again, and it’s so much faster now. Maybe computers are just faster, or maybe because there’s not as much JS in there anymore but it feels super lean and quick. In 15 commits (some are squashed), I have built a prototype app which I’ve deployed and have running on Google Cloud Run.
I’ve got a Postgres database, some models, a bunch of validations on the data being input, some asynchronous jobs running with active job and it’s all completely tested and testable. I don’t need to emulate message queues, or setup contracts between api’s for microservices. I also only need to manage fewer IAM permissions and provide fewer access to APIs I might otherwise need access to. It’s server-side rendered too, so it will play nice with deep links and open-graph. I’m looking for beta testers by the way, so if you’re interested, please fill this out and I can invite you! The one-line description of the app is: A way to share, categorise and organise your bookmark library of links to all kinds of things on the internet from recipes to learning new skills to holiday organisation.
It seems that lately distributed applications and microservice oriented architectures are all the rage but they bring significant complexity with them that most organisations don’t need. I think that Rails specifically with it’s focus on developer happiness and productivity provides a wonderful way to experiment with ideas, get them out quickly to market (or in my case friends and family and you, dear reader) and will get you a really, really long way before you need to start to bring additional complexity in to support the growth. Not to mention, additional developers to support that complexity.
One of the advantages touted by the microservice architecture is that they can support independent scaling if one part of the app gets busy. Sure that is true, but what kind of service is it? Is it a front end to support loading images? You can use a CDN in front of your monolith. Is it an email service sending out order confirmations or something? You could use background tasks to process those emails when the system isn’t busy. Even if you decide you really need to do it, then you need to setup a separate repository for your second service. You need to setup authorisation, secrets, service identities, etc. You need to spin up new compute too, and then it has connectivity needs. Is it public or private? IP addressing, routing and so on.
Another proclaimed advantage is that microservices introduce fault tolerance, in that if one part of your app goes down, then the rest can continue to work. I think this comes down to having good observability and becoming aware when things are a problem. Regardless of monolith or microservices. If, for example, your “payment” service in an online shop is not working, sure your app is probably showing the website and maybe the shopping cart, but when people go to pay then they just get error messages. In a monolith, they’ll still see the same error messages, but if the point was about nothing working at all on the monolith, then hopefully a failed deployment would initiate a rollback due to failed health checks. Good engineering habits (in my opinion) measure these kinds of metrics - the DORA metrics. When measuring things like MTTR (mean time to recovery), your change failure rate and LTTC (lead time to change) can mean that you can reduce your impact to customers by identifying problematic changes.
The point I’m getting at here isn’t to say don’t do it, not at all, I’m simply suggesting to take a step back and look at the needs of the overall platform and business and determine if you really need that thing or not. It’s definitely tempting to be doing what the new-hot-trendy-thing is, and right now it seems that microservices are all the rage. Or you know, Rust. We went from server side rendering to shoving megabytes of React down the wire to the client to deal with and now there seems to be a trend to go back to server-side rendering (htmx/templ/go), is it the same with the monoliths vs microservices debate?
I think for most people and most businesses the answer is yes.