Some Attitude Issues

One of the major themes of this chapter is that attitude is everything when it comes to writing zero-defect code. Developers aren't stupid, and they can write solid code when given the opportunity. Provided with a clear and unambiguous set of targets, developers are usually highly motivated and very effective at meeting those targets. If management sets a crystal-clear target of zero-defect code and then does everything sensible to encourage attitudes aimed at fulfilling that target, the probability is that the code produced by the team will have few defects. So given the goal of writing zero-defect code, let's look at some of the attitudes that are required.

Swallowing a Rhinoceros Sideways

The stark truth is that there is no such thing as zero-defect software. The joke definition passed down from generation to generation (a generation in IS being maybe 18 months or so) expresses it nicely: "Zero defects [noun]: The result of shutting down a production line." Most real-life programs contain at least a few bugs simply because writing bug-free code is so difficult. As one of my clients likes to remind me, if writing solid code were easy, everybody would be doing it. He also claims that writing flaky code is much easier—which might account for the large quantity of it generally available.

Having said this, it is really part of every professional developer's job to aim at writing bug-free code. Knowing that bugs are inevitable is no excuse for any attitude that allows them the slightest breathing space. It's all in the approach. Professional programmers know that their code is going to contain bugs, so they bench-test it, run it through the debugger, and generally hammer it every way they can to catch the problems that they know are lurking in there somewhere. If you watch the average hacker at work, you'll notice something interesting. As soon as said hacker is convinced that his program is working to his satisfaction, he stops working, leans back in his chair, shouts to his boss that he's ready to perform a production release, and then heads for the soda machine. He's happy that he has spent some considerable time trying to show that his program is correct. Now fast-forward this hacker a few years, to the point where he has become more cynical and learned much more about the art of programming. What do you see? After reaching the stage at which he used to quit, he promptly starts working again. This time, he's trying something different—rather than prove his program is correct, he's trying to prove that it's incorrect.

