Archive for June 2006
If we use primitives, we can design and write programs that will not be overly dependent on the idiosyncrasies of any one operating system. The primitives insulate a program from its operating system environment and ensure that the high level task to be performed is clearly expressed in a small well-defined set of basic operations.
It is a good practice to write first in an easy-to-read higher level language, then translate into whatever real-life language you happen to be working with. [eg, lib, script, lex/yacc]
If you adhere to the design principle of pushing details as far down as possible, by writing in terms of basic primitives which read from an arbitrary source and write to an arbitrary destination, your new tools will be compatible with previous ones; you will be building a whole set that work together. [pipe]
do reasonable things with extreme cases
When bugs occur, they usually arise at the "boundaries" or extremes of program operation.
We do recommend that you be consistent in applying whatever formatting standards you settle on.
The best place to begin this activity [test] is while the program is being written. The main assurance you have that a program is correct is the intellectual effort you put into getting it right in the first place.
Testing is still necessary, however, to check that the algorithm is valid and that the program implements it correctly.
intuitively a "boundary" is a data value for which the program is forced to react differently from an adjacent value.
Yet it is a fundamental principle of testing that you must know in advance what answer each test case is supposed to produce.
So part of the responsibility of writing a program is to prepare a comprehensive test of test inputs, and outputs against which to compare the result of test runs.
it's folly to write a program that blindly assumes that its input is legal.
Most real programs are subjected to a steady flow of changes and improvements over their lifetimes, and many programmers spend most of their time maintaining and modifying existing programs. This is an expensive process, so one of the most important design considerations for a program is that it be easy to change.
The best way we know to achieve this is to write the program so its pieces are as decoupled as possible, so that a change in one does not affect others.
Hand Compiling the Code
The moral should be obvious. By writing a program in a straightforward manner, you get it working correctly and minimize the chance of confusion. You can then measure how it performs to decide whether it works well enough and, if not, where to concentrate your attention. For a given algorithm, gains in speed are almost always obtained at the cost of readability. Sacrifice clarity for speed only when you know that you are solving the correct problem correctly and when you know that the sacrifice is worthwhile.
A Word on Structured Programming
Our approach to structured programming is to stick to the basics. We invest extra effort in the design and coding process (which is fun) to minimize the much costlier testing and debugging phase (which is not). We put strong emphasis on clean, comprehensible code, saving efficiency considerations for the end. We check and test code as we write it, rather than relying on a final debugging binge to fix everything. We make extensive use of subroutine calls and statement grouping to modularize code, and we always write control flow in terms of if-else and the looping constructs.
But our primary tool for writing good programs is to strive to make them readable. In our experience, readability is the single best criterion of program quality: if a program is easy to read, it is probably a good program; if it is hard to read, it probably isn't good.
Brad Appleton reviews misunderstandings, and records many references and good quotes, for simplicity in software design.
My favorites, of Brad's quotes:
Besides the noble art of getting things done, there is the noble art of leaving things undone. The wisdom of life consists in the elimination of nonessentials.
— Lin Yu Tang
Perfection (in design) is achieved not when there is nothing more to add, but rather when there is nothing more to take away.
— Antoine de Saint-Exupéry
Beauty is more important in computing than anywhere else in technology because software is so complicated. Beauty is the ultimate defense against complexity.
— David Gelernter
A complex system that works is invariably found to have evolved from a simple system that worked.
— John Gall
Simplicity and elegance are unpopular because they require hard work and discipline to achieve and education to be appreciated.
— Edsger W. Dijkstra
Architect: Someone who knows the difference between that which could be done and that which should be done.
— Larry McVoy
Manifest plainness, Embrace simplicity, Reduce selfishness, Have few desires.
— Lao-Tzu, Tao Te Ching