Having some bugs in code is inevitable, and even normal: the average bug frequency is estimated to be between “15 and 50 per 1000 lines of delivered code.” If you have code that’s hard to maintain, however, or find yourself spending more time you’d like tracking down bugs, there are a few steps you can take now to start writing cleaner code.
Take your time
One of the most common reasons for buggy code is rushing as you write it—and with the tight deadlines in a typical sprint, this makes sense. If you throw in something that “works” now but isn’t a good long-term solution, however, you’re probably not going to go back and fix it until you have to, and by then it will take longer to address. The technical debt and associated bugs that will pile up will come back to haunt you. Instead, try to consider the wider goals of your project and think about the potential implications of what you’re about to write: How does my code impact the application? Is the implementation readable and easy to understand? What will this code depend on and what will depend on it, now or in the future? How much have I considered the user?
Taking 15 minutes at the start of your project (or the start of your session) to plan out the potential repercussions of what you’re about to do, however, makes a big difference in the long-term ease of working with your code. Planning next steps under deadline pressure is better than debugging under deadline pressure—and a lot better than realizing you’ve shipped buggy code to a client.
Learn formal methods for proving your code’s behavior
One useful debugging technique that will also help you write clearer code to begin with is learning how to use formal logic to prove that your code actually does what you want it to. Formal verification forces you to understand the problem you’re trying to solve, and helps you do so efficiently. Some resources for teaching yourself (or others) the basics can be found here.
You might also find that this helps you simplify the code you’re writing, which is less likely to result in bugs (and much easier to debug if there are issues) than more complex code.
Document as you go
You should assume your code will eventually need to be interpreted and modified by other people (even if this is just “future you”). To make it easier for them to understand what it’s supposed to do when they refactor or add to it, write clear comments about the intended function of each unit of code.
Start testing earlier
Unit tests are one of the best defenses against convoluted code and hidden bugs. If you start testing as you write new code, you’ll be more likely to catch a mistake in a section of the code you’re currently working on, which places a much smaller cognitive load on you than returning to something you last touched weeks ago. Having tests for an entire codebase also makes it easier to locate problems and changes in seemingly unrelated bits of code you may have never seen before.
Testing tools can assist with this, and save a lot of time. Diffblue Cover, for example, actually uses formal verification techniques as mentioned above (in combination with other methods) to automatically create unit tests for code many times faster than a person could. Having a wide net of these regression unit tests makes it easier to catch regressions before integrating potentially buggy code.
With a bit of practice following these tips, you should be able to develop good habits that will serve you, your code, and your team well.