Perhaps one of the major differences between amateur and professional developers is that amateurs are satisfied to show that their programs appear to be bug-free, whereas professionals prefer to try showing that their programs still contain bugs. Most amateurs haven't had enough experience to realize that when they believe their program is working correctly, they are perhaps only halfway through the development process. After they've done their best to prove a negative (that their code doesn't have any bugs), they need to spend some time trying to show the opposite.

One very useful if somewhat controversial technique for estimating the number of bugs still remaining in an application is called defect seeding. Before performing extensive quality assurance or user acceptance tests, one development group deliberately seeds the application code with a set of documented defects. These defects should cover the entire functionality of the application, and range from fatal to cosmetic, just as in real life. At the point when you estimate that the testing process is near completion, given the ratio of the number of seeded defects detected to the total number of defects seeded, you can calculate the approximate number of bugs in the application by using the following formula:

    D0 = (D1 / D2) * D3 

D1 is the total number of seeded defects, D2 is the number of seeded defects found so far, and D3 is the number of real (i.e. non-seeded) defects found so far. The resulting figure of D0 is therefore the total number of defects in the application, and D0 minus D3 will give you the approximate number of real defects that still haven't been located.

Beware of forgetting to remove the seeded defects, or of introducing new problems when removing them. If possible, keep the seeded defect code encapsulated and thus easy to remove from the programs.

Some final thoughts Find developers who are intelligent, knowledgeable, willing to learn, and good at delivering effective code. Find out whether they are also aware that writing bug-free code is so difficult that they must do everything possible to prevent and detect bugs. Don't hire them without this final magical factor. It's true that the first four qualities are all wonderful, but they are meaningless without this last one.

Looping the Loop

One of the most effective ways of restraining soaring bug rates is to attack the problem at its source—the programmer. Programmers have always known about the huge gap between the quality of code produced by the best and by the worst programmers. Industry surveys have verified this folklore by showing that the least effective developers in an organization produce more than twenty times the number of bugs that the most effective developers produce. It follows that an organization would benefit if its better programmers produced the majority of new code. With that in mind, some corporations have introduced the simple but revolutionary idea that programmers have to fix their own bugs—and have to fix them as soon as they are found.

This sets up what engineers call a negative feedback loop, otherwise known as evolution in action. The more bugs a programmer produces, the more time he or she is required to spend fixing those bugs. At least four benefits rapidly become apparent:

  1. The more bugs a programmer produces, the less chance he or she has of working on new code and thereby introducing new bugs. Instead, the better programmers (judged by bug rate) get to write all the new code, which is therefore likely to have less bugs.

  2. Programmers soon learn that writing buggy code is counterproductive. They aren't able to escape from the bugs they've introduced, so they begin to understand that writing solid code on the first pass is more effective and less wasteful of time than having to go back to old code, often several times in succession.

  3. Bug-prone developers start to gain some insights into what it's like to maintain their own code. This awareness can have a salutary effect on their design and coding habits. Seeing exactly how difficult it is to test that extremely clever but error-prone algorithm teaches them to sympathize more with the maintenance programmers.

  4. The software being written has very few known bugs at any time because the bugs are being fixed as soon as they're found. Runaway bug lists are stomped before they can gather any momentum. And the software is always at a point where it can be shipped almost immediately. It might not have all the features originally requested or envisioned, but those features that do exist will contain only a small number of known bugs. This ability to ship at any point in the life of a project can be very useful in today's fast-changing business world.

Some people might consider this type of feedback loop as a sort of punishment. If it does qualify as such, it's an extremely neutral punishment. What tends to happen is that the developers start to see it as a learning process. With management setting and then enforcing quality standards with this particular negative feedback loop, developers learn that producing bug-free code is very important. And like most highly motivated personalities, they soon adapt their working habits to whatever standard is set. No real crime and punishment occurs here; the process is entirely objective. If you create a bug, you have to fix it, and you have to fix it immediately. This process should become laborious enough that it teaches developers how to prevent that type of bug in the future or how to detect that type of bug once it has been introduced.

Some final thoughts Set a zero-defect standard and introduce processes that emphasize the importance of that standard. If management is seen to concentrate on the issue of preventing bugs, developers will respond with better practices and less defects.

Back to School

Although Visual Basic 6 is certainly not the rottweiler on speed that C++ and the Microsoft Foundation Classes (MFC) can be, there is no doubt that its increased power and size come with their own dangers. Visual Basic 6 has many powerful features, and these take a while to learn. Because the language is so big, a typical developer might use only 10 percent or even less of its features in the year he or she takes to write perhaps three or four applications. It has become increasingly hard to achieve expertise in such a large and complex language. So it is perhaps no surprise to find that many bugs stem from a misunderstanding of how Visual Basic implements a particular feature.

I'll demonstrate this premise with a fairly trivial example. An examination of the following function will reveal nothing obviously unsafe. Multiplying the two maximum possible function arguments that could be received (32767 * 32767) will never produce a result bigger than can be stored in the long variable that this function returns.

 Private Function BonusCalc(ByVal niNumberOfWeeks As Integer, _     ByVal niWeeklyBonus As Integer) As Long BonusCalc = niNumberOfWeeks * niWeeklyBonus End Function 

Now if you happened to be diligent enough to receive a weekly bonus of $1,000 over a period of 35 weeks…well, let's just say that this particular function wouldn't deliver your expected bonus! Although the function looks safe enough, Visual Basic's intermediate calculations behind the scenes cause trouble. When multiplying the two integers together, Visual Basic attempts to store the temporary result into another integer before assigning it to BonusCalc. This, of course, causes an immediate overflow error. What you have to do instead is give the Visual Basic compiler some assistance. The following revised statement works because Visual Basic realizes that we might be dealing with longs rather than just integers:

 BonusCalc = niNumberOfWeeks * CLng(niWeeklyBonus) 

Dealing with these sorts of language quirks is not easy. Programmers are often pushed for time, so they sometimes tend to avoid experimenting with a feature to see how it really works in detail. For the same reasons, reading the manuals or online help is often confined to a hasty glance just to confirm syntax. These are false economies. Even given the fact that sections of some manuals appear to have been written by Urdu swineherders on some very heavy medication, those pages still contain many pearls. When you use something in Visual Basic 6 for the first time, take a few minutes to read about its subtleties in the documentation and write a short program to experiment with its implementation. Use it in several different ways within a program, and twist it into funny shapes. Find out what it can and can't handle.

Some final thoughts Professional developers should understand the tools at their disposal at a detailed level. Learn from the manual how the tools should work, and then go beyond the manual and find out how they really work.

Yet More Schoolwork

Visual Basic 4 introduced the concept of object-oriented programming using the Basic language. Visual Basic 5 and 6 take this concept and elaborate on it in several ways. It is still possible to write Visual Basic 6 code that looks almost exactly like Visual Basic 3 code or that even resembles procedural COBOL code (if you are intent upon imitating a dinosaur). The modern emphasis, however, is on the use of relatively new ideas in Basic, such as abstraction and encapsulation, which aim to make applications easier to develop, understand, and maintain. Any Visual Basic developer unfamiliar with these ideas first has to learn what they are and why they are useful and then has to understand all the quirks of their implementation in Visual Basic 6. The learning curve is not trivial. For example, understanding how the Implements statement produces a virtual class that is Visual Basic 6's way of implementing polymorphism (and inheritance if you're a little sneaky) can require some structural remodeling of one's thought processes. This is heavy-duty object-oriented programming in the 1990s style. Trying to use it in a production environment without a clear understanding is a prime cause of new and unexpected bugs.

