Serverless is an awfully attractive option. You're freed from infrastructure management, and you pay only for what you use. Actually adopt it, though, and a different kind of work is waiting for you once the infrastructure chores shrink. You end up facing constraints and complexity peculiar to the application design side.

Think of serverless as a meeting room rented by the hour. It's far lighter than signing a lease on an office, but rented rooms come with house rules. In other words, it is not the right answer for everyone. I tried to sort out why, starting with the main constraints and then moving on to where it fits and where it doesn't.

A Short-Lived, Stateless Execution Model

If you adopt serverless, FaaS in particular, there are several practical constraints you can't get around. To begin with, serverless is a model premised on short-lived, event-driven processing. A meeting room is not a place to linger.

First, there is a limit on execution time. Ordinary AWS Lambda functions have a maximum of 15 minutes, so longer work needs splitting or a different execution model. Nor can a function assume its own work will continue after an invocation ends as it would in a long-running process. The execution environment is not necessarily destroyed immediately after every invocation, however: it may be reused for a later one.

The application still needs a stateless design. Memory and temporary files may survive in a reused environment, but the next request is not guaranteed to reach that environment. State that must persist belongs in an external database or storage. Finding yesterday’s writing on a rented meeting room’s whiteboard does not make it the official ledger.

Cold Starts

When a function that hasn't been called for a while is executed, the environment has to be initialized, and the response can be delayed. This is the so-called cold start. A room nobody has used in a while starts with unlocking the door and switching on the air conditioning.

The delay is especially noticeable with languages that are slow to start, such as Java and .NET. The same goes for functions placed inside a VPC. In APIs that need low latency, it can hit the user experience directly.

Poor Visibility

Because the system is scattered across a swarm of small functions, troubleshooting becomes considerably harder than with a traditional monolith. Fully reproducing things in a local environment is difficult. Tracing processing that spans multiple functions gets complicated, too.

As a result, getting the big picture requires real skill with dedicated observability tools. Think CloudWatch Logs, X-Ray, and Datadog. You may find that working out where it broke has become a bigger job than the outage itself. That is entirely possible.

Lock-In and Cost

Incidentally, serverless is tightly bound to the various services the cloud vendor provides. Databases, storage, triggers, and so on. So if you later try to move to another cloud or on-premises, migration costs pile up. Sometimes the whole architecture needs rewriting.

Estimating cost is also somewhat tricky. The upside is that it costs nothing when unused, but it's hard to tell how far the bill will balloon when traffic suddenly surges. Not knowing the truth until you open next month's invoice is bad for the heart.

Also, for workloads under constant heavy load 24/7, it often ends up more expensive than renting fixed instances. If you're booking the meeting room from morning to night every day, you'd be better off just leasing the office.

Responsibility That Moves into Design

The crowning issue is architectural complexity. With infrastructure management no longer needed, that responsibility moves wholesale into application design. The landlord looks after the building, but nobody is going to run your meeting for you.

For example, you have to decide on a retry policy for failures and guarantee idempotency so that nothing goes wrong if something runs twice. Then there's the distributed transaction problem: how to maintain consistency when part of a process spanning multiple functions fails. All of this has to be solved at the code level. The team's design skill feeds straight back into productivity.

Jobs It Suits, Jobs It Doesn't

Given these constraints, where it fits becomes fairly clear on its own. Serverless suits, first of all, workloads with unpredictable spikes. Having it scale up by itself to match a sudden surge in traffic is about as convenient as it gets.

Next come intermittent jobs, like a batch that runs only a few times a day or an endpoint that receives webhooks. And then there are trigger-based, event-driven pipelines, such as running a conversion whenever a file is uploaded. All of these only need the room when they need it.

Conversely, it's a poor fit for processing that needs to run for a long time, like video transcoding or batch analysis of huge datasets. Real-time communication that keeps connections open at all times, such as WebSocket, doesn't get along with it either.

APIs that always demand extremely low latency and can't tolerate cold starts are best kept away from it. And for a high-load system where requests never stop coming, fixed instances end up more cost-efficient. Each of these amounts to trying to move into the meeting room.

That sums up the constraints of serverless and where it fits. Serverless is not a magic wand. It's a choice to entrust infrastructure management to the cloud vendor in exchange for taking on rigor in application design.

If you're considering adopting it, looking only at the reduced operational load isn't enough. Can your team absorb the complexity unique to distributed systems? That is the question to judge by. The servers may go away, but the thinking doesn't.