Writing Quality Software: A Primer

development prracticesOkay, so you have a respectable handle on syntax, and you are proud of yourself for getting that far. And, truth be told, you should be. But, knowing syntax is not the same as mastering syntax in such a way that builds quick, efficient web software. This article takes a look at not just writing software, but writing quality software.

Okay, so you have a respectable handle on syntax, and you are proud of yourself for getting that far. And, truth be told, you should be. But, knowing syntax is not the same as mastering syntax in such a way that builds quick, efficient web software. This article takes a look at not just writing software, but writing quality software.

First, let’s take a look at what quality software includes:
  • Consistent and readable code format
  • Naming conventions
  • Appropriate comments
  • Unit tests
  • System tests

Admittedly, this list is not all-inclusive. If it were, this article would span hundreds of pages. Instead, this article looks at some of the more important quality concepts and I encourage you to dive further into these subjects with a few good books. The purpose of this article is to merely introduce you to writing truly masterful software. {mospagebreak title=Some General Quality Issues} Before we explore these issues, let’s take a real broad gander at what quality software is. First and foremost, quality software is correct; that is, it provides the functionality to satisfy requirements. In addition, a quality piece of software exhibits robustness. Can it withstand unusual and unexpected demands? Can it process incorrect data and display appropriate error messages on demand?

Quality software is also accurate. What is the difference between ‘correct’ and ‘accurate’? Accurate describes how error-free the software is. Does the for loop iterate 9 times instead of 10? If so, the code is not completely accurate. Another issue is platform compatibility. A quality piece of web software, for example, runs successfully on a variety of operating systems and under a diverse set of browsers.

From the programmer’s perspective, quality software is easy to maintain. That means the code is well documented and effortlessly understood. Correcting code errors or adding modules is an easy task under quality software. Further, code reuse creates quality software. Are your modules portable to other applications and can they function properly under a multitude of environments?

Quality software is accomplished through insidious code inspection, often in the form of code reviews by other programmers. Unit and system testing ensures the application’s correctness, and audits, for those organizations with appropriate resources, bring in outside perspectives to perfect code.

Goal setting is imperative to quality software. Is correctness your goal? If so, you may need to forgo other aspects, like robustness. If robustness is paramount, it is possible the application may become slightly less correct, to the ‘T’. Trade-offs need to be finalized before software construction; these can then be used to form a development consensus. {mospagebreak title=Consistent and Readable Code Format} Have you ever poked around in someone else’s code, only to find the entire document left aligned? Very readable? No, of course not. Learning effective code formatting makes the job of reading your code exponentially easier.

For example, take this block of code, a classic example of bad coding ethic:

for ($x=0;$x<=50;$x++) 
echo States[$x]; 
$Inc .= $Incrementor; 
if (($Inc == 9) || ($Inc == 10)) 
echo "Execute this line of code"; 

The above code block is not especially readable; from a glance, it is not immediately clear where control structures begin, which happen to be perfect places to indent. Control structures include for loops, if statements and select/case blocks. Let's try re-writing this piece of code, in a style more readable.

for ($x=0;$x<=50;$x++) 

    echo States[$x]; 
    $Inc .= $Incrementor; 

    if (($Inc == 9) || ($Inc == 10)) 
        echo "Execute this line of code"; 


More readable? Yes, I think so. Even at a quick glance, we can clearly determine where control structures are coded, because we have indented our code and spaced it accordingly. One of the first marks of a quality software application is a properly formatted source code document. Not only can we read our logic, we also clearly see our logic.

So, where should you indent your code? A good rule to keep in mind is always indent code within control structures, like loops (for, while, do...while), and within if statements. If you are using a language such as Pascal, indent variable/constant definition blocks and within Begin/End code structures. Further, always indent code within functions or procedures.

Also notice our use of white space. Developers are often afraid of white space because of increased program size; this is a mistake, however. Use white space liberally to give your code room to breathe. After all, you would not think of writing a business report without spacing between your words and paragraphs, right? Code follows similar logic.

