Chapter 8. Defensive Programming

If you take care of the small things, the big things take care of themselves.

Anonymous

Defensive programming is a coding style that proactively prevents problems. As a coding practice, defensive programming is an amalgamation of small goals such as writing readable code, proper naming conventions, checking the return value of all functions, and employing design patterns. With defensive programming, it is all about the details. The bottom up approach makes the overall application more robust, correct, and extensible. Candidly, defensive programming consists mostly of common sense practices. For example, look at the following expression:

price=price*1.05;

The previous code statement has a simple problem. It is not fully readable and is an example of poor programming practice and a common sense problem. The problem is the literal 1.05. What is the context of this number? The number 1.05 could be a price increase, taxes, service charges, or even royalties. The context of the literal is important. Without that understanding, a maintenance programmer could improperly change the formula or use the results incorrectly. Literals, as used in the above formula, are difficult to optimize. That is the second problem. The following code is an excellent example of defensive programming. It corrects both concerns and is an example of self-documenting code.

price=price*priceIncrease;

Programs do not inherently have problems. A correct program is correct tomorrow, next week, and into subsequent years. What introduces code problems, now and in the future, are developers. Correct code requires programmer discipline. Defensive programming is a set of coding standards that apply a consistent programmer discipline for creating correct code. In many cases, defensive programming prevents future problems of the inadvertent nature. Look at the following code:

if(a>5)
    a+=5;

The truth condition of the preceding if statement is a single statement (a+=5;). Defensive programming dictates placing that statement in a code block. It is not compelling but nonetheless important. If not, someone might add a second statement to the truth condition and forget the block. The code would still compile. However, you have now introduced a subtle bug to the application. Rigorous testing would hopefully, but may not, uncover the problem.

This is one example of the detail that constitutes defensive programming. Here is the corrected code:

if(a>5) {
    a+=5;
}

Defensive programming starts with reasonable deadlines. You must have time to think about programming. The belief that writing coding is an entirely technical process is a myth. Great programmers are creative and require time for analysis and innovation. Short deadlines leave less time to think and be creative. Consider adding a task called "Thinking" to your project plan. To avoid raising eyebrows with management, call the task something inventive, such as Cerebral Exploration of Future Profits through Solid Applications, or simply Playing the Xbox in the Employee Lounge.

Defensive programming tends to add code to your application. But what is the objective of product development: fewer lines of code or correct code—particularly if performance is not measurably different? Regardless, I would attest that customers prefer correct code over a suspect application that performs a nanosecond quicker.

"Assume the worst case scenario in all circumstances" is an important tenet of defensive programming. The worst problems occur when developers assume otherwise. Code as if anything is possible. For example, always code the default case in a switch statement, even if the probability is remote. In the worst case scenario, the error handling in the default case is never used. In the best case scenario, you handled a future problem correctly.

Defensive Programming and C#

C# was designed with defensive programming in mind. C++ is akin to the wild wild West, where literally anything goes. Developers have enormous flexibility in C++, which is both good and bad. Developers are given plenty of rope. You know what some people can do with a long rope. C# has attempted to rein in the freewheeling environment of C++. For this reason, developers can focus mostly on resolving business problems and less time wrestling with the nuances of the language. The assignment problem is a perfect example of this. In C++, the following code is valid:

int a=5;
if(a)
{
        // Do whatever
}

In C++, true is a non-zero value, and false is zero. This means an integral value can be substituted as a Boolean value in expressions, as shown previously. Using an integer value for a Boolean accords considerable flexibility but can also result in an error if done incorrectly. One reason is that developers often forget the rules. The definition of true and false varies between languages, which can cause confusion for even experienced developers. In addition, the code is not very readable. In C#, Boolean expressions are limited to Boolean values (true or false), which is clearer. Clarity prevents potential problems. This is an example of a rule that forces defensive programming in C#.

Here is another example. The following code is allowed in C++. A transfer of control statement, such as a break statement, is not required with each case statement. For that reason, the following code is a nifty way to calculate a factorial. C# expects transfer control statements between each case statement and would not compile similar code. Why? Omitting the break statement in a switch block is a common C++ error. Preventing this error in C# is a form of defensive programming.

int factorial=5;
int result=1;
switch(factorial){
    case 5: result*=factorial--;
    case 4:result*=factorial--;
    case 3:result*=factorial--;
    case 2:result*=factorial--;
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.149.248.0