Building a Program

Tom Kelliher, CS 318

Mar. 1, 2000

Administrivia

Announcements

I'll collect programs Friday. Minimally, you need to hand-in hardcopy of your HTML form and Perl program. See Unix handouts for tips on using the printer.

Assignment

From Last Time

Outline

  1. Advice on the software engineering process.

Coming Up

Building a Program

Why bother with these ``details?''

  1. Program design and implementation tips:
    1. Top-down design.

    2. Test plan.

      Examples: no input, garbage input, can't open system files.

    3. Bottom-up implementation.

    4. Step-by-step testing.

    5. Subroutines:
      1. One page, one subroutine.

      2. Use subroutines to hide complexity.

      3. If that doesn't work, redesign: ``Plan to throw one away, because you will anyway.'' (Fred Brooks)

  2. Necessary (not necessarily sufficient) documentation:

    Standard: Is the documentation meaningful to the reader?

    1. Programmer's name and date of the program.

    2. Synopsis of use.

    3. Briefly document program interfaces. Examples: password file format, GECOS field format, CGI interface.

    4. Explanation of program's function.

    5. Use meaningful identifier names.

    6. For each subroutine:
      1. Explain what it does.

      2. Explain the parameters.

      3. Explain what it returns. If it causes side-effects ( heavily discouraged), explain them also.

    Block comments should stand out. Inline comments should maintain indentation style.

  3. Additional Perl security checks:
    #!/usr/local/bin/perl -T -w
    
    Taint checks. See perlsec(1).

  4. How to attack an uninitialized variable problem.

  5. How to force an initial value on a variable:
    my $name = param("name") || "";
    
    Short-circuit evaluation.

  6. Reducing complexity, increasing generality:
    1. Use subroutines.

    2. Don't make assumptions about how many components in a name.

    3. Don't read an entire file in if you only need one line at a time.

    4. Increase readability by using names with meaning and avoiding ``magic numbers.''

    Examples:
    my @record = split(/:/, $line);
    my @gecos = split(/,/, $record[4]);
    
    # ...
    
    if (lc($name) eq lc($record[0])
        || lc($name) eq lc($gecosName[0])
        || lc($name) eq lc($gecosName[1])
        || lc($name) eq lc($gecosName[2]))
    {
       # ...
    }
    
    This is much more readable:
    sub gecosMatch($$);
    
    # ...
    
    my ($uname, $pwd, $uid, $gid, $gecos, $homeDir, $shell)
       = split(/:/, $line);
    
    if (lc($uname) eq lc($name) || gecosMatch($name, $gecos))
    {
       # ...
    }
    
    
    sub gecosMatch($$)
    {
       my ($name, $gecos) = @_;
       my ($gname, $goffice, $gwphone, $ghphone) = split(/,/, $gecos);
       my @names = split(/ /, $gname);
    
       foreach (@names)
       {
          if (lc($_) eq lc($name))
          {
             return 1;
          }
       }
    
       return 0;
    }
    



Thomas P. Kelliher
Wed Mar 1 08:26:11 EST 2000
Tom Kelliher