I chose to surround my if statement with squiggly braces {} in the above code example, although I was technically not required to because my if statement only contained a single line of code. When in doubt, certainly use these squiggle braces, but consider using them anyway, even if you know they are not needed. These braces create a grouping effect that suggests particular code belongs together and, in the case of our if statement, execute only when that statement returns true.

Be careful about utilizing modern programming languages' ability to interpret multiple commands on a single line. When reading through code fast, we naturally assume each statement is afforded its own line. When two commands rest on the same line, it is easy for us to miss that second command. For the sake of clarity and readability, give each command its own line.

If you use comments in your code, be sure to indent those comments along with the indented source code. This again suggests grouping, and makes it clear which comments describe which commands. We will look at comments at more depth later in this article.

Many corporations put teeth into source code formatting, often insisting on a collection of strict guidelines for software construction. A set of guidelines that all internal programmers follow makes code inspections and unit testing easier to digest.

To wrap up, here's what you should have learned:
  • Always indent code within control structures
  • Utilize the benefits of white spaces
  • Use squiggly braces, even if not required
  • Place each command on a separate line
  • Indent comments with appropriate code
{mospagebreak title=Naming Conventions} An issue that many developers neglect is naming conventions. Some hasty programmers use the first word that comes to mind when naming variables, which hurts the intuitiveness of the application. Variable names need to accurately reflect the variable's purpose in life.

Let's take a look at some good and bad naming conventions, using PHP.

$A = 15 // Bad name 
$Age = 15 // Good name 

$P = 4 // Bad name 
$Perimeter = 4 // Good name 

$Date = "01/14/04" // Potentially good name 
$RetireDate = "01/14/04" // Better name 

Always use the shortest variable name that you can, while still maintaining the meaning of what the variable holds. Let's again look at a few examples.

$CircumferenceOfTheCircle = 4 // Name is too long 
$CircumCircle = 4 // Better name 

$MaximumPointsPossible = 100 // Name is too long 
$MaxPoints = 100 // Better name

Both $CircumCircle and $MaxPoints satisfy both of our examined criteria, (1) the variable name implies the value, and (2) the variable names are both concise. Try to avoid using words like 'the', and 'a' and other filler words within variable names, along with 'ing', 'ed', 'ies' etc. They violate both our criteria.

Also notice my use of capitalizations. It is often easier to read variables when using initial caps for each word. So, instead of $Maxpoints, I wrote $MaxPoints. Some programmers only capitalize the first letters of words other than the first, for example, $maxPoints. Either method works fine, although I prefer to initial cap each word, including the first.

Another method to naming your variables includes a reference to the datatype in the variable name. Although this does lengthen our variable, it does add understanding to what the variable should hold. Using this method, instead of declaring our "First name" variable $FirstName, we could declare it as $strFirstName. And, instead of declaring our Boolean variable "Success" $Success, use $bolSuccess.

How do we tell the difference between local and global variables? Unless they are declared within functions themselves, it may not be initially obvious. Consider tacking on g_ for global variables and f_ for function variables (or m_ for module variables). So, our global variable called $Multiplier could be renamed to read $g_Multiplier. This way, when other programmers read your code, or even when you read your code months from writing it, it is clearly understandable that g_Multiplier is a variable used globally, and you will look for such usage.

