
Kernighan's Law: You are not smart enough to debug it - dwmkerr
https://github.com/dwmkerr/hacker-laws#kernighans-law
======
smoyer
Over 20 years ago, after I had devised a way to use Gray Code to embed a clock
into a signal without increasing the signal's modulated bandwidth, one of my
engineers said that someday there'd be a "Moyer's Law". I thought that was
funny, so I created one myself:

Moyer's Law: "When we can finally print from any computer to any printer
consistently, there will be no CS problems left to solve."

Since every good law has a corollary, I created one of those too (simply to be
funnier):

The Corollary to Moyer's Law: "The printed dates will still be wrong."

While PDFs have brought us closer to "universal printing", I won't claim we're
anywhere close to solving all CS problems. Sadly, date conversion and
formatting continue to be problems (hint, consider UTC ISO-8601 or RFC3339
dates/times for the JSON representation).

P.S. I don't actually think I'm smart enough to have a law named after me ...
nor have I really contributed enough to "our art".

\-
[https://en.wikipedia.org/wiki/Gray_code](https://en.wikipedia.org/wiki/Gray_code)

\- [https://www.electronics-
notes.com/articles/radio/modulation/...](https://www.electronics-
notes.com/articles/radio/modulation/frequency-modulation-fm-sidebands-
bandwidth.php)

~~~
vbezhenar
Temporal literals really deserve dedicated syntax in JSON. I'm bored to parse
yet another "18.2.2020".

~~~
smoyer
I agree but I'd like the generic implementation of that. JSON schema never
really took off and I believe that part of the reason is that there's not a
way to indicate what type might be contained in a string or number (I'm okay
with JSON booleans and null). As ugly as it could get, adding XML Schemas to
XML documents did in fact help the parser.

The reason I stated I'd like the generic version is that there are other types
that we use consistently. There's a very nice RFC available for telephone
numbers that we've started following and we can marshal/unmarshal pretty
easily from strongly typed languages (where we control the code), but wouldn't
it be nice if there was a standard way (within the JSON to let systems know it
was a telephone number?

\- [https://tools.ietf.org/html/rfc3966](https://tools.ietf.org/html/rfc3966)

~~~
silvestrov
I think it's time for a JSON version 2.

a) no mandatory quotes for dicts keys b) date and time intervals in iso 8601
format. c) optional type-specifiers for strings, so we can add e.g. ip4 and
ip6 addresses. Eg. { remote: "127.0.0.1"#ip4 }

e.g. { guests: 42, arrival: @2020-02-17T17:22:45+00:00, duration: @@13:47:30 }

~~~
jnwatson
There’s a corollary in there to Greenspun’s tenth.

Any sufficiently complicated serialization technology contains an ad-hoc,
informally-specified, bug-ridden, slow implementation of half of ASN.1.

------
stared
It reminds me of a typical code written by scientists.

IMHO there is the biggest gap between the raw intelligence and software
engineering skills (including good practices). So, it means that most of the
code ends up as code-golf-style contraptions, incomprehensible for anyone else
(including their future themselves).

Full disclaimer: I used to be that guy who liked "clever hacks". Now I try to
make code readable in the first place (largely thanks to Python philosophy).

~~~
Balgair
I'll second this.

One grad student friend of mine traded me a case of beer for a Saturday of
help on his code. It was some code to record spike timings in the olfactory
cortex and also control valves (smelly research).

By the 12th nested for-loop, I gave him back the beer.

~~~
hinkley
I thought this story was going to end with you consuming the beer on the spot.

On several occasions, and with lesser crimes, I've told the person something
like "I think you are confusing yourself with your own code. I want you to
change to meaningful variable names (stop recycling variables) and factor out
a couple of child functions here, and here. If you still can't see the
problem, come get me and we'll try this again."

~~~
Balgair
> I thought this story was going to end with you consuming the beer on the
> spot.

Haha, no way. Grad students are poor as is. Drinking a month's beer budget in
front of the guy would be bad, leaving him with that code was cruel enough.

------
edejong
"The competent programmer is fully aware of the strictly limited size of his
own skull; therefore he approaches the programming task in full humility, and
among other things he avoids clever tricks like the plague. " \- EWD 340 [1]

[1] E.W. Dijkstra - The Humble Programmer, ACM Turing Lecture 1972
([https://www.cs.utexas.edu/~EWD/transcriptions/EWD03xx/EWD340...](https://www.cs.utexas.edu/~EWD/transcriptions/EWD03xx/EWD340.html))

~~~
ScottBurson
Really interesting to read this now, almost 50 years later. So much has
changed — and so little has changed.

~~~
edejong
Absolutely. Many of Dijkstra's EWDs have aged remarkably well. [1]

[1]
[https://www.cs.utexas.edu/users/EWD/](https://www.cs.utexas.edu/users/EWD/)

------
pattisapu
There's a saying in my family, which is full of good cooks:

The sign of a great cook is not the ability to make great dishes -- it's being
able to fix dishes that someone else screwed up!

~~~
contingencies
Nice one. Added a paraphrased version to
[https://github.com/globalcitizen/taoup](https://github.com/globalcitizen/taoup)

~~~
pattisapu
Wow! Interesting to see "firsthand" how the various bits of folk wisdom we
come across make it into fortunes. Nice work on this project by the way!

------
arsome
I've always found this one a bit peculiar - usually debugging is about looking
at something on a simpler, lower level than implementation. Rather than
looking at a whole set of logic, let's step through it piece by piece, look at
each operation. When done slowly with care and understanding of the lower
level components in the system, debugging code is simpler than learning and
implementing most architectural patterns in all but the most extreme of
circumstances (compiler bugs, hardware faults).

Or maybe I just spent too much time in OllyDbg at a young age to notice.

~~~
leeoniya
> usually debugging is about looking at something on a simpler, lower level
> than implementation

the lower you go, the less context you have about the author's _intent_. with
too-clever code it's easy to miss the forest for the trees.

e.g. it usually works fine to fix spelling errors at word level, but less well
to restructure complex sentances without larger context.

~~~
ves
Please tell me “sentances” was intentional.

~~~
yellowapple
Waht maeks yuo tihnk twas intantional?

------
BossingAround
I don't know, if I can debug code on my workstation, that does not seem
extremely difficult. Time consuming, if anything, but I feel like anyone with
sufficient grit could do that, regardless of education.

Tracking down a bug and fixing it with a one-liner does not feel like
productive programming (though it brings value to the business).

If I can't debug code on my workstation, e.g. it's running on Kubernetes with
service mesh and a cool feature must be added, that's when all hell breaks
loose. For example, debugging why Kubernetes deployed on OpenStack will push
an image to its internal repository but won't pull from it, that is hell and
I'd much rather debug HTTPD than that.

~~~
bluGill
For simple bugs yes. However if the bug is a one in a million race condition
between threads where the lock is held/released at the right time except for
one place where it isn't even obvious the other thread can write the data.
This is particularly bad if there are performance considerations and the
design ensures some places where it looks like a race are actually not and so
a lock would be a bad thing. Without fully understanding the complex design
you cannot add the needed lock in without adding in uneeded locks that kill
performance.

~~~
nullc
> However if the bug is a one in a million

This is what RR is for: you only need to be able to reproduce the bug once
inside RR.

> ensures some places where it looks like a race are actually not

Uh be careful, if you're writing in a high level language... such as C: there
are no safe data races.

[https://software.intel.com/en-us/blogs/2013/01/06/benign-
dat...](https://software.intel.com/en-us/blogs/2013/01/06/benign-data-races-
what-could-possibly-go-wrong)

The compiler is free to reorder operations in ways that make what appears to
be a safe data race unsafe.

~~~
bluGill
There are limits you can place on the compiler. There are atomics in the
compiler. There are times when you know you are safe because there is a future
write that is memory barrier protected so even though there is a potential
race, before the other threads can read it this thread will write something
else. There are times where you know the other thread isn't started yet. There
are platform specific ways to flush all the caches long after the race in
question which can be tied to something else that is synchronized across
threads...

~~~
saagarjha
> There are times when you know you are safe because there is a future write
> that is memory barrier protected so even though there is a potential race,
> before the other threads can read it this thread will write something else.

Often it is difficult to prove this to the compiler.

~~~
bluGill
I don't need to prove it to the compiler. I can prove it by a higher level
understanding of my own system. So long as the compiler emits the memory
barrier when I need it to, and the other thread stays in the state where it
won't be reading the memory in question it doesn't matter what the compiler
knows.

------
nitwit005
You're ready for a promotion from software engineer to senior software
engineer once you've spent hours debugging some piece of software, only to
realize it's actually working as intended.

~~~
aewens
Is this implying the debugging was due to the code appearing incorrect or that
the previously preceived erroneous behavior was actually intended?

~~~
nitwit005
The previously perceived erroneous behavior was actually intended. Just code
that's extremely difficult to understand and debug.

------
piinbinary
A possible corollary is that if you are smart enough to make the code simple,
you are also smart enough to debug that code.

(Making simple code for complex problems is hard!)

~~~
davnicwil
I agree it's hard to build a simple solution to a complex problem, but not
necessarily wrt what we normally talk about as problem solving skills in
programming.

What I mean is the hard part is stepping back and actually solving the real
problem in the best way. That might be utterly trivial code wise, it might be
brute force vs optimal. It might be just solving a readily parallelisable
problem on a single thread. It might be a unilanguage monolith instead of
microservices in the 'right language for every task', etc.

The smartness involved in making code simple (and I mean simple, not elegant)
is more about pragmatism, lateral thinking, discipline and focus on end goals
than any sort of analytical smartness.

------
finolex1
The intelligence required to write a piece of code =/= the intelligence
required to understand it. Usually the second is a lot easier. Writing a fancy
Haskell typeclass to structure a problem might require deep expertise or
creativity. Working with such an existing solution isn't as hard.

Even in math or science it's harder to create something new than it is to
merely imitate it.

~~~
s_dev
It's easier to write code than to read. This isn't a fact but it is generally
accepted by many. It doesn't seem obvious at first why but "reading code"
isn't like "reading".

[https://jonathanfries.net/code-is-still-harder-to-read-
than-...](https://jonathanfries.net/code-is-still-harder-to-read-than-write-
part-1/)

~~~
yebyen
It's also called the law of "Uphill Analysis, Downhill Invention" which states
"It is much more difficult to guess the internal structure of an entity just
by observing its behavior than it is to actually create the structure that
leads to that behavior."

Been reusing and repeating this one quite a lot, since I saw it mentioned in
one of this year's RubyConf keynotes:
[https://blog.jessitron.com/2019/11/05/keynote-collective-
pro...](https://blog.jessitron.com/2019/11/05/keynote-collective-problem-
solving-in-music-science-art-and-software/)

(There is a blog-post version behind this link as well, in case anybody wanted
to skim the contents rather than watch video of the entire talk to find out
how it fits in.)

~~~
gherkinnn
Uphill Analysis, Downhill Synthesis is a major point in the book _Vehicles_.
[0]

Fascinating thought experiments.

Here’s an introduction on YT [1], though it really only scratches the surface.

[0]
[https://www.goodreads.com/book/show/483485.Vehicles](https://www.goodreads.com/book/show/483485.Vehicles)

[1]
[https://m.youtube.com/watch?v=A-fxij3zM7g](https://m.youtube.com/watch?v=A-fxij3zM7g)

------
hinkley
The trick, I believe, is in convincing yourself that finding a simpler way to
achieve the same result is a more worthwhile form of cleverness.

You still get to be clever, but only you will ever know how clever.

------
xt00
Kernighans law:

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.

(Brian Kernighan)

The rest of the laws are interesting, so I’d recommend taking a look as well..

------
lkbm
I liked the optimistic twist on this, Kernighan's Lever:
[http://www.linusakesson.net/programming/kernighans-
lever/](http://www.linusakesson.net/programming/kernighans-lever/)

Kernighan's Law means that you're continually forcing yourself to level-up in
order to debug your own code. It prevents stagnation.

Use caution in multi-developer environments. :-)

~~~
strangerw
Or it could mean, be too stupid for complex tools, be dumb and choose
[simplicity].

[simplicity]:
[https://github.com/dosyago/dumbass](https://github.com/dosyago/dumbass)

Personally I find the original law inspiring.

~~~
Bartweiss
A related interpretation: your debugging tools need to be _at least_ as good
as your programming tools. Ideally, better.

Debugging a K8 cluster with print statements is hopeless, but if the cleverest
code you can write in a dumb editor is going through a good test suite and
profiler, you might be fine. How many as-clever-as-possible optimization
tricks have been made viable by Valgrind?

------
_bxg1
I write every piece of code as if someone else is going to have to be able to
use it later, even if it's just for me. And I find remarkable overlap between
the clarity that some random person would need and the clarity that future-me
ends up needing.

------
yellowapple
This law is actively biting me in the ass right now as we speak ;)

Gotta love T-SQL, where hard things are easy, easy things are hard, and one
must perpetually choose between extreme cleverness and extreme verbosity
because there is absolutely no middle ground.

------
madez
> 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.

The expression "by definition" is misplaced here. The first proposition
"Debugging is twice as hard as writing the code in the first place" is not a
definition. At best, we can treat it as an axiom. In any case, the conclusion
"if you write the code as cleverly as possible, you are not smart enough to
debug it" does not follow by definition.

~~~
hinkley
I promised myself I was going to stop getting sucked into pedantry.

I believe that the sense in which he meant 'by definition' is that it's
tautological to say that more of something is more than less of something.

For n > 0, 2n > n

~~~
madez
The meaning of what the quote is saying is clear. It is also clear how the
logical reasoning is supposed to be. My - admittedly pedantic - point is that
the choice of words is incorrect.

------
duxup
I worked in a technical support department for a long time. I often was the
guy between the customer (the technical customers) and the engineering teams.

After a while figured out pretty good ways to manage my interactions with the
engineering teams, despite having no coding experience or really any
visibility to the code.

How I worked with Development and Continuation teams was DRAMATICALLY
different.

When working with "Development Engineering" (they wrote new code) I always
asked them:

"What does X, Y, Z do?"

Effectively I always asked them what they think the code "should" do and what
the results should be. There was no point in presenting them "OMG it doesn't
do the thing" because they would just panic, get defensive / shutdown. Rather
I understood they knew what their code does (well what they thought it did)
and asking them that was the key to get them talking / sharing.

After I had their words and phrasing I could better present "Hey we see A, B,
C under D conditions. I expected to see X, Y, Z." That would get a lot more
buy in from those folks.

I also had to avoid some of the more obvious "hey it does G" where G would
obviously break the feature entirely... they often didn't understand use cases
(one guy I'm pretty sure didn't even know what the product did, but he could
program an ASIC for sure..) so you had to be careful about spelling out
customer experiences and rope in a program manager if you felt there was a
fundamental problem.

When working with Continuation Engineering (bugfixes and etc):

These guys were much more receptive to the customer's story on on how the
customer is using the code / equipment, and you could much more quickly
present "Seeing A, B, C, under D conditions. So then I changed L and got M..."
and so on. Continuation engineering grocked the meaning of why someone would
change L... and so it was helpful. Continuation didn't often know what the
code "should do" (or they weren't confidant in their understanding) so just
saying "Saw A... that's not right" meant nothing to them. In contrast
development engineering needed to talk about the happy path first.

Note that much of this occured after I gave them a good writeup / heads up of
all the information I had (even if they didn't read it I never kept anyone in
the dark).

It got to the point that if a panicked support call came in and it was end
times and someone gave engineering a heads up, they would ask it be assigned
to me if I was in the office. Technically I was far from the best tech, but I
could talk to engineering.

It was telling how much a difference there was between debugging and initial
development.

~~~
datenhorst
> Effectively I always asked them what they think the code "should" do and
> what the results should be.

[https://rubberduckdebugging.com/](https://rubberduckdebugging.com/)

~~~
duxup
Pretty much, just warming them up to get them into debug mode ;)

For me I (and the customer) all thought we knew what it should do, but it's
always good to spell it out for everyone so we all understand when / or even
if we're seeing an exception.

Lots of "Woah hey is that what the protocol really says?" moments too.

------
lowbloodsugar
Hit a performance cliff and rewrote a simple divide-and-conquer multithreaded
application into a two-thread solution using hand-rolled map and list
structures using optimistic concurrency with atomics and paying attention to
dining philosophers. Didn't work first time, funnily enough.

For about a day I was terrified that it would never work. Then I found my
mistakes (two).

Except in emergencies like this, my time is much better spent writing
"inefficient" yet easy to develop code that everyone can understand.

------
KerryJones
This highlights the importance of writing clean, legible, and well-thought-out
code but is also an excellent example of hyperbole and false statistics. I've
debugged my code consistently for 15+ years (which if you were to take this as
law, would imply I doubled my intelligence with a crazy-high compounding rate,
and while I enjoy my ego, that's a bit too much for me).

------
tomrod
I'm tickled pink to see Hyrum's Law included here. Hyrum and I were grad
school chums. Not too many brighter folks out there.

~~~
dwmkerr
That's awesome! Hyrum's Law is one of my favourites in the repo and one I
share the most often :)

------
commandlinefan
Writing code that can be debugged is a skill that can’t be taught, only
learned from experience. Sometimes painful experience.

------
carapace
See also Mark Miller's adages:
[https://web.archive.org/web/20090215132813/www.caplet.com/ad...](https://web.archive.org/web/20090215132813/www.caplet.com/adages.html)

------
gombosg
Such a good read, thanks for sharing this page! (And the authors of course)

------
joker3
The output of a machine learning algorithm is code that no one was clever
enough to write. In light of Kernighan's law, that should give you pause.

------
tomohawk
This is one of the things I learned to really appreciate about Go. Code
readability and comprehensibility is way better than any other language I've
ever used.

------
contravariant
Although curiously it's a _lot_ more difficult to write simple code (if you
want it both complete and correct).

------
lr4444lr
Eh... Not denying the law is correct, but this kind of thinking makes more
sense when you're not doing some cloud SaaS solution that can have daily
changes due to business needs and continuous deployment. Code can get
complicated over time because business moves fast and there isn't time do
everything perfectly. It isn't always people trying to be too clever by a
half.

~~~
Swizec
The business folks can be too clever too.

Dealing with that at work right now. We got super clever, changed a couple
times, tried to be even more clever, and engineering gets to pick up the mess
and try to make it all work.

------
CodeWriter23
I say: get clever, spend the inordinate amount of time debugging, then level
up.

------
artemonster
Disappointed that there was no „Greenspun‘s tenth rule“. It‘s HN, after all ;)

------
leeoniya
title would be less vague as

/s/it/your cleverest code

~~~
laumars
> _title would be less vague as_

True but that's too many characters for HN's title field. Which might be why
it was submitted with editorialised version.

> _/ s/it/your cleverest code_

massive nitpick but you should be suffixing rather than prefixing the regex
with a slash:

    
    
        s/it/your cleverest code/
    

As I said, this is a massive nitpick; literally the only reason I pointed this
out was because the submission was about debugging code and I liked the irony
of debugging someone's posted about debugging code :)

(there is another law somewhere about people who nitpick are prone to making
mistakes in their corrections thus getting nitpicked themselves -- I'm hoping
I'm not exception hehe)

~~~
jerf
"there is another law somewhere about people who nitpick are prone to making
mistakes in their corrections thus getting nitpicked themselves"

[https://en.wikipedia.org/wiki/Muphry%27s_law](https://en.wikipedia.org/wiki/Muphry%27s_law)

------
austincheney
Another way to think about this: The more steps that exist between the
developer and the end product the less likely the developer is to care or
identify whether their solution is clever.

------
mkagenius
Why do we pay attention to BS like this?

------
amai
Which brings us to the interesting question: Is God smart enough to debug it’s
own code?

------
shanemlk
And if you write Laws thinking you're Moses, you're not smart enough to code.

~~~
jodrellblank
You don’t think _Brian Kernighan_ is smart enough to code?

