My Insights After 10 Years of Serverless
Common mistakes, emerging tools, and architecture patterns from a decade in the trenches
Hey, it’s Lefteris 👋 I’m the voice behind the weekly newsletter “The Cloud Engineers.”
Ten years ago, I discovered Serverless and AWS Lambda, and it changed the way I build software forever.
What started as curiosity quickly turned into conviction. Over the past decade, I’ve designed and shipped production systems entirely on Serverless. I even built a startup from scratch, on a fully Serverless stack and took it to production in just 10 months.
In my four years at AWS, I’ve worked alongside hundreds of customers on their Serverless journeys, from first Lambda functions to complex event-driven architectures. Along the way, I distilled everything I’ve learned into my book, Mastering Event-Driven Microservices in AWS.
Last month, Lee Gilmore, an AWS Hero, reached out and featured me in his Serverless Advocate newsletter, where he posed three thought-provoking questions about the state of Serverless. I’m sharing my answers here, because they touch on things I think every Serverless engineer should be thinking about.
Q1: What is one common mistake you see teams making when building their solutions, and how can they avoid it?
A common mistake is that companies think serverless is all about AWS Lambda, and as a result, they become overly concerned about cold starts.
In reality, serverless is much broader than Lambda. Many use cases can be solved without Lambdas at all. For example, by using direct integrations with Amazon API Gateway or orchestrating workflows with AWS Step Functions.
The key is to step back and evaluate whether Lambda is actually needed. If it’s only being used to move data from one service to another, it’s often unnecessary.
That said, when you do need Lambda, you should know how to optimise it properly.
Three of the most effective techniques are:
Optimise memory: Use the AWS Lambda Power Tuning tool to find the optimal memory configuration. Since memory allocation also scales CPU, the right balance can significantly reduce both execution time and cost.
Minimise deployment size: Smaller packages lead to faster cold starts, so remove unused dependencies and keep artefacts lean.
Use SnapStart: Especially for Java workloads, SnapStart can dramatically reduce cold start latency by initialising functions ahead of time.
By using Lambda intentionally and optimising it when needed, you can avoid unnecessary complexity and get the best out of serverless.
Q2: Which tool, package, or AWS service are you most excited about right now, and why?
Right now, I’m most excited about AWS Lambda durable functions. This is something the ecosystem has needed for a long time, bringing orchestration closer to the application layer. Previously, you could achieve similar outcomes with AWS Step Functions, but local development, testing, and debugging were often cumbersome.
Although this may seem similar to Step Functions, the trade-offs are important:
Use Lambda durable functions when:
Your team prefers standard programming languages and familiar development tools
Your application logic primarily lives inside Lambda functions
You’re building Lambda-centric systems with tight coupling between workflow and business logic
Use Step Functions when:
You need a visual workflow representation for cross-team visibility
You’re orchestrating multiple AWS services and want native integrations without writing custom SDK code
You want zero-maintenance infrastructure (no patching or runtime concerns)
Durable functions make it much easier to build complex, long-running workflows directly in code, opening the door to more advanced use cases like multi-step processes and agent-style orchestration, without sacrificing developer experience.
Q3: What is your favourite trick or tip that the readers may find interesting?
A common anti-pattern I see is treating AWS Lambda as “one service = one function.” This often leads to architectures with hundreds of tiny Lambda functions, which quickly become difficult to manage, deploy, and reason about.
Instead, treat your Lambdas as microservices within a bounded context. It’s perfectly fine, and often preferable, to group related functionality together. For example, within a “users” domain, you can have both ‘createUser’ and ‘deleteUser’ handled by the same Lambda.
When deciding how to group your functions, consider these factors:
Bounded contexts
Team organisation
Scoped IAM permissions
Common code dependencies
Common downstream dependencies
Initialisation time (cold start impact)
Memory configuration
A powerful way to implement this approach is the Lambda Web Adapter pattern. Instead of creating one Lambda per HTTP endpoint, you run a traditional web framework inside a single Lambda and handle routing internally. This allows you to use familiar frameworks like Express.js, Flask, Django, Spring Boot, or ASP.NET.
The result is a more maintainable system that aligns with real domain boundaries, without losing the benefits of serverless.
Conclusion
Serverless has matured enormously over the past decade, but the fundamentals remain the same: build only what matters, let the cloud handle the rest, and always optimize for simplicity. Whether it’s choosing the right tool for the job, embracing new capabilities like Lambda durable functions, or structuring your Lambdas around real domain boundaries, the goal is to ship faster with less operational burden. If you want to go deeper on event-driven architectures, my book Mastering Event-Driven Microservices in AWS covers these patterns and many more in detail.