Developers faced with radically new concepts usually go through up to four stages of enlightenment. The first stage has to do with reading and absorbing the theory behind the concept. The second stage includes working with either code examples or actual programs written by other people that implement the new concept. The third stage involves using the new concept in their own code. Only at this point do programmers become fully aware of the subtleties involved and understand how not to write their code. The final stage of enlightenment arrives when the programmer learns how to implement the concept correctly, leaving no holes for the bugs to crawl through.

Some final thoughts Developers should take all the time necessary to reach the third and fourth stages of enlightenment when learning new programming concepts or methodologies. Only then should they be allowed to implement these new ideas in production systems.

Eating Humble Pie

Most developers are continually surprised to find out how fallible they are and how difficult it is to be precise about even simple processes. The human brain is evidently not well equipped to deal with problems that require great precision to solve. It's not the actual complexity but the type of complexity that defeats us. Evolution has been successful in giving us some very sophisticated pattern-recognition algorithms and heuristics to deal with certain types of complexity. A classic example is our visual ability to recognize a human face even when seen at an angle or in lighting conditions never experienced before. Your ability to remember and compare patterns means that you can recognize your mother or father in circumstances that would completely defeat a computer program. Lacking your ability to recognize and compare patterns intelligently, the program instead has to use a brute-force approach, applying a very different type of intelligence to a potentially huge number of possibilities.

As successful as we are at handling some sorts of complexity, the complexity involved in programming computers is a different matter. The requirement is no longer to compare patterns in a holistic, or all-around, fashion but instead to be very precise about the comparison. In a section of program code, a single misplaced character, such as "+" instead of "&," can produce a nasty defect that often cannot be easily spotted because its cause is so small. So we have to watch our p's and q's very carefully, retaining our ability to look at the big picture while also ensuring that every tiny detail of the picture is correct. This endless attention to detail is not something at which the human brain is very efficient. Surrounded by a large number of potential bugs, we can sometimes struggle to maintain what often feels like a very precarious balance in our programs.

A programmer employed by my company came to me with a bug that he had found impossible to locate. When I looked at the suspect class module, the first thing I noticed was that one of the variables hadn't been declared before being used. Like every conscientious Visual Basic developer, he had set Require Variable Declaration in his Integrated Development Environment (IDE) to warn him about this type of problem. But in a classic case of programming oversight, he had made the perfectly reasonable assumption that setting this option meant that all undeclared variables are always recognized and stomped on. Unfortunately, it applies only to new modules developed from the point at which the flag is set. Any modules written within one developer's IDE and then imported into another programmer's IDE are never checked for undeclared variables unless that first developer also specified Require Variable Declaration. This is obvious when you realize how the option functions. It simply inserts Option Explicit at the top of each module when it is first created. What it doesn't do is act globally on all modules. This point is easy to recognize when you stop and think for a moment, but it's also very easy to miss.

Some final thoughts Learn to be humble when programming. This stuff is seriously nontrivial (a fancy term for swallowing a rhinoceros sideways), and arrogance when you're trying to write stable code is counterproductive.

Jumping Out of The Loop

One psychological factor responsible for producing bugs and preventing their detection is an inability to jump from one mind-set to another.In our push to examine subtle details, we often overlook the obvious. The results of a study performed a decade ago showed that that 50 percent of all errors plainly visible on a screen or report were still overlooked by the programmer. The kind of mistake shown in the preceding sentence ("that" repeated) seems fairly obvious in retrospect, but did you spot it the first time through?

One reason for this tendency to overlook the obvious is that the mind-set required to find gross errors is so different from the mind-set needed to locate subtle errors that it is hard to switch between the two. We've all been in the situation in which the cause of a bug eludes us for hours, but as soon as we explain the problem to another programmer, the cause of the error immediately becomes obvious. Often in this type of confessional programming, the other developer doesn't have to say a word, just nod wisely. The mental switch from an internal monologue to an external one is sometimes all that we need to force us into a different mind-set, and we can then reevaluate our assumptions about what is happening in the code. Like one of those infuriating Magic Eye pictures, the change of focus means that what was hidden before suddenly becomes clear.

Some final thoughts If you're stuck on a particularly nasty bug, try some lateral thinking. Use confessional programming—explain the problem to a colleague. Perhaps take a walk to get some fresh air. Work on something entirely different for a few minutes, returning later with a clearer mind for the problem. Or you can go so far as to picture yourself jumping out of that mental loop, reaching a different level of thought. All of these techniques can help you avoid endlessly traversing the same mental pathways.



Ltd Mandelbrot Set International Advanced Microsoft Visual Basics 6. 0
Advanced Microsoft Visual Basic (Mps)
ISBN: 1572318937
EAN: 2147483647
Year: 1997
Pages: 168

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