|
developer.* by
Daniel Read
Principled
Programming
Please enjoy this partial list of "Principles" which I
have compiled. No one can pretend to live up to all of them
100%, but we can all try. The "Principled Programming" project
has it's home on Daniel Read's developer.*
web site (www.developerdotstar.com). Feel free to
pass this on to friends and colleagues, but please credit the
source, and please keep the principles together.
Principle #1: The Principle of Personal
Character
Whether we know it or not, and whether we like it or
not, our character is reflected in every line of code we write,
every report we design, every user interface we build, every diagram
we produce. When another person looks at our code—or just as
important, the output of our code—that person, consciously or not,
makes a judgement about us. Think back on code you have
written…what would that judgement be? Would you be proud to
stand up and take ownership of your code? Or would you have to
sheepishly admit that it's yours, and launch into excuses for why
it's not as good as it could be? If code is bad, then another
developer reading that code is likely to assume that this poor
quality is not an isolated event. The good news is this: we
have absolute control over the quality of our code.
The
question is not about whether or not one has the ability to
write the best code possible, but whether or not one cares to even
try. If one lacks in certain abilities, but takes pains to
write clear, readable, well commented code that at least shows that
the developer has taken the time to learn some of the fundamentals,
then that developer has done her due diligence—and that fact will be
obvious to a keen observer. It would be unreasonable to fault a
person for some level of inexperience, or ignorance of certain
techniques. However, it is absolutely reasonable to find a
connection between the overall quality of a developer's code and the
quality of that developer's character.
The
Principle of Personal Character states: Write your code so that it reflects, or rises above,
the best parts of your personal
character.
Principle #2: The Principle of
Aesthetics
One aspect of programming in general we too often
neglect is that of aesthetics. Aesthetics is about beauty and
elegance, and the appreciation of these qualities. Many people,
however, believe that aesthetics is only important when talking
about art and literature. Too few people realize the importance
of beauty and elegance in everyday things, and too few developers
realize the importance of these in the writing of
code. Aesthetics is especially important in software
development, a realm where we are constantly dealing in layers of
abstractions. The aesthetic aspects of our abstractions are
directly related to their understandability, and therefore their
usefulness.
A developer should strive for beauty, no matter
what tool or language he or she is using. Beauty can be
achieved on many levels, from the high level of the overall elegance
of a system design to the lowest level of the visual appearance of
code on the screen. Neatness counts. The best code not
only works efficiently and correctly, and is well formed from the
compiler's point of view, but the best code is also visually
pleasing to the human eye—and therefore easier for the human brain
to absorb and understand.
Steve McConnell writes in Code
Complete, "The visual and intellectual enjoyment of
well-formatted code is a pleasure that few nonprogrammers can
appreciate. But programmers who take pride in their work derive
great artistic satisfaction from polishing the visual structure of
their code." (Page 399)
The
Principle of Aesthetics states: Strive for beauty and elegance in every aspect of
your work.
Principle #3: The Principle of
Clarity
Clarity is a state that must be actively
sought. One of the biggest transgressions that we as developers
can commit is to forget that our code has a life far beyond the few
moments it takes us to write it. Chances are excellent that
someone else—maybe even the original author—is going to have to deal
with our code sometime in the future. Even if we write code
that works perfectly and never causes a problem for the user, we
have done our fellow developers (not to mention our employers) a
disservice if we have not attempted to be as clear as
possible.
There is a difference between clarity and
correctness, though the two are often confused. Correctness is
a primary focus of most developers, as it should be. The quest
for correctness focuses on making the syntax correct for the
compiler, designing the interface to meet the user's needs, and
writing the algorithms to match the requirements. But if
attention to clarity is not given equal emphasis, then the
understandability and maintainability of the code will
suffer. For our code to be as clear as possible, we must
consciously use techniques such as informative naming, modularity,
indenting, white space, strong cohesion, weak coupling, testing and
documenting assumptions, and proper commenting.
Lack of
clarity in our code causes unnecessary pain, and professional
embarrassment, for our fellow developers who will have to maintain
our code in the years (or even decades) to come. As for our
employers or benefactors, we short-change them by delivering less
value; if poor enough, our code may even become a liability to the
company. Leaving our fellow developers in this situation is
discourteous to say the least, but leaving our employers in this
situation is much worse: we make an agreement to produce quality
code for a price. Our employers have paid us for out work, but
how did they fare in the bargain?
The
Principle of Clarity States: Value clarity equally with correctness. Utilize
the proven techniques that will produce clarity in your
code. Correctness will likely follow
suit.
Principle #4:The Principle of
Layout
The Principle of Layout is a corollary to both The
Principle of Aesthetics and The Principle of Clarity. The
Principle of Aesthetics tells us that, besides providing
intellectual enjoyment, beauty and elegance play a crucial role in
well-written code. The Principle of Clarity tells us to make
our code as clear and understandable to human readers as possible,
and that clarity goes hand-in-hand with correctness. The
Principle of Layout puts these dual principles into
practice.
It is difficult to discuss the importance of good
visual layout without referring to Steve McConnell's "Fundamental
Theorem of Formatting," which states, "Good visual layout shows the
logical structure of a program." (page 403, Code
Complete) This means that layout not only serves to make
the code look more attractive, but also works on a subconscious
level to make the code more readily understandable to the
reader. The goal is to reduce the amount of work that a reader
needs to perform in order to understand our code. Layout should
be our first tool for communicating clearly with human readers of
our code.
There are several techniques that will ensure that
layout of code suggests or reveals its logic. These techniques
should be part of the foundation of every programmer's style: proper
use of white space (blank lines), indenting, grouping together of
related lines, using extra parentheses to make Boolean logic and
mathematical formulas clearer, horizontal alignment of related code
on separate lines, proper placement of block delimiters,
etc. As McConnell suggests in his Theorem, the idea is to use
the visual layout of our code to communicate on a subconscious
level with the reader. Remember that when we are working in
the realm of software development, we are always working with
abstractions, and an abstraction is only as useful as it is
understandable.
The
Principle of Layout states: Use the visual layout of your code to communicate the
structure of your code to human readers.
Principle #5: The Principle of
Explicitness
Following the Principle of Explicitness will save us
and our successors incalculable trouble. The Principle of
Explicitness is a corollary of the Principle of Clarity. But
the Principle of Clarity is about making one's code clear and
understandable to human readers. The Principle of Explicitness
applies to human understandability as well, but more importantly,
following the Principle of Explicitness makes our code more tolerant
to change.
Here is a simple example: many programming
languages and platforms offer the concept of a "recordset," which is
a collection of data, in the form of rows and columns, usually
pulled from a relational database. The recordset, often
implemented as an object, is usually not provided by the language
itself, but rather by some kind of library or component. When
you write code to open up a recordset, you would normally have
properties and/or parameters to determine the "cursor
type." When your code calls the function to open the recordset,
that function probably allows for a default cursor type, meaning
that you do not have to explicitly specify what cursor type to
use—your code can just accept the default.
If a developer
accepts the default cursor type, that developer has now created an
implicit assumption in his code, which reduces
clarity. Worse, he has also created a gigantic opportunity for
future bugs. The cursor type chosen directly effects the
behavior of the recordset. Your code depends on that
behavior. What happens six months later when the team upgrades
to a newer version of the component that provides the
recordset? What happens if that new version changes the default
recordset type from and a "dynamic/updateable" cursor type to a
"forward only/read only" type? Do you know what's going to
happen to all of that code that accepted the default cursor
type? It's going to break. Or worse, it's going to
silently change some behavior; some If condition is going to return False instead of True, and the Else block is going to be executed instead; and then months
later, someone realizes that data corruption is rampant throughout
the system.
By not being explicit in this simple example, the
fictional developer who implicitly accepted the default cursor type
made his code less tolerant to change. This is
unacceptable. We must acquire the knowledge of where the
potholes in the road are likely to be (the cursor type pothole is
but one example of many, and every language and platform is full of
others), and then we must use that knowledge when we write our code
so that the potholes don't hurt us. As professionals, it falls
on us to acknowledge the fact that change is constant, and to do our
best to ensure that our code can weather those changes without
failing or producing incorrect results. When our code does
fail, we must ensure that it will do so gracefully, and that upon
doing so, it provides as much specific information about where and
why it failed as possible.
The key to avoiding potholes is to
be explicit. Trouble lurks in the implicit—in the undocumented
and untested assumption, in the arcane technique, and in the
undocumented intent of the developer, which gets lost forever like a
ship sinking silently in a vast, opaque ocean.
The
Principle of Explicitness States: Always favor the explicit over the
implicit.
Principle #6: The Principle of Self-Documenting
Code
Self-documenting code does not get written by
accident.
As developers, we must give attention to the
development of a sound style, which is the key to self-documenting
code. We must constantly try to improve and perfect our style,
so that each program we write is better than the one before
it. A highly developed programming style comes through the
diligent incorporation of proven techniques: informative, consistent
naming; modularization that pays close attention to cohesion and
coupling; avoidance of hard to understand techniques; clear layout;
use of named constants; testing and documenting assumptions; and
much more.
To learn these techniques, we must read the
writings of all of those who came before us, for these people have
already blazed the trail. Seek out the classic
literature. Learn from the masters. Subscribe to
magazines. Join internet discussion lists. Read lots and
lots of other people's code. When you see code that falls
short, analyze it, and try to figure out why. When you see code
that reaches that high level we seek, you should be able to identify
the techniques the developer used to achieve that level of
quality. There is a saying: any fool can learn from his own
mistakes; a wise person learns from the mistakes of
others.
What about the role of comments? Do we still
need them if our code is to be
self-documenting? Self-documenting code, like perfection, is an
elusive goal, and one that is probably impossible to achieve
fully. However, that should not stop us from always reaching
for the goal of self-documenting code. Where we fall short of
perfection, we must supplement our efforts with good
comments. Well written code should not need a lot of comments;
it should speak for itself. However, some amount of commenting
is required—the comments just need to be of the most useful types
(see The Principle of Comments).
When viewed up close, truly
self-documenting code is a joy to behold, and it becomes clear to
the first-time observer that such a marvel could only occur through
the efforts of a conscientious and diligent software
engineer.
The
Principle of Self-Documenting Code states: The most reliable document of software is the code
itself. In many cases, the code is the only
documentation. Therefore, strive to make your code
self-documenting, and where you can't, add
comments.
Principle #7: The Principle of
Comments
Comments are a double-edged sword. Used
properly, they can infinitely improve the understandability and
maintainability of code. Used improperly, they can clutter your
code and render it less readable. Poor commenting is at
best of little value, and at worst creates a huge mess.
The
Principle of Comments has three parts:
First, comment in full
sentences. This simple technique greatly increases a reader's
comprehension of both the comment and the code it
denotes. Sentence fragments tend to be cryptic. Writing
each comment as a full sentence also makes comments more
understandable to a wider audience, which is especially important in
today's multi-cultural environment. High quality comments
written as full sentences also act as an instructional aid for less
experienced developers.
Second, use comments to
summarize. "Summary comments" summarize a block of code in
order to save a person from having to read all of the code that the
comment describes. A summary comment would usually appear as a
few lines at the top of a block of code. Note that a good
summary comment does not repeat the code, but rather "distills"
several lines of code down to two or three sentences.
Third,
try always to comment "at the level of intent." What this means
is to comment at the level of the problem, rather than the level of
the solution. The code is the solution to the problem being
solved. Ideally, the code should speak for itself (see The
Principle of Self Documenting Code). A person can read the
code, and if it's good code, should be able to readily see what the
code is doing and how it's doing it. However, what is lost over
time is what was in the mind of the developer who wrote the
code. In general, this is what needs to commented
on. What was the intent of the developer? How is
this code intended to be used? How does this code
intend to solve the problem at hand? What was the idea
behind the code? How does this code explicitly interrelate to
other parts of the code? One of the greatest sins a developer
can commit is to leave his code without his intent being clear to
subsequent readers of the code.
The
Principle of Comments states: Comment in full sentences in order to summarize and
communicate intent.
Principle #8: The Principle of
Assumptions
The Principle of Assumptions is a corollary to the
Principle of Explicitness. The practice of testing and
documenting assumptions in your code has several benefits: one, it
increases readability; two, it makes your code more predictable;
three, it makes your code more maintainable; four, it reduces the
need for comments; five, it makes your code more reliable; six, it
makes your code more communicative when something goes wrong,
thereby making your programs easier to troubleshoot; seven, early
detection of failed assumption tests protects data from corruption;
eight, it forces you to be aware of the assumptions any given
routine makes, and its relationship with other routines and shared
data, which decreases the incidence of bugs.
The testing of
assumptions is one of the cornerstones of defensive
programming. Every piece of code contains
assumptions. Some assumptions are fairly safe and don't need
testing or documenting. (That said, our error handling scheme
should always be there to gracefully catch when our untested
assumptions do indeed fail.) However, we can and should test
for (and document) the many other assumptions that are less
obvious.
The most common kind of assumptions that should be
tested (and thereby documented), are the prerequisites that a given
routine relies upon. These tests usually take the form of a
series of If…Then statements at the top of the routine. If any of
the tests fail, then your code might either take corrective action,
or perhaps raise a specific error message explaining that an
assumption failed. (Another often overlooked method for testing
assumptions is the use of assertions, which are True/False expressions that are usually only compiled into "debug"
versions of the program for testing.)
The
Principle of Assumptions states: Take reasonable steps to test, document, and
otherwise draw attention to the assumptions made in every module and
routine.
Principle #9: The Principle of User
Interaction
The phrasing for this rule or is borrowed from
About Face: The Essentials of User Interface Design, by
interaction design guru Alan Cooper. Cooper expands powerfully
on this idea in his subsequent book, The Inmates are Running the
Asylum: "Most software is used in a business context, so most
victims of bad interaction are paid for their suffering. Their
job forces them to use software, so they cannot choose not to
use it—they can only tolerate it as well as they can. They are
forced to submerge their frustration and ignore the embarrassment
they feel because the software makes them feel stupid." (Page
34) This is a powerful statement, and one that should make us
all pause to consider the real impact, good or bad, that our
software has on real people.
How are users made to feel
stupid? Alan Cooper has devoted two entire books to answering
this question, and other author's have tackled the subject as well
(including Donald Norman in his excellent book , The Design of
Everyday Things.) Obviously, then, we cannot do the subject
justice here. However, here is one simple example: a user
clicks a button on a form and immediately an error message pops up
that says "You cannot use that function right now." Then why
was the button even available for clicking? The developer,
by not taking the simple step of disabling or hiding the button,
unwittingly creates a situation in which he or she is just a joker,
pointing to a user's shirt and then flicking the poor user in the
nose when he looks down. Very funny.
Poorly designed
user interaction is a huge problem that applies to the entire
hardware and software industry. It is a sad truth that
developers throughout the hardware and software industry regularly
design solutions that end up making their users feel stupid. It
is even more sad that so many developers are blissfully unaware of
the stress created in people's lives. However, as developers,
we are in a position to help solve this problem—one application at a
time.
As software developers, our primary responsibility for
user interaction lies in user interface design. Let's face it:
in most cases there is not a detailed user interface design prepared
in advance. Most user interface design decisions (and this
includes report design) are made by the developer at the time of
construction. Therefore, in most cases, it is solely the
job of the developer to take steps to make sure the user is
never made to feel stupid. The developer writes the error
messages and prompts. The developer places the buttons and
fields on the form. The developer, therefore, has almost total
control over the user's experience.
The
Principle of User Interaction states: Never make the user feel
stupid.
Principle #10: The Principle of Going
Back
We've all been guilty of this one at one time
or another: "I don't have time to do that now . I'll come back
and do it later." This kind of procrastination usually applies
to tasks such as commenting, code formatting, error handling,
implementation of proper modularization, etc. Maybe you are
that rare person who always goes back later and does all this
"tedious" work, but most of us mortals never do.
The time to
do all of the tedious tasks associated with coding is at the time
you are writing the code. The main reason that no one goes
back later to "clean up" their code is that any task that is tedious
while you are in the middle of writing your code is monumentally
more tedious when you have to go back and do it after the
fact. Does anyone really think that going back and putting good
error handling into hundreds of routines in less tedious than
creating those routines with proper error-handling in the first
place? Not only will you hate every minute of the task, you
very well may introduce bugs that were not there before.
In
the case of comments, the comments you add later will never
be as good as the comments you could have written right at the
moment you were writing the routine. And what happens if you
have to leave an employer or project before you have a chance to "go
back later"? Now you've left that monumental and tedious task
for someone else to do, which is hugely
unprofessional.
The
Principle of Going Back states: The time to write good code is at the time you are
writing it.
Principle #11: The Principle of Other People's
Time and Money
The Principle of Other People's Time and Money
applies to all of the work product of a developer: code, reports,
user interfaces, models, diagrams, test results, and
documentation. The issue at stake for this rule is not just
code, but rather professionalism and craftsmanship. Remember
the rule that we started with? The Principle of Personal
Character states: Strive to make your code reflect only the best
parts of your personal character. The Principle of Other
People's Time and Money is a less friendly way of saying the same
thing.
Take pride in your work, because your work is you, and
other people will judge you based on your work—sometimes
solely on your work. Even if you don't care about being
judged, do you care about doing the right thing? Do you care
about feeling good about taking money for writing that code? Do
you care about how you and your work reflects on the profession of
software engineering as a whole? Writing code for hire is not a
game for our own amusement, and the quality of each developer's work
reflects on all other developers.
The
Principle of Other People's Time and Money states: A true professional does not waste the time and money
of other people by handing over software that is not reasonably free
of obvious bugs; that has not undergone minimal unit testing; that
does not meet the specifications and requirements; that is
gold-plated with unnecessary features; or that looks like
junk.
|
|
The "Principled Programming Project" is a part of Daniel
Read's developer.* web site (www.developerdotstar.com), which also
features Dan's developer.* column.
|
|
|