No one's perfect, and no matter what we do, we are going to produce code that has bugs in it from time to time. What are some methods/techniques for reducing the number of bugs you produce, both when writing new software and changing/maintaining existing code?
|
Avoid fancy coding. The more complicated the code, the more likely there's bugs. Usually on modern systems, clearly written code will be fast and small enough. Use available libraries. The easiest way to not have bugs writing a utility routine is to not write it. Learn a few formal techniques for the more complicated stuff. If there's complicated conditions, nail them down with pen and paper. Ideally, know some proof techniques. If I can prove code correct, it's almost always good except for big, dumb, obvious bugs that are easy to fix. Obviously, this only goes so far, but sometimes you can formally reason about small but complicated things. For existing code, learn how to refactor: how to make small changes in the code, often using an automated tool, that make the code more readable without changing the behavior. Don't do anything too quickly. Taking a little time up front to do things right, to check what you've done, and to think about what you're doing can pay off big time later. Once you've written the code, use what you've got to make it good. Unit tests are great. You can often write tests ahead of time, which can be great feedback (if done consistently, this is test-driven development). Compile with warning options, and pay attention to the warnings. Get somebody else to look at the code. Formal code reviews are good, but they may not be at a convenient time. |
|||||||||
|
|
Use code inspection tools like ReSharper or IDEs like IntelliJ IDEA that warn about many copy-and-paste bugs and others by e.g. pointing out variables that "are written to, but never read". Has saved me a lot of time. |
||||
|
|
|
A lot of good answers here, but a few things I wanted to add. Make sure you actually understand the requirement. I've seen lots of bugs when the user thought the requirement meant X and the programmer thought it meant Y. Push back for clarification on poor or ambiguous requirements. I know we all like to jump in and code but the more time spent up front ensuring understanding, the less rework and bug fixing there will be. Get to know the business you are supporting, you will often see things in requirements that are missing or need further explanation then. Know that if you do task Y as stated, it will break existing feature Z. Understand your database structure. Many many bugs are as a result of a query that is syntactically correct, but returns the wrong results. Learn how to recognize when your results look funny. If I am writing a complex reporting query, I always get a technical specialist to review my results before I mark it as ready to go, they will inevitably see something in the data I missed. Then make notes to yourself what they caught that you didn't and remember that the next time you do something simliar. |
||||
|
|
|
I follow the practice of Test-Code-Test instead of Code-test-code-test. This helps me to think of use-cases and appropriately frame the logic |
||||
|
|
|
I think the most important technique is take your time. If you feel you need two days to code a new module, but you boss force you to code only in one day... your code will be probable more buggy. One of the books I read some time ago, said that you shouldn't live with broken windows, because people won't care if anotherone gets broken... Coding is the same, everyone will care about being the first in doing something bad but fast, but none will care about one hell code, with lots of bugs, and very poor design and style. |
||||
|
|
|
A little less technical answer: don't program when you are tired (9h/day are enough), drunk or 'baked'. When I'm tired I don't have the required patience to write clean code. |
|||||
|
|
Merge multiple bugs into one bug? |
|||||
|
|
Code inspection or other forms of peer review such as pair programming. Structured code reviews such as Fagan inspection can be at least as effective and efficient as unit testing and has even proved to be better than unit testing in some cases. Inspections can also be used earlier in the software lifecycle and with artifacts other than code. Peer Reviews in Software by Karl Wiegers is a great book on this subject. |
||||
|
|
|
|||||||||
|
|
I've developed a fairly functional style of programming, despite my primary languages being C++ and Python. I found that if I pass all of the context to a function (or method) that that function needs to do its job, and return the meaningful data that I'm looking for, that my code has become much more robust. Implicit state is the enemy and in my experience is the #1 source of bugs. This state can be global variables or member variables, but if results are dependent on something that's not passed to the function you're asking for trouble. Clearly it is not feasible to eliminate state, but minimizing it has huge positive effects on program reliability. I also like to tell my coworkers that every branch (if, for, while, ?:) is a likely bug. I can't say what the manifestation of the bug will be, but the less conditional behavior your code has, the more likely it is to be bug free simply due to the fact that the code coverage during execution will be more consistent. Go figure, all of these things also have positive effects on performance too. Win! |
||||
|
|
|
Some great answers here regarding unit testing and tools. The only thing I can add to them is this: Involve your testers as early as you can If you have a test team, don't fall into the trap of treating them as the gatekeepers for your code quality and catching your defects for you. Instead, work with them and involve them as early as possible (on agile projects this will be from the project's beginning, but we can always find ways to involve them earlier if we really try).
Having a good working relationship with your testers means that you can catch poor assumptions and defects really early on, before they can do any damage. It also means that the testers feel empowered to help with the product design and catch usability issues when there is time to fix them. |
||||
|
|
|
In addition to all of the other suggestions here, turn on all possible warnings to the highest level of sensitivity, and treat them as errors. Also use any linting tools the language has. You would be amazed at how many simple mistakes can be caught by warnings and how many of those simple things translate into real bugs in your code. |
||||
|
|
|
In addition to what's been mentioned:
Lots of other things I'm forgetting at the moment, but the others will surely think of them. :) |
|||||
|
|
Static Analysis Tools Plugins and apps like FindBugs crawl your code and find places where there are potential bugs. Places where variables aren't initialized and used or just crazy things that 9 times out of 10, make it way easier for bugs to arise. Tools like this help me prevent my bonehead moves down the road even if it's not a bug yet. P.S.: Remember to always research why a tool tells you something is bad. Never hurts to learn (and not everything is right in all situations). |
||||
|
|
|
+1 on both of the unit test comments. Beyond that, set the highest warning level your compiler offers, and make sure warnings are treated as errors. Bugs often hide in those "erroneous" errors. Similarly, invest in static analysis tools that run at compile time (I view these as an extra level of compiler warnings). |
||||
|
|
|
Unit Tests let you reduce the number of bugs that pop up a second time. If you find a bug in your code, writing a unit test will make sure it doesn't come back up later. (Plus, thinking of all the cases and writing thousands of unit tests up front is hard to get done sometimes) |
|||||||||||||
|