Over the past few weeks, the news has been dominated by the coronavirus. I wrote about the topic last week, specifically about using alternative data to understand how to track the economic impact, and also appeared on Bloomberg TV to discuss it. In these times, punctuated by observance of hand washing, face masks etc. it can be difficult to think of anything else. Well, I can always think about burgers, but that’s probably for an entirely different article.
In this article I’ll endeavour to talk about bugs of a different type, those that afflict computer code. Computer bugs can cause all sorts of problems, and can be particularly dangerous in mission critical applications. We’ve all been on the receiving end of programs that crash, or code that appears to work, and seemingly give us odd results. A quick Google search will quickly reveal a few famous bugs, some of which had quite funny consequences (such as Bill Gates suffering the BSOD – blue screen of death – whilst demoing Windows in public) and some which were far more serious.
It’s clear, that ideally we want to be able to find as many bugs as possible before delivering code to users. What can a programmer do? A key part of the process, is obviously to write good code, that’s readable and understandable, and well designed. Well designed code that is modular and easy to modify is also likely to be less buggy. Code which is written in a single file, with weird dependencies everywhere is pretty much every programmers worst nightmare. Also use version control, so you can go back to previous incarnations of code easily (I’m pretty sure, everyone does this, these days!)
However, it isn’t sufficient to write “good code” as an abstract exercise. Another key part of it is to do unit testing. When I started university nearly 20 years ago, I have to admit I can’t remember hearing about unit testing. Maybe it might have been around, but it wasn’t something I heard of. These days, unit testing is much more common. Basically, it involves writing tests for your code, where you have inputs, and expected outputs. Every time you modify your code, you can re-run the tests and check if they pass. From experience, whenever, you “fix” a bug, it also time that another bug gets introduced elsewhere. Having lots of automated tests gives you piece of mind.
There’s lots of nice frameworks these days for doing unit tests for all sorts of languages. In Python I tend to use pytest. Writing test code (just like real code!) is a bit of an art. You want to test as much functionality as you can, and want them to run quickly. If it takes ages to run tests, you’ll probably run them less often, and it makes them less usable.
For older projects, I have to admit I didn’t do that many tests and it can be time consuming to add tests for existing code. These days, for newer projects and features, I try to write tests alongside when I write code, rather than leaving it towards the end. This way it can be integrated as part of the coding process and I find it easier. When it comes to the input data for tests, it’s always worth considering “edge” cases (eg. empty data or on boundaries), which can often break code.
Obviously, unit testing isn’t the only type of testing your code will need to go through. For example, you also have integration testing, when a new module is created, to see how it impacts existing modules. Lastly, there’s user acceptance testing (UAT), which involves actually giving the code to a sample of users for testing.
Unit tests won’t fix everything, but in my experience, coding with them in mind can make code more reliable and also actually makes the coding process more systematic and easier. In terms of the other bug dominating the news, the coronavirus, let’s hope we can conquer that soon.