Serverless
Arquitetura de Software
Implementação
Cloud Computing
Boas Práticas

Serverless for applications: architecture in practice

The difference between a serverless architecture that works and one that turns into a nightmare lies in the decisions you make before the first function.

Understanding serverless is one thing. Implementing it well is quite another. Many people who embraced the concept discovered, along the way, that the promised ease was accompanied by difficult decisions that no one had mentioned.

The distance between the serverless of the slides and the serverless of production code is where teams get hurt. Not because the technology is bad, but because it requires a way of thinking that few develop before they are already in trouble.

This text is for those who decided to build with serverless and want to do it right. Let's talk about the real design decisions, the pitfalls that appear in implementation, and the discipline that separates a solid architecture from a clutter of functions that are difficult to maintain.

The deceptive ease of the beginning

Serverless has a seductive beginning. In a few minutes you upload your first function, it responds, and it seems like everything will be that simple. That's where the trap lies.

The problem is not writing a function. It's writing fifty functions that talk to each other, share logic, depend on data and need to be understood by a team six months later. Complexity doesn't go away with serverless. It changes location, leaves infrastructure and goes to architecture.

Those who don't realize this build what is called a "distributed monolith": all the disadvantages of a distributed system, without any of the advantages of a thoughtful design. It's the worst of all worlds, and it's more common than you might think.

The thesis: serverless requires more design, not less

Here is my central position. Serverless does not dispense with architecture, it demands more of it.

When you manage servers, part of the discipline is imposed by the infrastructure. You are forced to think about how the pieces are organized. Serverless removes this imposition and returns total freedom. And freedom without discipline becomes chaos.

Therefore, implementing serverless well is an exercise in conscious design. You need to decide, on purpose, how to divide responsibilities, how functions communicate, where the state lives, and how it all stays understandable. Those who treat serverless as "fast serverless code" reap technical debt at record speed.

Design decisions that define the outcome

Granularity: how small each function should be

The first difficult decision is size. Functions that are too small multiply the complexity of communication. Functions that are too large lose the benefits of modularity and independent scalability.

A good rule of thumb is to organize roles around clear business responsibilities, not trivial operations. Each function must do something cohesive and understandable. Resist the temptation to fragment everything into micro-pieces, the seduction of the "extremely granular" usually ends in ungovernability.

State: Where the data actually lives

serverless functions are, by nature, stateless. They are born, they execute and they die. This means that all state needs to live outside of them, in databases, caches, stores.

This is one of the biggest mindset shifts. You cannot keep anything in memory between runs. All persistence is explicit and external. Designing this well, choosing the right stores for each type of data, is what separates a reliable application from one full of unpredictable behavior.

Communication: how the pieces talk to each other

In a real serverless architecture, functions need to interact. The decision of how they communicate, synchronously, waiting for a response, or asynchronously, via events and queues, shapes the entire robustness of the system.

Asynchronous communication, via events, tends to bring more resilience: if a part fails, the message waits. But it adds tracking complexity. Synchronous communication is simpler to understand, but it creates coupling and propagates failures. This choice is not minor technical, it is structural.

An example of conscious implementation

Imagine building the backend of a delivery app using serverless. The flow of an order involves several steps: validating, charging, notifying the restaurant, tracking delivery.

The naive implementation would make a giant function trying to orchestrate everything synchronously. Result: slow, fragile and impossible to debug. If the notification fails, the entire request hangs.

Conscious implementation separates responsibilities. A function receives and validates the request, recording it. This emits an event that independently triggers billing, notification, and tracking. Each part fails and recovers on its own. The order status lives in a database, accessible by everyone.

The difference between the two is not technology. It's the design care taken before writing the first line.

The pitfalls of implementation

The first pitfall is debugging. When something goes wrong in a system spread across dozens of functions and events, finding the cause is difficult. Without proper tracking from the beginning, you are left blind. Investing in observability is not optional, it is a condition for survival.

The second is the configuration explosion. Each function has its permissions, its variables, its triggers. At scale, managing this manually becomes a source of errors. Treating infrastructure as code, versioned and automated, stops being a refinement and becomes a necessity.

The third is the illusion of isolation. Functions appear independent, but share banks, queues, and provider limits. A poorly behaved function can affect the others. Thinking about these invisible dependencies is part of the job.

Discipline is the true infrastructure

What I've found, in practice, is that serverless doesn't eliminate hard work, it displaces it. You stop taking care of machines and start taking care of design, communication and state. For those who approach this with discipline, the result is powerful: flexible, scalable and cost-effective systems.

For those who treat it as a shortcut, the result is a tangle that no one understands and no one wants to maintain. The technology is the same. What changes is the rigor of those who wield it.

Serverless is not easier. It's different. And the difference is won with design, not with haste.

If you are implementing a serverlessarchitecture and want to avoid the classic pitfalls, it's worth changing your mind. I have other articles on the blog about the concept of serverless, use cases and day-to-day operations that complement this implementation vision.

Also read