Kernighan's lever
Brian Kernighan
famously wrote:
Everyone knows that debugging is twice as hard as writing a program in
the first place. So if you're as clever as you can be when you write
it, how will you ever debug it?
— The Elements of Programming Style, 2nd edition, chapter 2
The following version also circulates on the net:
Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are, by
definition, not smart enough to debug it.
This second quote may or may not be by Kernighan — the questionable
use of "by definition" makes me uncertain — but it is useful as a
provocative sound bite conveying the same essential idea.
It is tempting to interpret Kernighan's aphorism as a warning: Stay away from
clever techniques, it seems to say, because if you write clever code, you will
never be able to get it to work. But this interpretation is unfortunate, and
rests on the false assumption that cleverness is static.
While it is possible that Kernighan intended us to interpret the message in a
specific way, he wisely restricted himself to merely presenting an observation,
allowing us to draw our own conclusions from it.
Pay close attention to what is actually being said: Having written code as
cleverly as you can, you will suddenly face a problem that you are not clever
enough to solve. Certainly, "clever" in this context does not refer to some
innate talent, because nobody is born with the ability to write clever code in
the first place. The "cleverness" required to write and understand intricate
code is an acquired mental skill.
If you are a programmer, you will be familiar with a sense of wonder,
gradually transforming into utter stupor, as you stare at some perfectly
reasonable code that couldn't possibly fail, and yet somehow it does. And since
you are confident that you understand how the code works, having written it
yourself, you feel that you must be able to figure out what is going on. Not
only the desire to deliver working software on time, but other powerful forces
such as pride, stubbornness and curiosity contribute to the motivation that
pushes you onwards through the arduous task of tracking down the root cause of
the error. Suddenly you see it, and you're blinded by a bright light as all
the pieces fall into place. The inexperienced programmer may fall into the trap
of self-degradation: "Oh, look at how stupid I was!" But that same sentiment is
proof that your programming-related cleverness, or skill, has increased: "Oh,
look at how clever I've become!" (Although I wouldn't recommend saying that out
loud.)
Skill is the result of practice, that is, of systematically trying to work
slightly beyond one's ability. Quite understandably, most of us don't spend
that kind of effort unless we have good reason to. Hence, without motivation we
do not practise, but simply cruise along at our current level and never improve
any further.
The mind is very good at rationalising, and will convince us that our
current skills are sufficient, that we are all "good enough"; certainly
better than the average programmer anyway. The human brain will do this trick
regardless of our actual level of skill. So while we all tend to consider
ourselves sufficiently skilled right now, we never regret improving.
You effortlessly wield clever programming techniques today that would've
baffled your younger self. (If not, then I'm afraid you stopped evolving as a
programmer long ago.) But this improvement is the result of practice, and
something must have motivated you to put in all those hours of work.
Kernighan's witty remarks provide a clue: In programming, as soon as you work
at your current level, you will automatically end up in a situation where you
have to work beyond your current level. By means of this very fortunate
mechanism, you will leverage several basic human drives (honour, pride,
stubbornness, curiosity) into providing the motivation necessary for
improvement.
I call this mechanism Kernighan's lever. By putting in a small
amount of motivation towards the short-term goal of implementing some
functionality, you suddenly end up with a much larger amount of motivation
towards a long term investment in your own personal growth as a programmer.
If we deliberately stay away from clever techniques when writing code, in
order to avoid the need for skill when debugging, we dodge the lever and miss
out on the improvement. We would then need other sources of motivation in order
to grow as programmers, and if no such motivation appears, our abilities
stagnate (or even deteriorate).
The psychological concept of flow, somewhat simplified, can be used
to visualise the process. Flow is when you are "fully immersed in a feeling of
energised focus, full involvement, and enjoyment in the process of the
activity" (wikipedia), and it
only occurs when the challenge that you are tackling matches your current level
of skill.
Implement below your ability,
and you get to debug in the "flow" area.
Implement at your ability, and
the debugging will be frustrating, but you gain skill.
You will find yourself situated at a particular x-coordinate, corresponding
to your current level of skill. If writing code is a point on this graph, then
(according to Kernighan's assumption) debugging the same code would
be a point a fair bit directly above it.
It is certainly possible to deliberately pick a low starting point just to
avoid ending up in the frustration area. But this will put you squarely in the
boredom area, and boredom is frankly no better than frustration. However,
should you pick a starting point in the enjoyable flow area, Kernighan's lever
will screech into action and push you sideways through the graph, increasing
your skill until it matches the challenge posed by the bugs in your code.
Naturally, the real world is more complex than this, and you will sometimes
have compelling reasons to go for the boring option, and artificially reduce
your cleverness in order to dumb down the debugging phase. But it may harm
your long-term personal development if you go down that road every single time
you write a program.
In conclusion, the answer to Kernighan's rhetorical question — "how
will you ever debug it?" — is straight-forward: By tackling the problem,
thereby gaining valuable experience and becoming more clever in the process.
And the second version of the quote can be adorned with a single word at the
end: Yet.