Program Design in a Nutshell:

The ** design recipe for data
definitions** guides the students to ask the following questions:

á Can you represent the information by a primitive data type?

á
Are there several related pieces of information
that describe one item? If yes, design a composite data type (*struct, class*).

á Does the composite data type contain another complex piece of data? Define that data type separately and refer to it. (A Book data item contains an Author data item.)

á
Are there several variants of the information
that are represented differently, but are related (*e.g. a circle, a rectangle, a triangle --- all are shapes*)? If yes,
design a union type. (In Java, define a common interface.)

á Repeat these steps. This may lead to self-reference, mutual reference, and eventually to a complex collection of classes and interfaces.

á Make examples of data for every data type you design.

The *design recipe for
functions/methods**:*

á Write down in English the purpose statement for the function/method, describing what data it will consume, and what values will it produce. Add a contract that specifies the data types for all inputs and the output.

á Make examples of the use of the function/method with the expected outcomes.

á Make an inventory of all data, data parts, and functions/methods available to solve the problem.

á Now design the body of the function/method. If the problem is too complex, use a wish list for tasks to be deferred to helper functions.

á Run tests that evaluate your examples. Add more tests if needed.

If every function produces a new value, the result, then the entire design process is very straightforward:

á Tests are simple, as they only verify that the result matches the expected value.

á Function composition comes naturally --- the result of any function application can be used in further computations.

á The order of computation does not affect the result. (However, a function or a data item must be defined before it can be used.)

To test method that change state (have side effects) you have to do the following:

á
*Setup:*
Initialize the data needed to invoke the method (and to verify the results)

á
*Invoke the
method to be tested.*

á
*Test*
the expected results, and the expected changes (effects).

á
*Tear-down*:
Reset the data that has been used to their original values (it the data will be
used again in other tests).

The ** design recipe for abstractions**
helps us eliminate code repetition and produce a more general solution:

á Mark all places where the similar code segments differ.

á Replace them with parameters and rewrite the solution using them as arguments.

á Rewrite the original solutions to your problems by invoking the generalized solution with the appropriate arguments.

á Make sure that the tests for the original solution still pass.