The Truth About Debugging Serverless Applications
Bottom line: you can't. And that's good.
Debugging. The great divide line among developers. There’s probably no other activity that carries more “credibility” weight among software engineers.
Superhero developers are the ones who can debug quickly and effectively, even to the point of finding a (rather perverse) pleasure when a big problem occurs. It’s time to dive deep and show everyone how good at debugging I am!
I have never shared that type of love for debugging. I don’t even know how to set up a debugger on my current IDE. Don’t get me wrong, I’ve debugged a lot and I know the concept! I could set up a debug breakpoint in a few minutes if I need to. It’s just that, usually, I don’t bother.
One thing that I find especially attractive about serverless is that, coupled with an understanding of cloud-based development, I am implicitly encouraged not to debug.
This can be confusing to those who value the practice of debugging.
We Don't Need Debugging
A lot of people’s typical development lifecycle looks something like this:
Write a bunch of code
Refresh the page (or run a CLI command) to check that it works
Debug if something goes wrong
Points #2 and #3 are problematic since they often imply being able to run the code locally.
A far stronger and more sustainable alternative to that is to write tests as I go. I don’t have to be a TDD zealot to believe in the usefulness of writing tests. I can write tests before writing my code, or (horror of horrors) just after (no, really, it’s fine).
As long as I’m writing unit and integration tests along with my code, I don’t need to refresh the code in real time. And I don’t need to resort to the debugger if something isn’t behaving as expected.
Debugging Locally Is Not a Goal Worth Pursuing
If you're good at the debugger it means you spent a lot of time debugging. I don't want you to be good at the debugger. ~ Robert Martin
It’s not just a matter of personal preference. It’s not, simply, that I don’t love debugging but others do.
I believe that debugging is a bad practice. You debug (mostly) when you don’t have good test coverage.
Tests won’t catch all the issues, of course. When an issue arises, I have two choices:
Get stuck into debugging mode
Write a test case to reproduce the issue
As professional developers, we should train ourselves to always default to option 2.
Writing a test leaves a trace of what the issue was about and how I solved it. Moreover, should the same issue occur again in the future, the test case will (hopefully) catch it before it’s too late.
You get none of the above when you get deep into debugging.
What Does Cloud-Based Debugging Look Like
With serverless and cloud-based development, debugging is inevitably harder (at least in the traditional sense).
This is, in my view, an advancement.
We are forced to write more tests (especially integration tests) and this makes our applications more robust and maintainable over time.
What about those extreme situations where you just need to get stuck into the code? Centralised logs are the answer.
Using tools like Baselime (my favourite), DataDog, Epsagon, and others, you can search over all your logs, spanning through multiple components and services.
That should be rare though. And when it happens, it should lead to a conversation as to what can be done to ensure that, next time, we can simply use our tests to get to the bottom of it.
By the way, Baselime is super cool. If you haven’t tried it yet, reach out to my friend Boris and ask him to give you a tour. You’ll be blown away.