Building a Program

Tom Kelliher, CS 318

Mar. 1, 2000



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.


From Last Time


  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.''

    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