Every developer needs to debug sometimes. It's a fact of life as a developer. So how to make the problem tractable? How do we debug?There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. -- CAR Hoare
The best advice is to try to avoid debugging in the first place. It sounds rather trite, and essentially the opposite of what I said above, but in fact it is a very useful strategy.
The other part is that many of avoidance strategies can make bugs trivial to find. If you are going to have a bug (which you are) you may as well make it really easy to find.
This article then focuses on the steps that will help you build your software to be bug free, or at least so that the bugs can be easily found.
A common theme you will see below is that work up front will save you time later on.
Design
Draw the data structure, showing what references what. Now draw the things you are going to do with it? Remove a node from a linked list, draw the steps; find the node, then the predecessor, link the predecessor to the descendant etc..
Make sure you understand it. If you don't know in your head how every operation is going to work you will almost certainly make a design mistake or another error. Don't do that.
A bad design or misunderstanding will cost you more time then anything else on this list.
Simple Steps
You can easily reason about such a function. You can easily test such a function. You can understand if it is right or wrong very quickly.
Yes it takes more time to write lots of functions and document them and check the parameters and make sure there are no global vars in each. But it pays off quickly.
Testing
I listed simple steps above testing. But to be truthful, after a good design the next best thing is testing. The reason simple steps is above is because you want to write simple tests to check things are working.
Test everything. Write a test harness that allows you to quickly test a function with a range of values.
Then leave the tests there and keep writing more code. Then add more tests. Each time you add a function write some tests for it.
Then run all the tests.
Always run all the tests. Your standard build target should run your unit tests by default. Not manually.
Test simple functions. Break big functions into things that can be tested. Keep adding tests.
You can either write a simple harness for your self, or use something like check. The important thing is the tests are there and are run frequently.
If you have good tests you know that code is right. You don't need to debug it. If you do find a bug, you add a test and you will never have that bug again.
Structure
Structure comes from design so it's not a isolated property.
The hardest thing to debug is global state. It's hard to test, it's hard to reason about. That means it's hard to debug.
Avoid global state. Isolate and encapsulate. Functions should only be passed what they need. They should return simple structures or manipulate only arguments explicitly passed for manipulation.
No comments:
Post a Comment