Rules of the road for developing high-quality software
|
Rule number one: All code must follow the Porthole Principle.
The fundamental issue in programming is that we each look out at
the world through a mental "porthole" that limits our field of view.
We are limited in how much we can see and understand at any one time.
Therefore, systems must be structured so that they can be understood
completely, at all levels, even though we are only allowed to investigate
them piecemeal, through our own limited and finite cognitive windows.
|
|
Abstraction is the essential tool that allows us to create systems of
arbitrary size and complexity. A beautifully designed abstraction is easy
to understand and use. It is so trustworthy that you don't feel any need
to worry about how it is implemented. Finally, and most importantly,
it enables you to reason with rigor and precision about the correctness
of the code you are writing that makes use of it.
|
|
The overall culture of the software group is a commitment to creating
clean, bug-free, maintainable code.
|
|
Commitment to clear understanding of correctness of every line of code.
A programming ethos of a commitment to "getting it right" and the
intellectual tools to be able to reason through a chunk of code and
convince oneself and others that it is correct.
|
|
The code is structured so that the above is possible; the amount of other
code that must be understood to understand any particular line of code
is bounded and manageable.
|
|
Code is structured and documented so that when you have to come back to
a given place in the code, it is easy to get your mind into the fabric
of assertions, invariants, and assumptions necessary to reason about it
correctly and successfully.
|
|
Be considerate to the readers of your code (including your future self).
The code should be easy to navigate and understand at the forest level,
the tree level, and the bark level.
|
|
For each chunk of code that would be about a paragraph
in an essay, add a "topic-sentence" comment that describes its purpose.
Nota bene: It is a sin to change the purpose of an entire paragraph of code,
and leave the topic-sentence comment unchanged and therefore dishonest.
|
|
Strive to have the experience of reading your code be a gentle one
rather than a harsh one. In those cases where a carefully written
piece of code remains difficult and might require head-banging on the
part of your readers to completely understand it, augment your normal
commentary so that they don't have to waste lots of time reverse-engineering
your source code.
|
|
No stealth inbound dependencies in the code! A stealth dependency is an
inbound dependency on a part of the code that is not obvious in the code
that is depended on. It is as though adjusting the lighting in the
library causes the dishwasher in the kitchen to suddenly stop working. It may
be hard to recognize that you are introducing a stealth dependency,
because at that moment you have both the library and the kitchen in mind.
But other programmers would have no reason to suspect that when they make
a change in the library, it also has a stealth effect on the kitchen.
|
|
At least two people understand and agree to the correctness of every
line of code. (Pair programming, or peer reviews of every line of code.)
|
|
Engineers collaboratively discuss and review design approaches and
algorithmic approaches early and often during the development process.
|
|
The yin and yang of software development are the handling of cases
where things go as expected and the handling of cases where errors occur.
The overall system design must have support and conventions at all levels
for the handling of errors or unexpected situations.
|
|
It is essential that developers make their work visible to others on an
ongoing basis. Use of configuration management is mandatory, and as
a rough guideline developers should check their work in to the shared
repository at least once a week, if not more frequently. It is a sin
to check in code that breaks the build or breaks regression tests.
|
|
It is essential to have software tools that enable the developers to
immediately identify the file and line when a fatal error occurs.
|
|
Automated regression tests with embedded code coverage metrics.
Strive for 100% code coverage of the deployed production system.
Do you want a line of code to be exercised for the first time on
a running, deployed production system??
|
|
Unit tests the developers create while writing and debugging can be
conveniently migrated into the automated test repository.
|
|
To avoid developer myopia, a non-developer must do a day-long full system
test once every week or two.
|
|
To avoid organizational myopia, an outside group must do a full system
test with training once every two or three months.
|
|
Bug database is actively maintained, and test point status in test
procedures is tied back to current status of bugs and requested features.
|
|
Keep the codebase squeaky clean. No dead code, no sloppy messes in
the code. No gratuitously redundant copy-and-paste code. It's not
that hard once you get used to it. It is valuable in its own right to
make the code understandable and maintainable, and it also fosters an
attitude of discipline and care. Sloppy code is probably also buggy code.
|
|
Have a standard, consistently applied coding style, possibly enforced
using a tool like GNU indent.
|
|
Use static analysis tools on the codebase: no compiler warnings; use
lint-style static checking tools. Use dynamic analysis tools such as
valgrind or Purify.
|
|
Use Doxygen or similar to generate API documentation automatically from
the codebase. One of the big successes of Unix was the humble man page.
|
|
There is a "just right", optimum development speed. Going too slow
has the obvious problems of unnecessarily burning schedule and budget.
But trying to go too fast also creates problems. The development effort
can devolve into a rushed, flustered, panicky state. This results in
sloppy, buggy, unreliable, and unmaintainable code that ultimately
slows the project down and makes progress increasingly difficult.
Developers need enough "breathing room" to do things right along the way,
as opposed to rushing off to the next crisis and leaving behind a trail
of half-baked, patched messes that will need to be cleaned up later.
|
|
If it feels a bit over-engineered and completely bullet-proof to the
engineers, it is probably OK. If it feels just basically OK to the
engineers, it is likely not really OK.
|
|
If the platform isn't stable, nothing else matters.
|
|
System security must be designed in, not tacked on.
|
|
Perfection is brittle; aim for robustness and trustworthiness.
|
|
No one is right 100% percent of the time. Foster a culture of willingness
to learn, to be convinced to change your mind, to trust others enough
to share new ideas that may seem "off the wall", but may lead to important
breakthroughs with some nurturing and reformulation.
|
|
Foster ego-free mutual trust: "It doesn't matter who gets the credit".
|
|
When making changes, respect the accumulated intellectual capital of your
colleagues. Realize that when you change things, you may be costing others
time and effort to re-learn something. Make sure your changes are valuable
enough to be more than worth that cost.
|
|
"Clear and hold:" Whenever a bug is found and fixed, add a test case
that differentiates between the failure and the corrected system.
Include that test case in the automated regression suite, so that the
bug never comes back again, or gets immediately caught if it does.
|
|
There are times when we all need help. Create enough trust that people
are willing to ask for and receive help when they need it.
|
|
Respect the testing staff; make sure they know what to expect at each
iteration of the process.
|
|
A well-rested brain works better than an exhausted, sleep-deprived brain.
|
|
Beginning programmers write simple code. Intermediate programmers
write complicated code. Masterful programmers write simple code.
|
|
Don't write "look how smart I am" code.
|
|
Understand the problem before starting to fix the problem.
|
|
Writing software is like writing poetry. The skill of finding names that
suggest the essence of your thinking and the underlying model behind your
code is essential for creating understandable and maintainable code.
In software as in poetry, one is always on the lookout for that "mot
juste".
|
|
Write your code to help readers make the transition from seeing the
local details to grasping the underlying big picture. You are looking
to facilitate the moment when the reader says, "Oh! I see what they
are up to here."
|