Computer programs are the most complicated things that humans make. They must be perfect, which is hard for us because humans are not perfect. Programming is thought to be a “head” activity, but there is a lot of “gut” involved. Indeed, it may be the gut that gives us the insight necessary for solving hard problems. But gut messes us up when it come to matters of style. The systems in our brains that make us vulnerable to advertising and propaganda also influence our programming styles. This talk looks systematically at the development of a programming style that specifically improves the reliability of programs. The examples are given in JavaScript, a language with an uncommonly large number of bad parts, but the principles are applicable to all programming languages.
The two topics:
There is an idea in economics that people work towards their own interests… but it is in fact not true. Humans do not always work in their own interests.
We have two systems: head and gut. Your gut is fast and you can’t turn it off. Your brain can lie to you! Look at a Edward H Adelson’s checkerboard illusion – your brain can be tricked.
Advertising knows this! They have been crafting messages that work on the gut for years. The head knows $199 is not a lot less than $200 but our gut says differently.
This is all important because our head and gut are in play when we make code. Code, programming, is some of the most complex stuff humans make… and we are still doing it entirely by hand, because AI isn’t advanced enough to do it for us. We can’t express what we want in small enough pieces for a computer to calculate it all for us.
Our primary tool is the programming language. We write the language, the computer can transform it into something that can be executed by the machine.
The thing that makes programming so hard is that is requires perfection, because if it’s not perfect, the machine has license to do the worst thing possible – not work correctly. But we can’t actually achieve perfection; and even if we did achieve it we have no way to recognise it. We can’t hold software back to be perfect, we’d never release it. That’s why we release things early so we can find problems quickly.
We have the brains of hunters and gatherers. Nothing in our evolution has prepared us for writing programs.
Programming makes use of head and gut. There are tradeoffs. Doug “I have no evidence at all that gut is involved… but my gut says it’s true!”… but the gut doesn’t really have the data it needs to make rational decisions, that’s the head.
…
Good and bad code… naturally the examples are in JS.
JS has good and bad parts; which is why Doug wrote JSLint, to tell him when the code is using a bad part.
WARNING: JSLINT WILL HURT YOUR FEELINGS! Doug “It really does, it hurts me too!”
People have an emotional reaction to the results of JSLint. Rationally they went to a code quality tool and asked for advice; but they don’t like the advice.
Braces on the same line (“on the right”) or on a new line (“on the left”):
foo {
}
foo
{
}
If someone is told to go between the systems, they get upset. The gut dislikes it so the head tries to rationalise it.
In JS though, you can actually break stuff due to automatic semicolon insertion:
return
{
ok: false;
}
SILENT ERROR! Because ASI has put a semicolon after “return”. So in JS there is a very good reason to say put the brace on the right. So you should prefer forms that are error resistant.
Switch statement fallthrough hazard. It kind of persists the problems of goto. While there is a problem, DC initially decided not to create a warning as it would lose some elegance to avoid an error that hardly ever happens. But then the next day it was proved he had that error in JSLint!
“I had a moment of enlightenment.” Elegance for its own sake is worthless.
Also saying “that hardly ever happens” is the same as saying “it happens”.
Code style should not be about personal preference, it should be about making more robust code, something closer to perfection than we could do otherwise.
While the Romans WROTEINUPPERCASEWITHNOPUNCTUATIONORSPACES people who had to copy it later introduced lowercase, word breaks and punctuation because it reduced the error rate, it removed ambiguity.
Programs must communicate clearly to people, not just to the compiler. People are important. Use elements of good composition where applicable. For example, use a space after a comma, not before.
We want people to focus on the substance and not the formatting.
Good rule: no space between a function name and the first bracket; one space everywhere else. But then you get to Immediately Invocable Function Expressions…
(function () {
...
})();
…but then you have the extra brackets floating around in the middle of nowhere. DC feels this is more readable:
(function () {
...
}());
Never rely on ASI! This breaks:
x = y
(function () {
...
}());
So put the semicolon in!
x = y;
(function () {
...
}());
Don’t use the with
statement. It’s useful but never not confusing. Confusion must be avoided, it creates bugs!
Always use ===
as the result of ==
is hard to anticipate. “It turns out you don’t need double equal…”. If there is a feature of a language that is sometimes problematic and another feature that’s reliable, use the reliable form.
Multiline string literal example – breaks when there’s a space after the \ …you can’t see the problem, but it’s there.
Make your programs look like what they do!
Declare all your vars at the top; declare all functions before you call them. Because of hoisting.
for (var i) {}
…i is not scoped to the loop, it gets hoisted too!
let
is coming and that will have block scope. When that’s available DC’s advice will change. Unless of course you need to support IE in which case stick to var
.
Global vars are evil but sometime necessary; they should be rare and stick out like a sore thumb so DC’s advice is to write them in UPPERCASE.
New prefix – forgetting new can clobber globals. To help avoid problems, name constructor functions with TitleCase (?)
Write in a way that clearly communicates your intent.
++ … “this will be controversial. Controversial does not equal wrong.”
The value of ++ is to reduce large amounts of code to one line; but that’s a bad trade as it becomes incomprehensible. DC eventually just stopped using it. When he has to add one to something he adds one.
++
vs. x += 1
You can get subtle off by one errors if you use ++
and DC has even seen two instances of ++x
when x += 2
would have worked.
Who are the bad stylists? DC identifies four groups:
Designing a programming style is not about selecting features because they are liked, disliked or pretty. It’s about avoiding the abyss. It’s about avoiding broken code, avoiding debugging.
Devs can do this because we are optimists – we know we can go down into the abyss and come out with a fix. It’s why we can’t schedule (estimate) for CRAP.
If we want to be more efficient, it’s not about saving keystrokes it’s about avoiding time spent in the abyss of debugging.
Forms that can hide defects are considered defective.
Language subsetting – “only a madman would use all of C++” – liberate yourself from the parts that don’t work, that will trip you up and cause you pain.
“There will be bugs. Do what you can to move the odds to your favor.”
Good style is good for your gut.
Coffeescript – good to learn from, exposes good parts and not too many bad parts; but has bad parts of its own and not great tooling yet… not recommended for production.
What does DC think about the comma first style? “I think it’s stupid.” Main benefit appears to be saving a few keystrokes, are people truly that feeble?