Steven S. Skiena
Software Engineering and Saddam Hussain
Think about the Patriot missiles which tried to shoot down SCUD missiles in the Persian Gulf war and think about how difficult it is to produce working software!
Even today, there is great controversy about how well the missiles actually did in the war.
Testing and Verification
How do you know that your program works? Not by testing it!
``Testing reveals the presence, but not the absence of bugs.'' - Dijkstra
Still, it is important to design test cases which exercise the boundary conditions of the program.
Example: Linked list insertion. The boundary cases include:
Test Case Generation
In the Microsoft Excel group, there is one tester for each programmer! Types of test cases include:
Boundary cases - Make sure that each line of code and branch of IF is executed at least once.
Random data - Automatically generated test data can be useful to test user patterns you might otherwise not consider, but you must verify that the results are correct!
Other users - People who were not involved in writing the program will have vastly different ideas of how to use it.
Adversaries - People who want to attack your program and have access to the source for often find bugs by reading it.
But how can we know that our program works? The ideal way is to mathematically prove it.
For each subprogram, there is a precise set of preconditions which we assume is satisfied by the input parameters, and a precise set of post-conditions which are satisfied by the output parameters.
If we can show that any input satisfying the preconditions is always transformed to output satisfying the post conditions, we have proven the subprogram correct.
To correctly build a complicated system requires first setting broad goals and refining them over time. Advantages include:
A hierarchy hides information - This permits you to focus attention on only a manageable amount of detail.
With the interfaces defined by the hierarchy, changes can be made without effecting the rest of the structure - Thus systems can be maintained without being ground to a halt.
Progress can be made in parallel by having different people work on different subsections - Thus you can organize to build large systems.
Stepwise Refinement in Programming
The best way to build complicated programs is to construct the hierarchy one level at a time, finally writing the actual functions when the task is small enough to be easily done.
Most of software engineering is just common sense, but it is very easy to ignore common sense.
Building a Military Threat
Module Build-Military: The first decision is now to organize it, not what type of tank to buy.
Several different organizations are possible, and in planning we should investigate each one:
Procedure Army: Tanks, Troops, Guns ...
Procedure Troops: Training, Recruitment, Supplies
Top-Down Design Example
``Teaching Software Engineering is like telling children to brush their teeth.'' - anonymous professor.
To make this more concrete, lets outline how a non-trivial program should be structured.
Suppose that you wanted to write a program to enable a person to play the game Battleship against a computer.
Tell me what to do!
What is Battleship?
Each side places 5 ships on a grid, and then takes turns guessing grid points until one side has covered all the ships:
For each query, the answer ``hit'', ``miss'', or ``you sunk my battleship'' must be given.
There are two distinct views of the world, one reflecting the truth about the board, the other reflecting what your opponent knows.
Interesting subproblems are: display board, generate query, respond to query, generate initial configuration, move-loop (main routine).
What data structure should we use? Two-dimensional arrays.
How do I enforce separation between my view and your view?