Computational Physics
Strategy
Comments and questions to John Rowe.
Strategy is driven by several things including the non-scalability of
the mental task and the difficulty of finding bugs. It's also driven
by the three rules of planning and design:
- You can't write code without being 100% sure what that code going
to do. Sitting down at the keyboard to write a function whose
task is almost but not quite clear is a recipe for disaster.
- You or your customers won't know exactly what they want until
they try using it. The specification will change.
- Even if they do, you can be sure that new, unthought of requirements will
emerge after the program has been in use for a while.
Understand the task
from the perspective of the people who will be using the program.
This not only guides what the problem does but also how you implement it.
Create a framework
-
At the beginning of a project you are not writing
a computer program, you are
creating a framework that is easy to:
- Test
- Debug
- Modify and extend
Right from the start.
- More time is spent maintaining existing programs than writing
new ones. New features always get added.
- The major problem is preventing, finding and fixing errors.
- Trying to "bolt on" testability, etc. afterwards is never very
effective - it must be designed in right from the beginning.
Structure your data
- Each type of "thing" will normally have its own type of
structure.
- Each actual thing will have a structure allocated for it and a
pointer to that structure will be passed from function to function.
- That structure tells you everything you need to
know about it, including its relationship to other things, usually via
other pointers.
- Once you get your data structure right, working out what
functions to write is usually quite easy.
Structure your code
- Structure your data first, then your code.
- Two strategies:
- Top down: divide your task into sub-tasks, the sub-tasks into
smaller sub-tasks and so on until you get to something small
enough to do.
- Bottom up: build up a collection of utility "tool-box" routines, and
string them together to make increasingly higher-level
routines.
- Top-down implies that you know your requirement pretty
accurately and that it's unlikely to change (although the way
you implement it may). Bottom-up is pretty meaningless unless
you know what higher-level functions you are aiming at.
- It's a bit of a false dichotomy.
Types of program
- Traditional. Has a fixed task: read in data, do calculation,
output data, finish. Examples: payroll, movie rendering,
batch job scientific simulation.
- Modern. Event loop: initialise, wait for input, handle input,
wait for next input. Examples: word processor, web server,
real-time scientific simulation.
- Event loop suited to null program style: start off with program
that does nothing, add a tiny functionality, test, repeat.
This is a popular solution to the "Can't write a program until you know
what it's got to do, can't work out what it's got to do until you try it"
paradox.
Splitting up your task
Remember from the previous notes:
-
Functions break large computing tasks into smaller ones, and
enable people to build on what others have done instead of starting
over from scratch.
Kernighan & Ritchie.
Functions should be short and sweet, and do just one thing...
and do that well.
Torvalds
- Functions allow you to think about what you are trying to do,
not how you are doing it.
- Conversely, when writing a low-level utility function you only
need to think about what the function does and not the wider
context in which it is being called.
- Avoid side effects (do one thing..)
- The structure of your code reflects the structure of the task
you are trying to achieve: you should be able to describe in
words what the function does in terms of the task.
- Better criterion: the structure of your code reflects the
decisions you had to make when deciding what to do and how to do
it.
- If I had to change one aspect of the code (say, a particular
algorithm), could I just change one function or would there be a
large number of functions that needed changing?
- Could this function be reused in this program or even in
another program?
Smart people have simple code
-
Keep It Simple, Stupid.