12 Practical Tips for Building Bug-Free Software
By Dennis Gurock, February 3rd, 2009
Has your software bugs? Of course it has, every software application that’s out there has bugs and bug-free software is a myth. But it’s still possible to greatly minimize bugs, security problems and errors in your application by following a few simple tips and techniques.
Some studies claim that up to 40% of system failures are caused by software bugs and that common memory and concurrency related bugs account for 60% of system vulnerabilities and security problems. Even if it were less in reality, reducing software bugs in your application is the best way to increase the stability, reliability and security of your software.
During the development of our logging tool SmartInspect, we used many techniques to keep the quality of our product high and the following list contains some of the techniques we use. So without further ado, here’s our list of 12 practical tips for building bug-free software (or at least software with fewer bugs):
1. Code Reviews
Four eyes see more than two. That’s why you should let other developers review your source code on a regular basis. Pair programming on the other hand, a technique where two developers write code together for longer periods, isn’t for everyone and is often not needed. But complicated, critical or security related code greatly benefits from code reviews and will improve your code quality a lot.
2. Beta Tests
Beta tests play an important role with keeping your software’s quality high. Although it often doesn’t make sense to release beta versions for minor updates, major releases with many changes greatly benefit from tests by end-users and customers. You can test your software as much as you want, if you cannot control the execution environment of the final product, chances are high that end-users will have issues with all the different computer configurations out there. Also make sure that your software has reached a high quality standard before releasing it to beta testers. You don’t want to waste the testers’ time by letting them find and report bugs that you already know about.
3. Automated Tests
Automated tests like unit tests or automated GUI tests can be used to verify the functionality of application modules, application programming interfaces (APIs) and user interfaces. You don’t have to be a test-driven development wizard to make good use of automated tests. Using unit tests for key parts of your application can go a long way towards building more reliable software. There are tons of unit testing frameworks, web and GUI testing tools out there that you can utilize.
4. Logging
Using log files or live logging during development and production usage is a useful technique to identify bugs, find concurrency problems and fix the root cause of application crashes. Advanced logging tools are also able to log entire objects, trace threads and offer rich viewer tools to monitor your application. Instead of writing yet another basic logging framework, you should give a proven and advanced library a try. Many open-source and even some commercial offerings have been released over the years, including our very own .NET, Java and Delphi logging tool SmartInspect.
5. Error Reporting
To find and resolve errors and exceptions, you first have to know what kind of errors your users and customers are experiencing. Most trial users won’t get in touch with you to report errors. Instead, they will just uninstall your application and test a competing product. To make error reporting for end-users easier and more useful to you, you should add automated error and exception reporting to your software. Desktop applications should show a friendly dialog offering the user an option to send an error report back to the developer every time an unhandled exception occurs. Hosted web applications can automatically send or log an error report without user interaction. Error reports should contain all the information you need to identify problems, including error messages, call stacks, version numbers and log files.
6. Customer Feedback
Similar to error reporting, you should make it as easy as possible for your users to provide feedback. In SmartInspect, for example, we have buttons in the menu and toolbars to send feedback and questions. You can also use a quick (optional) survey when a user uninstalls your application. Such a survey should only have a few questions and ask for a reason the user uninstalled your software. If a lot of users report that they uninstalled your software because of stability problems, you will know that your application isn’t as high-quality as you have thought.
7. Use Proven Code
You should build the core functionality and main features of your applications yourself, because only then are you able to easily and quickly modify and improve it. But for some parts of your application, reusing existing and proven code might make sense. For example, it would take years to build a stable, easy-to-use and feature-complete reporting engine if you have a need for it. In such cases it’s often better to use existing code, either from internal libraries, third-party companies or open source solutions if the license permits this. However, using a lot of third-party code can also have its downsides. It makes upgrades to new versions of your development platform harder, increases your dependencies on other people’s code and will most likely introduce bugs that are hard for you to fix, as you are not familiar with the code.
8. Dedicated Testers
If possible, you should have dedicated testers in your organization for quality assurance. In fact, you should probably have lots of them. For simple standard applications, one tester per developer is a good rule of thumb. For applications that are complicated and time-consuming to test, two or more testers per developer are more applicable. Many small organizations cannot afford dedicated testers. If this is the case, developers should test each others’ code. It’s important that others test your code and functionality, because general wisdom says that developers do a really bad job at testing software and functionality that they wrote themselves.
9. Virtualization
To test your software on all supported operating systems and software combinations, you can use virtualization tools such as VMware or Virtual PC. Besides allowing you to test your software on all kinds of configurations, you will save a lot of time because you can easily copy, share and reset the virtual machines. It’s a good idea to create a few base images for all the operating systems you regular test on and put them on a file server. When you need a new configuration to test something, you can then start with one of your base images without first installing the operating system, drivers and required software.
10. Design Your Software
Many software quality problems are caused by badly designed class hierarchies, inaccurate interfaces, wrongly understood requirements and resulting workarounds. That’s why you should design and plan key parts of a module or application before writing the first line of code. You should also refactor your code as needed if requirements change during the lifetime of a software application. Also make sure to update any documentation or specification you have, because there’s nothing more useless than outdated documentation.
11. Use a Good Debugger
If you use an IDE like Visual Studio, Eclipse or Delphi, you already have access to a powerful debugger that you should make use of. But with some programming languages such as PHP, Python and Ruby, many developers aren’t using a debugger but rely solely on print statements and logging. While logging is certainly useful (see above), it’s not a complete replacement for a debugger. Do yourself a favor and get a good debugger for your development platform that you can use to step through your code, set breakpoints and inspect variables. There’s a good debugger for almost every platform and language out there.
12. Debug and Strict Options
Many development environments allow you to enable special debugging options such as range checking, overflow checking and memory corruption checking. Such options should be enabled during development and sometimes even while testing your software, as it makes identifying some complicated bugs a lot easier. Most dynamic languages like Perl or PHP also allow you to enable certain rules and warnings to enforce variable declaration before using them. This is especially useful if a language is case-sensitive and it’s easy to make typos.
The above mentioned tips won’t make your software magically bug-free, but they allow you to make your software a lot more stable, reliable and usable if used correctly. And on top of it, they will make you a better developer, too.
This article is based on a posting I previously published on the Gurock Software blog. As the tips are still relevant I decided to republish it here.
