DEV Community

Gabriel Chertok
Gabriel Chertok

Posted on

My monolith doesn't fit in your serverless

Serverless is the future, no doubts about that, and I love the model. For a small agency like Ingenious it helps us reduce costs and allow us to forget about infrastructure.

As cool as serverless is, I found myself always needing to go an extra mile to deploy a complete solution, and it's not for the lack of tools. I have come to the conclusion that the problems I'm tasked to solve are tricky to get right using a serverless approach. Here's my take on why not serverles-all-the-things.

What's serverless?

First, let's scope what we say when we speak about serverless. A definition I like -that may be incomplete- is the following: "Serverless is the ability to scale up, but also to scale down to 0".

I would add that typically serverless comes in the flavor of specialized services. For example, if you do a serverless app to store and retrieve things from a database, you may need at least functions, datastore, and authentication services. Probably also some background job processing, CDNs, etc.

In theory, this sounds amazing, having all these discrete parts that do only one thing, and one thing well sounds appealing. I used to think serverless would solve most of our problems and that we will be able to write the frontend and author some functions to glue the different services together.

The magical world of cherta that doesn't exist

I don't think that anymore

Sadly, I don't think that's the case. At least not for the apps I build, and I would argue that's also the case for many of you.

Stitching services together sounds excellent in theory, but it has its own complexity. I'll try breaking down a list.

Lack of conventions

When developing a monolith, either RoR, Laravel, Django, or any other tool, you have a common way of modeling the problems, and this philosophy sticks during the development process. I think I would know how to use Rails ActionMailbox even if I never used it in the past, the framework is coherent and I know what to expect.

This doesn't happen when you use Service A for one thing and Service B for another. There's some extra work your brain needs to do when moving between specialized services.

Event-driven programming is hard

At the very core, whenever you need to use two services together and complement some missing functionality with a lambda function, you are doing event driven programming. This is, an action performed in service A may trigger a function to execute and impact your datastore, or to send an email, etc.

This model is hard to follow, things end up in a database, or in a queue without apparent connection. Similar to what happens on a monolith with model callbacks where you start getting effects that do not follow an evident cause.

Conclusion: How to decide

As usual, it depends. When the endeavor is huge, and you are building an app that needs to scale rapidly and painlessly, I think you should definitely consider serverless. Here service orchestration costs are less than what the services itself will offer in terms of scalability, reliability, etc.

The same is true when tradeoffs are minimal. Imagine a small website like Ingenious's website or a marketing site. Those have not that many moving pieces, so I think it's ok to liberate myself from thinking about the infrastructure.

But, here's the catch. Most of the apps we develop, and when I say we, I mean, most of the people I know that work on the industry -sorry, I don't have any friends at Google 🀷- are in an uncomfortable middle ground.

Their app is probably not that big that needs to scale to infinity. Neither is so small that you can hold the architecture in your head all the time.

Most of the apps I've worked on are fine running on Heroku dynos or having a few powerful DO boxes. Yeah, that may be a bit expensive, and I'm sure you can cut the bill by 50% if using serverless, but is it really necessary? What things are you trading off by doing that?

Too many times, I end up answering that it isn't worth changing. I may be getting old πŸ‘΄πŸ§‰, but I prefer to be in control and to keep the same conventions thru my app even if I need to pay a bit more.

With that being said, I also think this will change rapidly. Both, technologies, and serverless services will end up providing full-stack frameworks that will mix the best of both worlds. I think Blitz.js heads in that direction, and it will be interesting to see how it evolves.

For now, I'm sticking with monoliths and plain-old-servers for the apps I need to maintain, but hopefully not for too long.

Top comments (17)

elussich profile image
Esteban Lussich

Nice post, Gabriel. You touch on very interesting points and I can relate to several of them.

In the same line of full-stack frameworks, and similar to the direction taken by Blitz.js, have you tried RedwoodJS? I went through their project tutorial and had it (almost) completed; it looks promising to me, although there's still a learning curve, as in any other framework, maybe less related about specific technologies, but more related to architecture, structuring and high-level decisions.

I wonder if that's one of the reasons that would push people away from embracing a full-stack framework or platform (and me, from completing the tutorial... :P), opposed to just write some React code, and make some web requests, and, you know, make it work. You mention "Lack of Conventions" as a main disadvantage, but I wonder if that's actually appealing to some developers, specially the ones not familiarized with the hurdles of backend work.

iamcherta profile image
Gabriel Chertok

Thanks Esteban, I'm glad you liked it! I haven't tried RedwoodJS (neither Blitz.js tbh), but I know the big picture.

