This article is part of a series of six articles:
- Multi-paradigm programming
- Declarative Computation
- Functional Programming
- Explicit state
- Object-oriented Programming
- Program design
Programming essentially is about solving problems. The previous articles have shown that there are different ways to solve problems. We start from a problem we want to solve that gives the high-level structure of the program, i.e. what programming techniques we need to use and how they are connected together. This process is called program design.
Many things have been said about the correct design methodology and in the end it’s very hard to prove what works and what does not work. The following points summarise the design methodology shown in CTM:
- Informal specification: Start by writing down what the program should do: what are the inputs and outputs and how do they relate. This specification has to be precise.
- Examples: To make your specification clear it is always a good idea to imagine examples of what the program does in particular cases. The examples should “stress” the program, i.e. use boundary conditions and the most unexpected ways imaginable.
- Exploration: A good way to find out what programming techniques work best is to use an interactive interface to experiment with program fragments. The idea is to write small operations that we think might be needed for the program and we use the operation that the system already provides as a basis. This step gives us a better view of what the structure of the program should be.
- Structure: We make a rough outline of the operations needed to calculate outputs from the inputs and how they fit together.
- Coding: We implement the structure and group related operations together into modules.
- Testing: Finally we have to verify that our program does the right thing. There are different approaches to testing concerning when to test, what to test and how to test.
There are many ways to organise software development, from top-down to bottom-up they often have in common that you have to start with a fairly complete set of requirements. Practice has shown that it is almost impossible to correctly anticipate most of the functional and non-functional requirements and it is therefore often beneficial to start with a small set of requirements. CTM calls this the thin-to-thick approach and you might you this approach as the main driver of agile development.
- Start with a small set of requirements. The specification and architecture are just complete enough to build a running program but they do not solve the user problems right away.
- Continiously extend the requirements. This is sometimes called the evolutionary approach. At all times there is a running system that satisfies its specification and can be evaluated by its potential users.
- Do not optimize during the development process. That is, do not make the design more complex just to increase performance. Performance optimizations can be done near the end of development if needed.
- See architecture as necessary during development to keep a good component organisation. Components should encapsulate design decisions or implement common abstractions. This reorganisation is sometimes called refactoring. There is a spectrum between the extremes of completely planning a design and completely relying on refactoring. This best approach is somewhere in the middle.
I know it’s hard but:
Don’t go crazy with any programming technique you use even if you are super-hyped, it will not make you look smarter. Using every super clever inheritance pattern is as useless as staying point-free for esoteric style reasons.