Spiria logo.

Debugging Superpowers

July 4, 2019.

Do you use Typescript with Node and Express? Ivan Djokic explains his debugging strategy, one that makes him a superhero:

Console logging is the worst. Some may disagree with my assessment of this handy tool, but I feel that it’s too often used as a crutch, despite the existence of better debugging tools and methods.

Here is where I’m coming from: my first professional programming language was Python. I spent five-and-a-half years of my career developing Python/Django applications, and one of my favorite things about working in this environment was a tool called PDB, the Python Debugger.

In my opinion, this tool is a junior developer’s dream come true. At any point, I could stop my program and inspect its current state; I could see the lifecycle of variables; I could see and follow the stack of functions and methods as they were called. Thanks to this tool, I was able not only to solve bugs and issues more quickly, but also to learn from the process. I felt like I had X-ray vision. I felt like a superhero.

Fast forward a number of years, and I started working more and more with Javascript. Gone was my beloved debugger, but I quickly learned to use Chrome’s DevTools debugger and console. These tools satisfied all my debugging needs and allowed me to add breakpoints to my code easily and visually. I felt like a superhero once more.

In my current position at Spiria, the applications I work on are all in TypeScript. We use Node and Express in the back-end, with a React client-side app. On the client side, things are still fine. We use WebPack to transpile the TypeScript code, along with source-code mappings, and we’re able to debug it in Chrome as we always did. When it came to the back-end, however, the team was exclusively reliant on console logging for debugging purposes. Our development and debugging process consisted in making changes, adding a bunch of debugging logs, running through the code, then parsing the output log to try to get an idea of what happened. It was a cumbersome process which I felt generated more noise than insight. My X-ray vision was gone, and I felt like a superhero no more.

Furthermore, unlike in the front-end code, we had to manually run the command for the build process to transpile the back-end code. Also, the server process was not watching for changes and had to be restarted manually for it to acknowledge the latest transpiled code. After a few months of going along with the status quo, I felt increasingly bogged down with the process and yearned to have my superpowers back. Happily, I wasn’t the only one who felt this way and our team was lucky enough to be able to take the time to improve these processes.

While working on a project that happened to involve a large amount of back-end work, I improved our debugging process as best I could. The first step was to get proper debugging powers back. Luckily, Node comes with a --inspect flag that opens up a Websocket on a particular port, exposing the Node process for debugging. Chrome can hook into this and open an instance of its DevTools that works with Node; there are even handy extensions! I use one called Node Inspect Manager (NiM) to automatically open DevTools when a debugger is exposed to a predefined port. X-ray powers: check!

However, I was still unhappy with the process as a whole. Whenever I made changes to the code, I’d have to kill my server, re-build the server code and restart the server process. But this was also an easy fix. The TypeScript transpiler comes with a --watch flag that has it re-transpile every time it detects code changes. Magic shapeshifting: check!

Lastly, I wanted my server process to restart whenever it detected changes in the transpiled code. This was relatively easy as well, with a tool called Nodemon. It’s a light wrapper around Node that restarts the process when code changes are detected. It supports all the same flags as the Node command, so our debugging process was still in business. Super-speed: check!

Wow.

I definitely felt like a superhero again: I was able to write code efficiently and debug it on the fly. No longer did we have to do the legwork of re-building code and restarting processes manually. But there was still one thing that bugged me: I still had to run separate commands to watch for code changes and to start up Nodemon. Then I remembered a great little tool that I’d used in a past project, called npm-run-all, that can be used to run a number of separate scripts either serially or in parallel. Now, we enter one command, npm run watch:server, and the rest happens as if by magic.

Proper debugging processes are the foundation of any team. All developers, regardless of their experience, can learn much from properly inspecting their code and workflows. This results in better-running, bug-free apps that satisfy stakeholders and developers alike.

Wow.