When solving a problem by computer, one normally designs a program by breaking the problem into parts, which in turn can be broken into subparts, and so on, until the individual sub-sub-parts are either already to be found in a library or are so easy as to admit of simple, quick solution. Each individual subpart is solved by a function or by a collection of functions in a module. Each solution is written as another function, and so on, all the way up to the main function, which solves the whole problem. In other words, the solution to the main problem is composed of solutions to the individual parts. To design software systems successfully, you must master the techniques of analysis and composition.
You can develop your analytical skills by applying the following systematic technique to any assignment:
- Get your class notebook.
- Write these headings:
Things I need to complete or create Tasks Modules Data Types Algorithms Functions
- On a separate piece of paper, write these headings:
Things that are provided for me Modules Data Types Algorithms Functions Code
- Does this paragraph describe a task you are to accomplish?
If so, list it in your notebook under tasks.
For nontrivial tasks, start a fresh
sheet of paper for the task, and use it to keep track of modules, data
types, algorithms, functions, and advice related to the task.
- Does this paragraph describe a module, data type, algorithm, or
function that is provided for you?
If so, what is it?
Does it solve a problem?
Does it represent a subtask to be accomplished?
Will it help solve a subtask you already know about?
In that case, make a note of it on the sheet of paper for that task.
- Does this paragraph introduce a new type of data?
- How will that data be represented?
- Will it be an abstract data type or will its representation be exposed in a header file?
- What functions should be packaged with the data type in the same module?
- Does it relate to a task? If so, note it on the sheet for that task.
- Does this paragraph suggest a module, algorithm, or
function that you will need to develop?
If so, what sub-problem will it solve?
What tasks does it relate to?
How will it connect with other elements of the system in order to form
a harmonious, useful whole?
Will it need new data types?
- If this paragraph suggests a programming technique or a problem to watch out for, to which tasks, modules, data types, algorithms, or functions is it likely to be relevant?
Once you've analyzed the whole assignment, you can start tackling the design. Here are some more questions to ask:
- What are my most important data types?
- For each data type, should it reside in a module of its own, or should it be grouped in a single module with other data types?
- For each data type, are there functions related to it that should reside in the same module with the data type? What are they?
- Are there functions that are not necessarily related to any data type but are related to each other, so they should be grouped in the same module?
- Which modules should be clients of which other modules?
At this point you are probably ready to design your program. I encourage you to follow Wirth's method of stepwise refinement. This method encourages you to decompose problems into subproblems. About any possible decomposition you can ask:
- Do all of the subproblems appear easier to solve (or better specified) than the original problem?
- Can I solve some of the subproblems with library functions?
- Are some of the subproblems so simple I know how to write functions for them?
- Can I test the solutions to subproblems independently of the whole problem? (This testing technique is called unit testing.)
For an example of how to apply this method to a particular programming problem, see the problem of building a lossy image compressor.