54.

We discuss the crucial interdependence between effective debugging and effective development, highlight extreme programming development methods, and peek at the potential future of test-oriented languages.

Debugging as Scientific Experiment

To debug software is to perform a type of scientific experiment. (This topic is explored in detail in Chapter 5.) And just as scientific experiments are best done in a laboratory environment, with controlled procedures and equipment, debugging software is best done as part of an integrated method of software development. Indeed, an appropriate method of development can easily help prevent many bugs from ever occurring in the first place.

Even when bugs are found, the development method can make a big difference in how quickly a bug can be diagnosed. As you might have guessed, I strongly advocate extreme programming as a particularly effective development method when you want to diagnose bugs quickly. And who doesn't want to find and dispose of bugs quickly?

Let's talk specifically about how extreme programming facilitates the debugging process. Although a thorough introduction to extreme programming is beyond the scope of this text (see the Resources chapter for some good references), I have found the following aspects of XP to be quite useful in debugging:

  • Software is specified, integrated, and released incrementally.

  • Design is kept as simple as possible.

  • Programming is done in pairs.

  • An on-site customer is always available.

  • Code is owned by all developers.

  • Tests exist for "anything that could possibly break."

How do each of these practices help in debugging software? Let's see.

Software is specified, integrated, and released incrementally

In extreme programming, each aspect of the functionality is specified just before it is implemented. A pair of programmers will then work on implementing that aspect for a couple of weeks or less (remember, it's just a small bit of functionality), and then release the new version. Along the way, they will integrate the work they've done thus far into the system, ensuring that all the tests they wrote and the tests everyone else wrote still pass.

In this way, any bugs that are introduced have a very good chance of being caught right away by the unit tests. Additionally, since implementation is incremental, the programmers will be wholly focused at each integration on making sure that one small piece of new functionality works.

Why do it? Catch bugs as they're introduced; focus is on a single, small bit of functionality.

Design is kept as simple as possible

Complexity is the enemy of robustness. If there is one aspect of software construction that laymen find most puzzling, it's that good programmers treat complexity like an unwanted weed, rooting it out to the extent possible. Why? Because programmers know that software systems are often used much longer than anyone expects, in contexts never anticipated, growing larger and larger all the while. Unless complexity is actively resisted, it'll quickly overtake a project.

Extreme programming continually strives to keep the system as simple as possible. Collective code ownership and constant refactoring (facilitated by the heavy use of unit tests) help to keep the code simple. Of course, that helps to prevent bugs from being written in the first place. But it also helps debugging; the simpler a program is, the fewer possibilities have to be considered as potential causes of a bug.

Why do it? Simpler code means less potential causes for a bug.

Tip 

Complexity is the enemy of robustness.

Programming is done in pairs

In extreme programming, all programming is done in pairs. Partners take turns driving at the keyboard. The partner who isn't driving is navigating-that is, inspecting the code as it's written, considering the big picture, and determining if there's a better way to do things. In essence, the navigator performs a continuous code review.

The motivation behind pair programming is that the act of coding involves simultaneously considering high-level aspects of a program, such as encapsulation and abstraction, and thinking about low-level aspects, such as syntax, argument order, etc. By using two people, we can distribute this cognitive burden more effectively.

Believe it or not, two programmers working together can be just as efficient (or even more efficient) than the same two programmers would be if working separately. At first, that sounds absurd. Since they're both working on just one task, as opposed to the two they'd work on separately, we would expect that productivity would be cut in half. But, as amazing as it sounds, time and time again pair programming increases overall productivity.

No doubt there are many reasons why pair programming is so efficient, but there's one that anyone who has ever debugged a program can appreciate. Consider the most common form of bug introduced in a program: a typo or syntax error. Even when these bugs are caught by static type checking, it takes time to go through the tedious cycle of compile, fix, compile, etc. The navigator will prevent many such typos from making it to the compile stage. This alone can save a surprising amount of time. But the real time savings occurs when the navigator discovers a typo that actually would have made it past static checking. In those cases, tracking down the bug can involve a substantial amount of cognitive effort and time (often several hours). If the navigator finds just two such bugs in a four-hour pairing session, the pairing will have paid for itself. After that, any further time savings is in the black.

Why do it? Divides thinking about highand low-level issues; increases person-hour productivity; provides backup on error introduction.

An on-site customer is always available

In contexts in which requirements are ambiguous and changing frequently, having a live customer available to ask questions is extremely helpful. It can often prevent developers from wasting precious time guessing how the customers would like some functionality to be implemented, only to discover that they were completely wrong.

In the context of effective debugging, the important aspect here is that the programmers are getting continuous feedback from someone who is actively using the product, and the more people using it, the better. Inevitably, these users will discover bugs that escaped even the most thorough test suite. As always, the sooner a bug is discovered, the easier it is to fix.

Why do it? Provides active user/client feedback.

Code is owned by all developers

When all programmers have the authority to refactor the code written by any programmer on the team, they tend to become more familiar with that code. Extreme programming involves not just collective ownership of code, but uniform coding standards and constant refactoring. When programmers are given the authority to review and improve all code in the project, they naturally become more familiar with the code they didn't write. This facilitates effective debugging in several respects.

Most obviously, they will be much better able to debug each other's code, since they'll understand it better. But they will also be less likely to blame a bug on code they didn't write. Humans tend to be suspicious of things they're unfamiliar with. That's a great survival trait when deciding which wild plants to eat, but it's deadly when debugging software. Programmers place blame all too often on anything but their own code. Collective code ownership ameliorates this phenomenon.

Why do it? Increases familiarity of all code for all programmers; lessens time spent blaming "foreign" code.

Tests exist for "anything that could possibly break"

In extreme programming, programmers write tests for functionality even before they start implementing that functionality, and they continue writing tests as they finish implementing it. Every time a programming pair integrates their code, all tests are run to ensure that the new code doesn't break anything. As mentioned previously in Chapter 2, unit tests form part of the specification of a program and they help prevent the members of a programming team from breaking each other's code. And since unit tests are run every time new code is integrated, they help to catch many bugs as soon as they're introduced. Even in cases where a bug isn't detected until long after it was introduced, the unit tests help programmers to eliminate many possible causes of the erroneous behavior and diagnose the cause of the problem quickly.

What does it mean to say "test anything that could possibly break"? Any method with a non-trivial body should be tested. Getters and setters on the other hand may not require testing since they are trivial and utterly fail to work if they are mistyped.

Why do it? It ensures that new functionality is consistent with existing functionality.

Taken together, these concepts make up a very powerful environment for debugging software. In fact, I've found that bugs resulting from mere typos can be virtually eliminated with extreme programming. An effective development method is the single most important quality of an effective debugging strategy.



Bug Patterns in Java
Bug Patterns In Java
ISBN: 1590590619
EAN: 2147483647
Year: N/A
Pages: 95
Authors: Eric Allen

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net