I understand structure and conventions may push back some people, but honestly, if you are doing any decent sized app you will need to come up with structure yourself. The debate is not no-structure vs Redwood structure (or rails or Blitz), but your own clunky structure vs a tested one.

Of course if the app is small, then maybe no-framework is the best framework, but when there's more than one dev on the team -even on small apps- structure and conventions make a huge difference.

A word on the difference between RedwoodJS and Blitz.js, and why I mention the later. I think Blitz enhances the idea of a monolith making the API you call from React to your controllers an implementation detail. It has an API, but it looks you are calling a node method. This fuzzes the client-server line, same as django or rails does with the view layer, where you can declare a variable in the controller and access it in a template.

For me, this thinking produces a faster development experience, you are not required to think where in the stack you are, you have less moving pieces resulting in less information in your head. I think I cover some of that on my previous post telling how we currently think at Ingenious.

jreinhold profile image
Jeppe Reinhold • Edited

I couldn't agree more, I've come to the exact same conclusion over the past year. I've built two different web applications, where the backend was entirely composed of Lambda functions. In theory it sounds great, and in the beginning it was. We didn't have to worry about environments, servers, containers, up-time, etc. But I quickly realised, that the complexity was just moved, to now be about executions, orchestration, event communication, and most importantly, the lack of a great local development workflow.

... I'm sure you can cut the bill by 50% if using serverless, but is it really necessary? What things are you trading off by doing that?

Exactly! Sure, your infrastructure bill will go down, but without a great local development setup, your productivity will go down too! And IMO serverless hasn't yet solved that problem. In the software industry, the cost of time is MUCH higher than the cost of infrastructure (many miss this point). If the developers are just 5 % slower, because it's a bit more complicated to run the backend while developing, you will NEVER see those savings, because the developers' pay-check is huge compared to the infrastructure bill.
And that's just talking money, now factor in employee satisfaction, planning, etc.

mattschwartz profile image
Matthew Schwartz

You're exactly right. Human time will almost always cost more than hosting.

I'll add that "serverless" is not always cheaper than traditional hosting. By the time you hook up all the services, and require more usage than the free tier but less than the high volume discount tiers, you could end up spending around the same. The cost savings really depend on the use cases.

themobiledev profile image
Chris McKay

Don't forget that going serverless, in its current state, is also handing control over to a few companies (primarily GCP, Azure and AWS). Hosted servers give you a little more control and the freedom to jump ship to another host if something goes wrong (or prices increase).

Thread Thread
iamcherta profile image
Gabriel Chertok

I agree with you. It's not something I think every day, but it's definitely true that we have less players for serverless than for regular servers.

iamcherta profile image
Gabriel Chertok

I totally agree! I do feel we tend to copycat what works for other companies and extrapolate to our own use case, and here's the catch, most of us don't need the scalability serverless provides, but all of us using serverless will pay the upfront cost of service orchestration, and reduced developer experience.

jreinhold profile image
Jeppe Reinhold

Yeah, it's totally underestimated how many millions request ywe can handle a day with even a medium sized EC2 instance or similar, and the majority of us will never need more than that.

benbonnet profile image
Ben • Edited

With any given monolith framework (rails, django, etc...) that runs on docker, you'll be fine on cloudrun for most apps. Try fargate if you prefer aws (way harder than cloudrun, but same paradigm). You assets can surely be moved to any cdn easily.

You don't need to split your apps to see hundreds of endpoint. You don't need to run a ruby based framework, neither lamby, neither jets. You can move away from sidekiq and use shoryuken, or cloudtasker. You now have serverless postgres at aws, gcloud might follow sometimes soon.

A class is a microservice, and your monolith is the best way to manage thousands of those (let's just laugh about what's called "service discovery", it sounds so painful).

imho monolith devs have been fooled by the hype around tools that were actually lacking of so many functionalities. They already had everything in hands. Redwoodjs or Blitz are a solution for js devs that struggled so much that they ended up creating their monolith-capable solution.

Give your old app a go. Don't loose time believing that you NEED to spend hundreds of hours learning a new framework that did not even prove a fraction compared to your framework.

With little efforts, it'll work, serverlessly.

iamcherta profile image
Gabriel Chertok

Thanks for your comment Ben!

I agree with most of what you say, I still believe running Docker containers is far more complex than being provided with a platform, either a serverless platform or a serverfull (?) one (rendr, Heroku).

Other than that I fully embrace the monolith model myself, and I make the conscious decision of what problems I want to deal with. I understand I'll need to deal with some infrastructure problems and probably incur in more costs, but I gain productivity and traceability of my code and program behaviors, and that for me is far more important.