To wrap up, here's what you should have learned:
  • Choose specific, descriptive variable names
  • Keep variable names short
  • Avoid filler words, and be consistent with abbreviations
  • Consider including variable datatypes in names (strName)
  • With global variables, tack on g_, or function vars with f_ {mospagebreak title=Appropriately Commenting Your Code} Comments are a programmer's way of translating code into English, especially code that may not be directly intuitive. Comments seem to be a religious issue to some, often fought over with fierce potency and leading to lengthy debates. I happen to be in favor of comments, because good comments add transparency to the code and makes the job of reviews easier.

    Comments explain your syntax. They explain particularly lengthy or difficult to read code segments and can also be used to provide the programmer with reminder messages about why he or she chose to code the loop this way instead of that way. They also serve as markers in the code, which are generally taken out later in life. Markers help the programmer remember where to put code, or to remind the programmer of incomplete code fragments.

    Remember that if comments are not useful, they can create more of a burden than benefit. Creating effective comments is a skill, just like mastering programming syntax. First, let's take a look at how to comment your code well.

    In the following examples, we use PHP's comment syntax. A one line PHP comment is always preceded with double slashes (//). Let's take a look at a poor comment.

    // loop from 0 to 50 
    for ($x=0;$x<=50;$x++) 
        echo States[$x]; 
        $Inc .= $Incrementor; 
        if (($Inc == 9) || ($Inc == 10)) 
            echo "
    Execute this line of code"; } }

    Is the above comment accurate? Yes, I suppose it is. But, does it add anything to the code? No, not really. It states the obvious, that we are looping through 0 to 50. To make comments effective, be sure they are descriptive enough; ensure comments earn their keep. Let's re-write the above comment snippet, using a better comment.

    // print out all 50 states, including an 
    // extra line for states 9 and 10 
    for ($x=0;$x<=50;$x++) 
        echo States[$x]; 
        $Inc .= $Incrementor; 
        if (($Inc == 9) || ($Inc == 10)) 
            echo "
    Execute this line of code"; } }

    Now we have a pretty good idea about what this loop does. Not only do we specify what this loop's purpose in life is, we also touched on the purpose of the if statement inside the loop. Of course in this case, the if statement is little more than useless. In a real application, that if statement would provide extra functionality or logic and should be described in the comment more fully.

    One method to fill your source code effectively with comments is to describe your entire page first with English, avoiding any syntax what-so-ever. Once the page is described in English, cut and paste your description, comment it (ie: //), and write the code to satisfy that comment underneath it. Although this method takes longer, it certainly does ensure your code is sufficiently commented.

    Let's move on now to generalized comments, often describing the entire source code page. Many developers devote a few lines at the top of their source code to provide information like function name/source code page name, programmer's name, date authored and a description of the contained functionality.

    Here is a clear, efficient comment block that provides these details (remembering that /* and */ signify multiline comments in PHP).

    /* ---------------------------------------------- 
      Page: DBLogin.php 
      Date: 10/31/03 
      Author: Bill Simon 
      Page controls database login details to 
      connect to the MySQL database. 

    This comment block is clean, clear and under control, would you say? It is easy to see that these comments belong together because they are boxed in above and below, and provides pithy, yet detailed, page information.

    In general, do not comment simple lines of code, like variable declarations for example. You may comment an entire block of variable declarations above it, but not each individual line within the block. Use comments that provide additional information for the code and explain logic not intuitively obvious from the syntax. Overly commented code adds nothing but size to the application.

    For example, the following is an example of grossly overused comments, because each variable declaration is quite intuitive.

    $strName = "Steve" // declare $strName as Steve 
    $strPhone = "888-888-8888" // declare $strPhone as 888-888-8888 
    $strCity = "Scottsdale" // declare $strCity as Scottsdale 

    Commenting the entire variable block, however, is appropriate.

    // declare and assign personal variables 
    $strName = "Steve" 
    $strPhone = "888-888-8888" 
    $strCity = "Scottsdale" 

    Notice that in each example, the comment precedes the code (for the exception of the overused comment example, which is the exception). Remember to place all comments before the code, so the code reader knows what to expect, except in the event of commenting non-intuitive variable declarations, where comments can safely be placed on the same line as the code.

    To wrap up, here's what you should have learned:
    • Comments serve as explanations or reminders (markers)
    • Write comments that describe complex code
    • Except for one line variable declarations, comments precede code
    • Possible technique: English first, code second
    • Overused comments add nothing but size to the application {mospagebreak title=Unit Testing} The methods discussed thus far focus on code writing. These last two sections, unit tests and system tests, looks at quality software after code. We now test the code that we've written to ensure it meets certain standards, like correctness, efficiency and robustness.

      When most of us think of the word "test" as it relates to software, naturally we assume 'system test'; that is, we open up our browser and see if the darn thing works. Unit tests, however, are different. They are known as 'white box' tests, because we remove the browser from the equation. Instead, we inspect the code and establish a well documented list of inputs and outputs. We look through the box and focus on code, not user interfaces through our browser.

      Remember that even the most exhaustive test cannot guarantee the complete absence of errors. Testing is used to surface the most common errors, or the errors that are most likely to affect application functionality. A piece of quality software certainly sports a well functioning, relatively error free experience.

      Contrary to system tests, where testing can be completed by a group of career testers, unit testing is performed by the developer. Management or career testers need not be involved in this step.

      To test effectively, concentrate on control statements, like if statements and loops, where errors are most likely to hide. Particularly, statements to test include:







      The key is to choose a piece of test data that easily suggests the expected outcome. When testing mathematical algorithms, for example, use numbers like 10, or 100; make it easy on yourself. When testing a for loop, select a variety of iterative values (that is, values that control the number of times the for loop executes). If the body of the for loop does not print data, write a statement like "For loop ran". Testing the accuracy of the iteration is as easy as counting the number of times that test statement is displayed to the output device.

      Another unit testing technique is testing variable values. When you expect a variable to have a value, print the variable to the output device. Does it contain the expected value? If it does, great. If not, locate the error and fix it.

      Remember to test variables and control structures with a variety of data. Along with testing easy data, include data below your expectations and also above expectations, as it relates to the quantitative value (ie: 100000 instead of 10) and length of the variable's value. Users don't always follow directions; quality software ensures your program is robust enough to handle anything thrown at it.

      So, where are you most likely to find errors? Believe it or not, you will find most of your errors in a fairly small portion of your application. Areas to check include variable declarations, class instantiations, control statements and data visibility.

      Be sure not to overlook the obvious. Mistyped variable and function names account for a surprising number of mistakes. Another common mistake is setting initial array element sizes to 10 rather than 9 (array elements begin with 0). Anther is the dreaded "off by one" iteration mistake within for or while loops. Remember, most errors are relatively easy to fix.

      How much unit testing should you do? Well, this is up to you. First, judge the importance of your application. Does it require the extra time and expense of "error-free" status? If you are designing pacemakers, your rate of failure better be slim to none. What if your application displays scores from college football games on Sunday morning? Your rate of failure is far different, and probably not as important.

      To wrap up, here's what you should have learned:

    • Unit tests are "white box"; we look inside the code
    • Developers complete unit tests, not management or testers
    • Concentrate on control statements (if, while, case, etc)
    • Print variable names to ensure expected values
    • Check iterators closely to avoid "off by one" errors {mospagebreak title=System Testing} System testing is what we are all used to, and what we all may or may not enjoy. System testing involves firing up our web browsers and hoping for the best. We ensure the interface displays correctly and we confirm that data is being stored, retrieved and manipulated properly.

      When system testing, take one chunk at a time. If your application is large, focus on a particular page. Before moving to the next, make sure the page is absolutely 100% correct. Focusing on too many elements of your application at once causes confusion and increases the chances of overlooking common errors.

      When testing the system, pay special attention to unexpected data. Make your application handle the unexpected data, just like you did in a unit test. But in this case, ensure that your interface remains consistent and a clear error message is presented. Error messages should both explain what the error is and how to fix it. Users need to be guided.

      System testing is usually the last step in writing quality software. Once all modules and control structures are thoroughly screened and the interface tested, quality software is right around the corner.

      Google+ Comments

Google+ Comments