benbonnet profile image

Well it boils down to saying "Running a monolith is painful, and if you dare using docker, you'll loose productivity"

Things can alway get better, and there are always improvements to find anywhere

Most failed at serverless. It has been created by cloud providers to increase lock-in, that's all. Not to really help anyone's productivity. Going serverless does not mean that you have to stick to the advertised schema

Once you read between the lines, it'll maybe cost you an hour or so to learn those ten lines of docker maybe, and probably way less to find out where your stdout should go. This can be seen as a productivity loss of course..

brpaz profile image
Bruno Paz • Edited

Nice article.

I believe that when many people talking about Serverless, they think mostly about Lambda functions and similar.

But for me, Serverless is much more than that. (I wrote about it here).

A good example of a Platform that implements my vision of serverless is Google Cloud Run.
You just need a container and you can run it with one click. You can deploy your traditional Rails, Laravel apps while still benefit from some of the serverless advantages like no infrastructure to manage, and "infinite" scalability (including scale to 0).

Together with a Serverless Database like Fauna DB or a traditional MySQL / Postgres running on some instance, and you can get pretty far.

iamcherta profile image
Gabriel Chertok

I'm glad you like it!

I don't know Google Cloud Run, I must check it. I use a "similar" approach with, it's not the same and focused solely on Rails, but it gets the job done without too much magic which is something a value a lot.

I read your article and I completely agree on the approach that FaaS is not Serverless, that's for me the next step in the way we see serverless.

kspeakman profile image
Kasey Speakman

I have the same outlook about serverless. Moving things out of process means that you now have to deal with new failure modes and latencies for communication between components. It works exactly the same as when a company grows and splits into departments. Only it doesn't make sense to split into 5 departments (or any at all) when your company only has 3 people. I think this is a lesson from Conway's law that has been missed as people are discovering serverless.

On AWS, there is an interesting ops middle ground between shepherding individual EC2 machines to using Lambdas. And that is using Fargate. Unfortunately it is more expensive than both of these options. We are using the similar but cheaper option -- our own ECS cluster. It is like fargate, but we have to tell it what EC2 resources should back the cluster. They only charge for the EC2 resources -- the clustering is no charge.

iamcherta profile image
Gabriel Chertok

Nice info about how to handle it on AWS. I'm currently using to provision DO boxes, both in cluster or standalone, also I tend to over use Heroku for dev/staging/review apps which provisions a new Dyno and DB for every new PR.

agorakit profile image

In my situation, serverless relates more to something that looks like shared hosting for an initially small project, and the scale up involves scaling up to the point the project uses a single, very powerful server at my hosting provider (at a quite high price). And you know what, none of my project ever reached the limit of the single, managed high end server.

I have the feeling that this serverless trend smells over-engineering for a lot of projects.

Tradeoff : you need to trust your hosting provider, and they must provide a nice scaling on the pricing side (from a few $$ / month up to a few hundreds / months).

diegocard profile image
Diego Cardozo • Edited

Hey, nice post Gabriel!

In my opinion, in order to understand the value of serverless frameworks, there are two questions that you need to answer first and foremost:

1) What type of application are you trying to build? a.k.a what is your business model?

For instance, a company that sells a specific service/product is a completely different world from a company that has 10 teams working on 10 different applications tailored for 10 different customers. These companies could be equal in size, but they have completely different requirements and trade-offs.

2) Where is the bulk of the cost/effort for your product? Is it in setting up the infrastructure initially? Is it in adding new requirements? Is it in troubleshooting? Setting up CI/CD?

Depending on the answer to these questions, different serverless frameworks will yield different benefits. Otherwise it's hard to draw any concrete conclusions.

Now, allow me to get into some specifics in order to provide something a bit more valuable to this discussion. I'm going to talk about AWS because, well, it's simply what I know best. Say you are building a typical web app (SPA, API backend, DB and authentication).

In this case, the likes of Fargate and RabbitMQ and incredibly overkill. Yes, if you're trying to model a simple app using those components, you're going to run into trouble. They're meant for much larger applications.

You should be looking at solutions like SAM and Amplify that will abstract away a lot of complexity. Vercel is also a great alternative.

Concretely, SAM lets you specify your desired architecture in a single config file, and it will take care of deploying, creating and changing all the components for you. It will also allow you to run your serverless code locally and do things like debugging lambdas directly on your IDE. Is this more complex than Heroku dynos? Yeah, and that may be enough to make you go for the latter. But it's significantly more powerful.

-- Disclaimer: I work in AWS, but these are just my own opinions.