>> DOUGLAS CROCKFORD: Thank you very much.
Welcome to the YUIConf Gala Costume Masquerade.
It's great to see all of you here in your
festive costumes; you all look fabulous.
We are here at YUIConf at Yahoo!'s -- where
are we?
-- Great America campus in Santa Clara, California.
Tonight: Section 8, JavaScript Programming
Style and Your Brain.
This might seem three unusual things to talk
about in one talk -- how could these things
possibly be related to each other?
JavaScript and brains?
What's the connection?
There actually is a connection.
JavaScript and programming style and brains?
Yeah, there's a connection and it's an important
connection, and surprisingly and hopefully
entertaining.
This talk comes from a scientific discovery.
There were some social scientists who were
doing some work, as they do, in trying to
understand human intelligence.
How do we think?
How do our brains work?
They came up with a set of simple experiments
and their results were really surprising.
They published their results and the scientific
community said that can't be right, there
must have been an error in the design of the
experiments, there must have been some error
in the evaluation of the data.
This cannot possibly be the correct explanation
for how we think.
But the results were at least interesting
enough that other people attempted to replicate
the studies, and then did follow on studies
and new experiments.
The conclusion was: yeah, it's true, we actually
think like this.
This is sort of how science works, where someone
will come up with an experiment which has
a conclusion which contradicts what is commonly
understood by the scientific consensus, and
it will immediately be challenged.
But then we'll try to replicate it, and if
it bears out then the scientific consensus
changes to adopt that, until further experiments
will contradict again.
Then there's a Nobel Prize.
All of that happened in this case.
This is how science happens.
This is all told in a wonderful book: The
Science of Fear by Daniel Gardner.
Gardner talks about this research and its
implications on society, and the fact that
because of the way we think, we tend to misunderstand
what danger is.
We fear the wrong things.
The consequence of fearing the wrong things
is that you actually put yourself in greater
danger.
Great book, I highly recommend it.
What was this discovery that was so amazing
and unusual and probably true?
It was that there are two systems in the brain.
System two could be called the head.
It's where we do analytical thinking, it's
where we do arithmetic and mathematics.
It's where we think deep thoughts.
It's great, but the problem with it is it's
kind of slow.
It's because the head is kind of slow that
we had to invent computers, because the modern
world demanded a lot of number crunching,
and we're just not very good at that.
We needed machines that were faster than we
were at doing that stuff.
Then there's system one, which could be called
the gut.
It's evolved from the flight or fight response.
It is very, very fast, but there are tradeoffs
in the way it's fast, so it makes mistakes.
If you ever saw a cat just standing there
and then suddenly he freaks out and runs,
and then he stops and goes yeah, I meant to
do that, that's the flight or fight response.
The biases in that system are set so that
false positives are OK, because it's better
to get a false positive than a slow positive,
because then you don't have time to get out
of the way of whatever's at you.
You'll see a flock of birds suddenly take
off for no reason and come back; that's that
mechanism.
We got that.
The gut is really fast, but it's only approximate
because it doesn't know arithmetic, it can't
solve hard problems.
But it's not trying to solve hard problems,
it's just looking for certain kinds of patterns,
and when it sees those patterns it reacts.
Now, neither the head nor the gut are surprising.
I mean, we all know about that.
My head tells me this but my gut tells me
that.
We're always experiencing that kind of stuff.
The surprise in this research was the connection
between those two systems.
It turns out that the gut informs the head.
The gut sets up the assumptions that the head
is going to use in doing its computation.
The head is not generally aware that that's
the case.
The things that the gut tells the head are
weighed as more important than things that
the head itself has experienced.
That makes it really easy to confuse people
by confusing their guts.
This was news to the scientific community,
but there is another community which has known
about this stuff for a long, long time, and
that is of course the advertising community.
They figured this stuff out decades ago; this
is not news to them, because a lot of their
business is selling stuff to us that we don't
need.
They create wants for things that we don't
really want.
How do they do that?
You don't do that by talking to the head,
you do that by talking to the gut, and nobody
is better than the tobacco industry.
Because look at tobacco.
What does tobacco do?
It makes you smell bad.
From the first time you light up, you stink.
Tobacco does that.
Then your teeth turn yellow.
Then you get sick, and then you die.
That's what tobacco does.
So how do you sell a product like that?
You don't sell it to the head, you sell it
to the gut.
If you ask a smoker "why do you smoke?"
Well, why, that's an analytical question,
so that goes to the head.
But the head is going to now start thinking
with facts that it got from the gut, and the
gut says cigarette smoking is not dangerous
because of the way the gut looks at danger;
it's looking at immediate danger, it's looking
at shocking danger.
Slow death doesn't register.
So slow death is as good as good for you.
If you have any logical system and you start
with false premises, you can reach a false
conclusion.
I mean, we know that; logic tells us that.
But that's how we think.
You can ask a smoker "why do you smoke?" and
you can be sitting with them in a restaurant
and if he were rational he'd go "I smoke,
well that's stupid, I should stop immediately."
But that's not what happens.
Instead he's trying to think "why do I smoke?
There must be good reasons for it.
Um, it makes me popular."
And he'll say that not noticing that the healthy
good smelling people who are near him are
trying to get away so he doesn't taint his
food.
So people will smoke until it kills them,
until they die.
You could say that's because of nicotine addiction,
they're addicts and that's why it happens,
but that doesn't explain brand loyalty.
Most smokers will stick with the brand that
got them hooked until it kills them.
That's not addiction, that's something else.
That's some confusion that's happening in
the gut.
Let's switch for a minute and talk about computer
programs, a completely different topic.
Computer programs are the most complicated
things humans make.
We don't make anything else which is as complicated
as programs.
Programs are made of a large number of parts,
usually expressed as statements or variables
or functions or other things, and they all
have to work together in a way which is amazingly
complicated.
There's nothing we do that's more complicated
than software.
You could point at systems which are very
complicated, like an airplane is very complicated,
and that's true, but the most complicated
component in an airplane is the software.
That's true of all systems today.
Software is complicated.
People are not good at that, so early on when
we started programming there was this idea
that programming is just too difficult and
we should write programs that can write better
programs than we can, because people are just
not very good at this.
Once we can get the program to do that, we
can then tell the programs "make a program
that's better than you," and we keep doing
that until they become our overlords.
That didn't happen.
Artificial intelligence failed.
Artificial intelligence has done a lot of
amazing things -- it can play grand master
chess and a pretty good game of Jeopardy now
-- but you can't give a set of requirements
and custom router views to a computer and
have it write the program for you.
It can't do that.
We're still writing programs by hand.
We've made extremely small progress in the
evolution of technological thinking around
programming.
The most powerful tool we have is the programming
language.
That is a partnership between us and the computer
where it's doing some of the work and we're
doing some of the work.
The programming language allows us to work
at a higher level of abstraction, which allows
us to be more productive, but still it's basically
handmade stuff.
Programming languages are extremely important
in that they control, or shape, the way that
we think about things.
Sometimes that's a really good thing if the
programming language helps us to organize
things well, but that can also create blind
spots in us.
If you're using a programming language that
does not offer recursion, you're not aware
of what a valuable tool recursion is.
Or if you have a language that doesn't have
closures, you're not aware of what a valuable
tool closures are.
So, programming languages work for us and
against us.
The thing that makes programming so difficult
is that it has to be perfect.
A program has to be absolutely perfect in
every detail for all possible inputs and all
possible uses, even including uses which were
not anticipated in the design of the program.
If any flaw is found in the program, the computer
has license to do the worst possible thing
at the worst possible time, and it is not
the computer's fault.
Whose fault is it?
It's the programmer's fault.
It is the programmer's fault for having created
a program that was not perfect.
You would think that the way we should do
this stuff is we should hold onto the programs
and keep working on them and refining them
and cleaning them until finally they are perfect,
and then we'd release them.
We don't do that because we would never release
anything.
Instead we put out stuff which is known to
be imperfect and just hope that we get away
with it, that we won't find a bug in it until
the next cycle.
Sometimes we get away with that, and very
often we don't.
So we have this problem of perfection.
Humans are terrible at perfection.
We are greatly imperfect creatures.
I am a very imperfect person, but I program
because we've got no one else to do it.
We are hunters and gatherers.
I don't mean that metaphorically.
There has been no human evolution since the
Paleolithic era.
We are those guys, we've got their brains.
We were selected for running around, our heads
were designed for thinking about strategies
for getting food, and our guts were designed
to get us out of danger when the predators
were coming after us.
We're using that brain now to program computers,
and there is no reason to think that that
should work.
Somehow it does.
It's miraculous, it's crazy.
We're using everything we got.
Obviously we're using our head to do the analytical
stuff, and it can do it.
It needs to keep the problem and the state
of the program and all of the stuff it's working
on.
You try to keep the whole model in your head
so you can reason about it.
But if you try to teach programming, it's
really hard.
We don't have an algorithm for how we do it.
As we're decomposing a problem, sometimes
we're going top down, sometimes we're going
bottom out, inside out, outside in.
We're constantly changing strategies as we're
working on this.
Nobody can describe how we do that.
Somehow we all figured it out, and we do that
every day, but we don't know how we do that.
It occurs to me that it must be the gut that's
allowing us to do that.
It's the thing that shifts us from one strategy
to another, that gives us the occasional flash
of insight which makes the whole thing work.
We could not program without our gut.
I have absolutely no evidence to justify that
statement.
But my gut tells me it's true, so I believe
it.
Much of the craft of programming is making
tradeoffs.
There's never a perfect solution to anything,
which is one of the things that makes perfection
unattainable, so we're constantly having to
tradeoff space for speed, or other things.
The gut, unfortunately, is extremely bad at
making tradeoffs.
Sometimes the gut, instead of helping us,
significantly hinders us.
We'll talk about some of the consequences
of that.
The programming language I'm going to use
for examples tonight is JavaScript, obviously,
but the things I'm going to talk about are
applicable to all programming languages.
It's just JavaScript is kind of special, partly
because it has good parts.
I can tell you that I discovered that JavaScript
has good parts, and that was the first important
discovery of the 21st century.
Everybody has discovered for themselves that
JavaScript has really bad parts.
JavaScript was designed in about ten days,
and somehow in those ten days Brendan Eich
managed to get some good parts in it -- and
they are really, really good -- but he got
a lot of bad stuff.
There was just not time to try it out and
make sure it worked right, and it doesn't,
and it's horrible.
My first couple of years working with JavaScript
were extremely painful, partly because I decided
not to learn the language before I started
working in it, which was about as stupid a
thing as you could do.
I did that.
But I kept running into all these sharp edges
that the language had, so I decided I needed
to make a tool to help me manage this crazy
language.
I created something called JSLint.
I started with a Pratt parser.
Pratt parsers are amazing things.
You can write compilers really efficiently.
It's a lovely technique.
I owe you a talk on that, because it's fascinating.
Just a little bit of fluff, and suddenly you've
got a compiler.
It's great stuff.
Having this JavaScript compiler written in
JavaScript, I decide to make a Lint tool out
of it to help me find problems in my programs,
because there were a lot of them.
I started hanging out on comp.lang.javascript,
which was on Usenet.
Anybody remember Usenet?
Yeah.
People would come on and say "hey, my program
doesn't work," and they'd post it.
I'd take it and throw it in JSLint and see
if I could automatically figure out what the
problem was.
Sometimes I could and sometimes I couldn't;
sometimes the way they were coding was just
so complicated or so error-prone that there
was no way that you could tell if it was right
or wrong.
In cases where these examples suggested rules,
I'd put them into JSLint.
In examples where there weren't, sometimes
it suggested a discipline, that if you had
a discipline then it would be possible to
determine if that was right or wrong.
The program evolved that way.
When I started I had no plan for how JSLint
was going to grow; it basically grew in response
to the things I was learning on comp.lang.javascript.
JSLint comes with a warning: JSLint will hurt
your feelings.
This is true, this is absolutely true.
I hear from people all the time "waaaah, JSLint..."
You wouldn't believe how much mail I get from
people whining about JSLint.
Well, wait a minute.
Let's look at this.
JSLint is a code quality tool.
Its intention is to help people become slightly
more perfect in their programming.
They're running the program on purpose, for
that purpose.
Why are they complaining that it's telling
them how to make their programs better?
I think there's some interference going on
with the gut, that the gut is telling them
they're doing things which are bad.
I determined these things were bad empirically
by looking at bad programs and trying to identify
flaws in bad programs.
They haven't been through the process that
I have, so they just don't understand why
JSLint is telling them to do the things they're
doing.
We've talked about this argument.
Should curly braces be on the left or the
right?
When Ken Thompson designed the B language
he decided to put them on the right.
They could be anywhere.
When the late Dennis Ritchie did the C language
he copied Thompson's syntax, so he put them
on the right too.
But there were guys in their lab who wanted
to put them on the left because they thought
it looked better.
They probably argued about that for a week
and then said leave us out of this, because
this is a stupid argument.
There is no reason for why you should do it
one way or the other.
There isn't.
There is no argument which is right or wrong;
left or right, it's completely arbitrary.
It's like driving -- should we drive on the
left or the right?
The British can demonstrate that you can drive
on the left.
We drive on the right.
It's OK.
It's good there aren't any roads connecting
us with England so we don't have to deal with
that.
It doesn't matter which side we're on, it's
just that we all be on the same side.
I told that story in Bangalor, and it was
like confusion; "what is he talking about?"
If you have someone who's always put them
on the left come into a shop where they put
them on the right, and they say you've got
to put them on the right now, he'll start
to cry.
"No, I'm not going to put them on the right,
that's so wrong.
Can't you see how wrong that is?"
He'll start making up reasons.
The head is now working, trying to figure
out why it's wrong.
"It's more readable?"
He gets more frustrated because it doesn't
make any sense, and he might even hear himself
saying these things and know this doesn't
make any sense, but there's got to be a reason,
because why would I be this passionate, why
would I be crying, if this weren't important?
We'd like to think we're rational.
We're programming computers, we're analytical,
we're mathematicians, we're laying this stuff
out, and we're crying because we had to move
a piece of punctuation from one line to another.
There is something else going on here.
Ultimately, I don't know what the right answer
is, except in JavaScript where in fact we
have a right answer.
You want to put them on the right.
You've got to be consistent, no matter what
you do.
Everybody will agree that it looks stupid
to sometimes put them on the left, sometimes
put them on the right.
You've got to be consistent.
It's like driving.
You've got to always do it the same way, and
everyone will agree that everybody should
do it like they do it.
But we can't agree on how it should be.
I think Thompson did the world a disservice.
He could have easily fixed his B compiler
and said it's got to be on the right, dammit,
and shut up or you get a syntax error, end
of story.
But he didn't, he left it sloppy.
That introduced some personal expression into
the thing, so we can't agree.
Partly we can't agree because there isn't
a right answer, except in JavaScript, because
of semicolon insertion, which does this stupid
thing if you have a return statement that's
returning an object literal instead of returning
an object, it returns undefined.
You get no compile time warning, no runtime
warning.
Your program may not fail at the point here;
it may fail some minutes later, which makes
debugging really hard.
In debugging if you finally track it down
to this line, you can look at that for hours
and not understand what's wrong with that.
That should work.
This is due to a terrible design error in
JavaScript.
This was a blunder, it's awful.
But if you always put your curly braces on
the right, you will never suffer.
Once after explaining this at a talk, someone
came up to me and said "wow, that thing about
the return statement, that is so right.
From now on on all my return statements I'm
going to put them on the right, but the rest
of the time I'm still going to put them on
the left."
Prefer forms that are error resistance.
For no cost, if you just say I'll do this
thing for which there isn't a right answer
and do it this way, you avoid a terrible problem,
and the net cost of doing that is zero.
If you look at it in terms of tradeoffs, this
is a good tradeoff.
For zero cost, big benefit, you're trying
to be perfect?
This is good.
Your gut might be saying no, this is so wrong,
can't you see how wrong this is?
The gut is really bad at making tradeoffs,
but the gut will tell the head yeah, we're
making a good tradeoff.
But you're not.
The switch statement.
I have to tell the switch statement story
again.
Early in the development of JSLint someone
wrote to me and said "you know, there's a
problem with the switch statement."
The switch statement was designed by Thompson.
He modeled it after the Fortran computed goto
statement, which is now recognized as harmful.
But that hadn't been completely accepted yet.
There's this goto-ness in it, in which you
really don't have a set of cases, you've got
a set of labels and the code will fall through
to each other.
It's really a computed goto statement, which
is terrible.
You can have fall-through going on.
This guy wrote to me and said "that's sometimes
a problem.
When I'm looking at the code it's really hard
to see where the fall through occurs, and
that can be a difficult thing to debug, so
your Lint program should warn about that."
I thought about it, and I wrote back to him,
I said "well yeah, that's true, I've seen
it, but that hardly ever happens.
On the other hand, you can optimize the flow
going through all these cases and that could
be quite elegant.
There's value in that, so looking at the tradeoff,
I think it's probably better not to warn on
that."
OK.
The next day, the same guy wrote to me and
said he found a bug in JSLint.
I'm always happy to hear of that, so I threw
the debugger, and it turned out I had a case
that was falling through.
In that moment, I achieved enlightenment.
We like to think we spend most of our time
power typing.
"Yeah, I'm being productive, I'm writing programs!"
But we don't.
We spend most of our time looking into the
abyss, saying "My God, what have I done?
How am I ever going to make this work?"
Once we figure it out, we forget that we did
all of that.
It's sort of like the way we forget the false
positives that the gut triggers.
If we observe all of the false positives then
the gut couldn't work anymore, because we'd
be analyzing our reactions instead of responding,
which is what the gut wants us to do.
I got that really wrong.
What was my mistake?
That hardly ever happens means the same thing
as it happens.
This is the gut talking, and the gut is confused
about number.
The gut thinks that a lot has more value than
all.
The gut thinks that not very much, or not
very often, is the same as none, or never.
That's not true; I mean mathematically we
know that's not true, but the gut tells us
that.
So that caused me to reach a very wrong conclusion
about the safety of switch statements.
Normally when we make mistakes we just forget
about it and keep going.
We spend most of our time making mistakes,
not power typing, because there's something
wrong with us.
I used to think that everybody should learn
programming when I first started learning
it and thinking about how to organize the
world in terms of data structures and algorithms.
I thought wow, this is such an amazing way
to organize information -- everybody should
learn to do this.
I don't think that anymore.
I think there has to be something seriously
wrong with you in order to do this work.
A normal person, once they've looked into
the abyss, would say I'm done, this is stupid,
I'm going to go do something else.
But not us, because there's something really
wrong with us.
A good style can help produce better programs.
Style should not be about personal preference
or self-expression.
Some people think that style is the stuff
in your program that the compiler ignores,
and because the compiler ignores it, you've
got license to do whatever you want with that
because it doesn't matter, it's not part of
the important information.
You can structure it any way you want, just
to show off or to amuse yourself or to express
your individuality.
That's not what it's for.
Let's talk about style.
The Romans wrote Latin all in uppercase with
no word breaks or punctuation.
They were the biggest empire in the world
at one time, and they did fine with this.
It's definitely harder to read from our perspective.
Like, on the third line, you could read that
as "NOW OR DB REAKS".
You have to work a lot harder in order to
parse the text and understand what it says.
This worked fine for the Romans up until about
the time Constantine established Christianity
as the state religion of the Roman Empire.
At that point it became necessary to replicate
all of the Holy documents and distribute them
over the empire.
There was a problem, because they didn't have
the originals of any of these documents; all
they had were copies of copies of copies,
and none of the copies agreed.
That was a problem because they were claiming
their spiritual authority on the written word,
and nobody was really sure what the written
word said.
They decided well, we need to get better at
this.
It turned out this style of writing was contributing
to the problem.
This turns out to be really hard to copy by
hand accurately.
Medieval copyists introduced lower case, word
breaks, and punctuation in order to improve
their error rate.
It made it easier to extract the information
from the texts and to copy them into good
copies.
It worked -- this was a very effective way
of making their copying much more reliable.
Gutenberg copied this convention when he laid
out his Bible, and it's been in printing ever
since then.
It's on the internet now.
This is the way we do text, not just in religious
texts now but in academic work, popular work,
fiction; everything uses these conventions
because they work.
We've been using these now for many centuries.
It's a good idea, and I think to the extent
it makes sense, we should continue to use
these in programming too, because the most
important thing for a program is for people
to understand it.
This is a convention that people can understand.
We have centuries of evidence about it.
But what they demonstrated was that use of
good style can help reduce the occurrence
of errors.
Since we're going after perfection, we want
a style which helps us to do that.
There have been lots of books written about
style in literature.
One of my favorites is William Strunk's Elements
of Style.
It's very influential.
It was written almost one hundred years ago.
Some of his advice is a little dated now,
just because English has continued to evolve
as a language, but much of his advice is still
really, really good.
Programs must communicate to people.
There are some people who think as long as
the compiler understands what I meant, that's
all that matters.
That may be the least important thing.
It's more important that humans be able to
understand it, because we need to keep that
thing working.
Particularly as we get more and more agile,
programs are never finished, so you can't
say it's in the can, it's done.
It needs to always be in a form which is always
editable, and in order to be editable it needs
to be readable.
We want to use the elements of good composition
where applicable.
For example, if you have a comma, you put
a space after it, not in front of it.
Even though the compiler will let you put
it in front, there's no reason to do that.
It looks stupid, and you don't want to write
programs that look stupid.
Now, the rules of English are not good enough
for software.
There were attempts at trying to create programming
languages which look like English, and they
didn't work because English is not precise
enough.
You need extreme precision as you're trying
to approach perfection.
The computers are not smart enough to make
sense out of wacky prose, so we need to be
much more specific.
We have new kinds of ambiguities that we need
to be concerned about that we didn't need
to be concerned about when we were writing
in English.
For example, we've got parentheses which can
indicate grouping, and they can also indicate
invocation.
One way to help us distinguish which of those
is going on is that when we're grouping, we
put a space in front of it, and when we're
invoking we don't.
In these examples foo is a function, so there
should not be a space, it should be adjacent.
Return is not a function.
In some languages it could be a function but
in JavaScript it's not, so we should make
it clear it's not a function.
There should be a space there.
Here we have an anonymous function, but it
looks like we're calling a function called
function, and that's not what we're doing.
We should put one more space in there to make
it clearer.
You could argue that the reader ought to be
able to figure this out, and in fact the reader
can.
You could figure out all these bad examples
and make sense out of what was really going
on, but that is not where the reader should
be spending their time and energy.
They shouldn't be trying to get past your
syntax and your lousy grammar, they should
be trying to understand the thoughts and the
structures of the program so they can make
it work.
In JavaScript we've recently discovered that
immediately invokable function expressions
are a really useful form, but there's a syntactic
hazard in that you can't put them in as the
first thing in a statement because of an ambiguity
in the language.
If the word function appears in statement
position, then that's assumed to be a function
declaration, and you can't immediately invoke
a function declaration.
I think you ought to be able to, but you can't.
The way we get around that is by putting parentheses
around it, and those parens change it from
being in statement position to expression
position, and then there's no ambiguity; we
know it's a function literal.
I see a lot of people wrap the function in
parens, but I think that looks goofy.
What we're talking about is the whole invocation
but we've got these things hanging outside
of it looking sort of like dog balls.
[laughter]
So we have an opportunity here to use the
weirdness in JavaScript syntax to help the
reader, saying no, what's important is the
whole invocation.
I would put the parens around it.
That's better, I think.
We can see everything between the parens should
be treated as a unit, which is the function
being invoked.
That's what we're talking about in this expression.
Now, there's another hazard in the language.
We've talked before about automatic semicolon
insertion.
Here's another example of that.
We can have almost any statement before this
immediately function and it will be misinterpreted.
Instead of setting x to y and then doing our
function thing, it will treat y as a function
and pass the other function to it as a parameter.
That's screwed up.
This is majorly screwed up.
The moral of this is: do not rely on automatic
semicolon insertion.
Put all of the semicolon insertions in all
of the places where they're supposed to go
and nowhere else, because if you don't, things
like this happen to you.
This is another thing where you could read
this code for hours and go "I don't see what's
wrong with this."
If you put it in JSLint it'll tell you right
away what's wrong with it, and that's why
you should pay attention to everything JSLint
tells you.
JavaScript has a with statement, which is
terrible.
It was a nice idea, it was well intentioned,
but it just doesn't work right.
We've got this green with statement.
It does one of those.
Can anyone tell me which one it does?
Yeah, well you can't tell.
It could do any of them.
In fact, every time this statement is executed,
it could do a different one.
There's no way you can tell, reading the program,
what it's going to do.
When JSLint's looking at a program trying
to figure out what's wrong, it says oh, you've
got a with statement, that's your problem.
Stop using those with statements!
You don't need it.
There's nothing you can do with a with statement
that you can't do just as well without one,
so just don't do it and you avoid the confusion
that this causes.
Now, some people argue, well yeah, I know
with is screwed up, but still sometimes it's
really useful.
You can do these really clever, useful things
with it.
I'm not saying it's not useful, I'm saying
there isn't ever a case where it isn't confusing.
Confusion must be avoided.
Confusion is the enemy.
Confusion is what causes bugs and security
mishaps and all the other things that make
us miserable.
We want to be precise and clear and clean
and elegant and simple; we don't want confusion.
We can't afford it.
JavaScript has a broken double equal operator.
Brendan knew it was broken.
When the language was standardized he was
trying to fix it in the standardization committee,
but Microsoft insisted no, it stays wrong
in the spec, so we've still got it.
Fortunately Brendan was able to get triple
equal in kind of late, so I recommend to always
use triple equal and never use double equal,
because triple equal avoids these stupidities.
Now, some people will ask, well, what about
in the case where double equal actually does
what I want?
Can I use it in that case?
I'd recommend no, don't even use it then,
because someone who's reading your program,
they have to stop and ask is he using it because
this is one of the rare cases where it actually
makes sense ,or is he just incompetent?
Which is it?
Maybe it's undecidable.
Maybe he's read other things you've written
and gone "I don't know."
So don't use it, because it's hard to tell
if it's being used right.
Anything which is indistinguishable from a
common error, if there's a better alternative
then go with that.
If there's a feature of the language that
is sometimes problematic and if it could be
replaced by another feature that is more reliable,
then always use the more reliable function.
The cost is zero.
The benefit is that you avoid a whole class
of bugs and confusions.
Another good tradeoff.
Multiline string literals.
This is a new feature in the language; it
was added in ES5.
I don't like this feature for two reasons.
One is it breaks indentation.
We have deeply nested structures in our programs,
and this breaks it.
The text has to go all over to the left margin,
so it makes the program harder to read, it
really does.
But there's a worse problem than that; there's
a syntactic problem.
The first one is OK, and the second one has
an error in it.
Can anyone spot the error?
Yeah, yeah.
There's a space here.
I mean it's obvious once it's pointed out,
right?
But I don't want to be putting things in my
program that I cannot distinguish from errors.
I want my program to be obviously right, or
at least obviously trying to achieve rightness.
I don't want to be putting in things which
are clearly wrong.
That makes it much harder to spot the things
that are really wrong.
So avoid forms that are difficult to distinguish
from common errors.
Some people say "but I did that on purpose!
I'm intentionally using this thing that looks
wrong."
I don't even have to answer that, do I?
I mean it's just stupid.
Often I hear people saying "it's OK because
I know what I'm doing."
If you knew what you were doing, you wouldn't
be doing that.
This is a common bug.
You see this in most of the C-like languages.
We've got the first statement, which appears
to be doing what that one does, but actually
does what that one does.
When you're reading this program you have
to stop and ask "OK, which did he mean?
Did he accidentally get it right, or not?"
All we know for sure is that the programmer's
incompetent.
Beyond that we really don't know what he's
thinking.
My advice is don't write the top one, write
one of these two.
Figure out which one of these you mean and
write that.
Make it clear.
We have a problem in JavaScript with scope.
Well, it's not really a problem.
Scope is the idea that you've got some block,
and anything that's declared, any variables
declared inside of it, are not visible outside
of it.
That turns out to be a really good thing.
It came with ALGOL 60, it's one of the great
ideas in programming language history.
Most languages have something that's called
block scope where any block defines the scope,
so any variable you declare inside of that
block is not visible outside of the block.
Nice.
JavaScript doesn't have that.
JavaScript only has function scope, which
means any variable declared anywhere within
a function is visible everywhere within the
function.
That turns out to be OK.
You can write good programs just having function
scope.
The problem is that JavaScript syntax looks
like a language that has block scope, but
it doesn't, so that's confusing for people
who learned programming in another language
like Java or C or C++ or any of those others.
They come to JavaScript and they get confused
about what the visibility of variables are,
and confusion leads to errors, so that's a
bad thing.
In a block scope language, the advice is to
declare the variable as close to the first
use as possible.
That's good advice in those languages.
In a function scoped language, that is really
bad advice.
You should declare the variables at the top
of the function, because that's what's actually
happening anyway.
Let me show you what's actually happening
with a variable statement, with a var statement.
A var statement gets split into two pieces.
The var part gets hoisted to the top of the
function and initialized to undefined, and
then the initialization part stays where it
is and later gets executed.
If you declare a variable inside of a block
it doesn't get declared inside of a block;
the declaration part gets hoisted up to the
top of the function so it actually gets declared
at the top, so it's visible everywhere within
the function.
Again, not a bad thing, except the syntax
suggests that's not what's happening.
Because of that confusion, I recommend declaring
all of your variables at the top of the function.
Also, while we're at it, declare all of your
functions before you call them.
JavaScript has these hoisting tricks which
allow you to not do those things, but confusion
happens because most people don't understand
how that hoisting happens.
Even if you understand it the people who are
reading your program may not, and you want
to write the programs so that they can make
sense of your work so that they can transform
your program into something with greater value.
That's hard if the conventions you were using
were causing them to make bugs.
So make your programs look like what they
do.
Now the thing that seems to be hardest for
people to accept is the for var statement,
where you're declaring the induction variable
in the conditional part of the for statement
in the initialization clause, because that's
how you do it in Java.
I mean, it makes so much sense, but it makes
no sense in JavaScript, because that variable
is not scoped to the loop, and if you do things
which are dependent on the scoping of that
variable inside of the loop, your program
will fail.
It works differently than what you're thinking,
and even if you think you understand it, the
person who's reading your program may not.
I've seen really good programmers get hung
up on this.
You've just got to tell them you're not working
in Java.
This is not Java, this is a different language.
Write in the language you're writing in.
This is a different language; it has different
rules, different conventions, different good
parts, and you need to respect that.
JavaScript has global variables.
This is the biggest problem in JavaScript.
I'm hoping we'll fix it in the next edition.
Dave Herman will be here tomorrow morning
to tell us about some of the stuff we're going
to do here.
But for now we're stuck with global variables,
and that's a problem because global variables
are evil.
They cause all sorts of reliability problems,
security problems, really bad things, and
the language is dependent on them.
My advice is to avoid global variables as
much as possible.
You should try to reduce your use of global
variables in a program or a subsystem down
to one or maybe zero.
It's possible to do in JavaScript, which is
really nice.
The language provides for its own workarounds.
In the few cases where you have to use global
variables, I recommend making your global
variable names all uppercase.
I want my global variables to be as rare as
hen teeth, and I want them to stick out like
a sore thumb.
All uppercase seems to be the most obnoxious
way you can write a variable name, so that's
the way I want to write it so it's really
clear that this is stupid.
The biggest resistance I see people having
to that is that they come from other languages
like C where all uppercase means something
completely different.
C has a different class of problems.
C has a preprocessor, a macro processor on
the frontend, and it can create....
In the language you can create things that
look like variables that are not variables,
they're macros, and that is a source of confusion.
People at Bell Labs really early on discovered
that confusion was intolerable, so they established
a convention: let's make all the macros all
uppercase, and that way we can tell which
is which.
That convention of having consonants be in
uppercase traveled over to Java for no good
reason, because they had finals, so there
was no reason to do that.
But they did it anyway.
That convention is now coming to JavaScript,
where it makes absolutely no sense, because
we don't even have final.
It's nothing.
My advice is let's use that convention for
something that has value in this language,
never mind what it might mean in other languages.
JavaScript has a new prefix.
I don't use the new prefix anymore; I found
it's just so problematic I don't use it anymore.
I use object.create now exclusively.
But some people still use new, so that has
to be respected.
But there's this big problem in the language
that if you write a constructor function and
someone forgets to put the new prefix in front
of it, instead of creating and initializing
the new object it clobbers global variables,
which is horrible.
It's the worst -- maybe second worst -- thing
it could do.
Maybe it could kill somebody; that might be
worse.
So that's a really bad thing.
Fortunately that gets fixed in ES5 strict.
Unfortunately ES5 strict is not in IE6.
It's not in IE7.
It's not in IE8.
And it's not in IE9.
But someday we'll get some value out of ES5
strict, and that'll be good.
In the meantime we have the InitialCaps convention.
If a function starts with an InitialCap, we
know it has to be used with new, and that
should be the only use ever of the InitialCaps.
Having that convention, it becomes possible
to read a program and figure out if it's using
new correctly, if the constructors are being
used correctly.
Without that it's hopeless; there's no way
you can read a program and know if it's right.
So this is an important convention.
In some languages they don't have this convention.
Microsoft still hasn't figured this out.
But it's important.
This should be respected.
Here's another fun thing you can do with var
statements.
The top statement appears to mean this, but
it actually means this.
Again, you have to look at it and ask what
the intention was here, and again, all you
really sure know for sure is the programmer
was incompetent.
Again, figure out which of these you meant
and write one of those.
Don't ever write the one on top.
Write in a way that clearly communicates your
intent; that's what we should be doing as
programmers.
Someday we may have the let statement in JavaScript,
and that'll be nice.
Let is like var except it respects function
scope, so there's no more hoisting, and that'll
be great.
When that happens, my advice will change from
declare all your vars at the top to saying
never use the var statement ever again, we're
using let from now on.
But we're not there yet, and we're not going
to be there until we get rid of IE6, and IE7,
and IE8, and IE9, and IE10.
++.
This came out of C. It was intended for doing
point arithmetic, so you could increment pointer
and get to the next thing that was being pointed
at.
We've since determined that point arithmetic
is a really bad idea.
The last popular language with point arithmetic
was C++, a language so bad it was named after
this operator.
But we still have it, so it's in all of our
languages now even though we don't have pointers
anymore.
It adds one to something.
It is generally used to create side effects,
and side effects are a source of confusion
anyway.
But I've found that when I'm writing stuff
with ++, I cannot stop myself from trying
to pack as much stuff into a statement as
I can.
I'm not the only one.
A generation of programmers has this affliction.
Most of the buffer overrun craze in the eighties
and nineties, where it was so easy to take
over operating systems, was because of this
operator; it just is so easy for the enemy
to get something into memory and get it executed
because this encourages you to write stuff
which is just way too damn clever, way too
difficult to understand.
It's bad.
I've found in my own practice, I do not trust
myself to use this operator ever, because
if I use it anywhere, even in a for statement,
I start getting the twitch and I'm trying
to push too much stuff in, I'm using commas,
I'm doing all sorts of stupid stuff trying
to get it all on one line.
I'm trying to optimize a thing which has absolutely
no value, has negative value.
There's no cost to us today in getting stuff
all into one line and it presents a tremendous
cost in terms of reliability, readability,
all of the good abilities.
It's a bad thing.
In my own practice, I say no.
I do not trust myself to use this ever.
I use + = 1 instead, everywhere, because I'm
no good with the other one.
I get people complaining "wait a minute, I
should be able to write x++ because it's one
character shorter, and it means the same thing."
Saving one character here has no value at
all.
It is not a good tradeoff.
In fact, it doesn't mean the same thing.
++x means the same thing.
This actually means something slightly different,
and something slightly different means you've
got a subtle off by one error that is really
hard to detect because it's only off by one
for a moment, so debugging that is really
hard.
When I see someone using that interchangeably
with that, I have to look at every ++ in his
stupid program and ask OK, did he get it backwards
or not?
Does he understand the difference between
pre-increment and post-increment?
Because he doesn't there.
I don't have time for that, it's just way
too much work.
I'm just trying to make the program work,
I don't want to have to figure out what he's
doing.
Recently I was reviewing some code and I saw
this: ++x; ++x.
Now had he originally written x += 1, he could
have easily changed that to x += 2 and it
would have been great, but now it's too much
work so he doubled the line.
Or maybe it was a copy and paste error?
I don't know.
I don't know.
It's stupid.
I would call a bug on that.
I don't know that it actually is the wrong
thing, but it sure looks stupid.
It would cause me to wonder if there are other
really bad things in this program.
So for no cost, by adopting a more rigorous
style, many classes of errors can be automatically
avoided.
That is a good tradeoff.
No cost, big benefit.
Here's another one.
The biggest design error that Thompson made
when he designed B -- and Ritchie copied the
error in C, and everybody's copied it in everything
since then except for maybe Python -- was
that he made the curly braces optional on
these structured statements.
He should have made the parentheses optional,
but he decided to make the curly braces optional
instead, and that was a huge mistake.
As a result of that you have statements like
this, where it looks like we're going to conditionally
call B and C, but that's not what happens.
It looks like it wants to do this, but it
actually does that.
This is another one of these confusion things.
I talk to people all the time saying my advice
is put the braces in, put them in everywhere.
It's only two characters and it makes your
programs so much more resilient and it's so
much more likely that someone who's going
to be maintaining your program doesn't accidentally
break it.
It makes your program stronger, less error
prone, and that's a good thing.
"But it's two characters!
So hard!"
It's not that hard.
Again, they're thinking we spend all of our
time typing.
If we can somehow save those two keystrokes,
we're going to be so much more productive.
And you're not.
You're going to be so much less productive
because you're going to be chasing down problems
due to false structures in your code.
As our processes become more agile, our coding
must be more resilient.
We need to anticipate that this code is going
to be changed many, many times, and will not
break as a result of that change.
We can't do anything that's too tricky or
too intricate, because it will not work.
Programming is the most complicated thing
that humans do.
Computer programs must be perfect and humans
are not perfect, so that is the struggle;
that is the core problem in our craft.
That is what we do.
Designing a programming style demands discipline.
We're not selecting features because they
are light, or pretty, or familiar.
We're designing features because we want to
improve our error rate.
Now, because we spend way too much time staring
into the abyss, if you want to be more productive,
spend less time staring into the abyss.
That's what I'm talking about.
The JSLint style was driven by the need to
automatically detect errors.
I decided that forms that can hide defects
are themselves considered to be defects.
I had no idea I was going to reach that conclusion
when I started working on JSLint.
When I started working with JavaScript, I
made exactly the same mistake that everybody
else makes, so I don't claim to have come
into this with perfect knowledge, and I'm
not trying to impose my personal standard
on anybody.
This all came about empirically as a result
of trying to automatically detect errors in
a deeply flawed language.
JSLint taught me JavaScript.
I know what I know about JavaScript because
JSLint taught me.
JSLint is much smarter about JavaScript than
I am.
It's probably smarter than you are, too.
My approach to JavaScript has been subsetting.
Any feature which is problematic and that
I can live without, I will happily live without
it.
It's been said only a madman would use all
of C++.
You could also say only a madman would use
C++, but I'm not going to argue that tonight.
But this approach to subsetting works in every
language.
It's really easy to add features to a language.
Some designers will think of a clever feature
and put it in, and sometimes it works and
sometimes it doesn't.
If it doesn't, they cannot take it out.
If a language is popular, if there is significant
use, they cannot remove a bad part without
breaking things.
Even if that part is dangerous and causes
people to write bad programs, it's stuck there.
You have a power that language designers and
standards bodies do not have -- you can take
features out of any language at any time by
simply refusing to use those features.
My advice is not that you be ignorant about
the features that you don't need -- I think
it's important that you know the whole language
-- but that you know enough to know to avoid
the features which are working against you
and not for you.
There will be bugs.
I'm not promising that by using JSLint or
using these techniques that you're going to
be bug free.
What we're trying to do is to move the odds
slightly to your favor.
Any bugs we can help you to avoid will make
you more productive and happier.
My conclusion: good style is good for your
gut, even if your gut doesn't think so.
Thank you, and good night.
[applause]
I think we have time for some questions.
Do you want to run the mic, or should I repeat?
OK.
>> FELIPE GASPER: Has anyone written a JS
tidy tool?
For example, if I write a var statement in
the middle of my function, I would love some
tool that strips out that var and sticks one
at the beginning of the function for me so
I don't have to worry about adding two lines
just because I added a new variable to the
function.
>> DOUGLAS CROCKFORD: Has anyone written a
JS tidy tool?
>> FELIPE GASPER: Like, Perl has a beautiful
one.
>> DOUGLAS CROCKFORD: Someone may have, I
don't know.
For a long time I've been thinking about writing
something called JSMax, which would be the
reverse of JSMin.
It would take something and pump it all back
up, and it would do things like that.
But I haven't.
Maybe somebody else will.
>> AUDIENCE MEMBER: Do you have any comments
on CoffeeScript?
>> DOUGLAS CROCKFORD: Do I have any comments
on CoffeeScript?
I really like CoffeeScript.
I think CoffeeScript is a brilliant experiment.
JavaScript's good parts have nothing to do
with its syntax.
Most of the bad parts in JavaScript are its
syntax; it's quite awful.
CoffeeScript takes the good parts and puts
a minimal syntax on top of it, which is lovely.
I like CoffeeScript a lot.
I don't recommend using it in production because
it comes with its own world of problems and
I don't think that's a good tradeoff.
I would like to see JavaScript move in the
direction of CoffeeScript in the long run.
There are a lot of pressures on the language,
and I'm not sure it's ever going to get there,
but that would be my preference if we could.
Anyone else?
>> AUDIENCE MEMBER: What are your thoughts
on Google Dart?
>> DOUGLAS CROCKFORD: I'm sorry?
>> AUDIENCE MEMBER: Google Dart.
>> DOUGLAS CROCKFORD: Google what?
Oh, Dart?
I've thought for a long time if I could take
a clean sheet of paper and write a new language
which corrects every defect in JavaScript
but retains all of the goodness in it -- because
there is a lot of goodness in it -- I would
not have come up with anything like Dart.
That's not to say there aren't some good ideas
in Dart, but it doesn't capture the goodness
of JavaScript.
It feels like it's trying to go back and be
more Java-like.
And its syntax stinks.
I don't get it.
There's something wrong over at Google, I
don't know what it is.
Apparently there are a whole lot of guys over
there who think it's a good idea; I don't
know what's going on.
>> AUDIENCE MEMBER: Are there any other languages
you would borrow any other goodness from to
add to JavaScript?
>> DOUGLAS CROCKFORD: I'm not an advocate
of trying to make JavaScript bigger.
I'm actually going the other way, I'd like
to make it smaller.
My goal for the next edition of the standard,
which will not be met, but my personal goal
is to make JSLint unnecessary.
We're not going to accomplish that.
Instead we're going to add a lot more stuff
which will probably introduce more bad parts
unintentionally; that's just how this stuff
happens if you try to add too much stuff too
quickly.
JavaScript sort of miraculously combined functions
as first class objects with lexical closures
and dynamic objects with prototypal inheritance,
two things that were never put together, two
experimental ideas, and put it into the mainstream
wrapped in a familiar syntax that worked.
It's ingenious, and I love that about JavaScript.
I think that's enough, there's enough there.
Anything else it needs can be added as libraries.
>> FELIPE GASPER: You did mention it tonight,
but JSLint also has a thing against -- I forgot
how you put it -- if you use a for in but
you don't have a hasOwnProperty check in it.
>> DOUGLAS CROCKFORD: Yeah, JSLint complains
about unfiltered for in statements.
>> FELIPE GASPER: Doesn't that filtering defeat
a lot of the benefits of prototypal inheritance
though?
Like, one of my beefs with YUI is that they
do this.
If you have use prototypal inheritance to
define your configuration object, YUI will
reject anything that that configuration object
has inherited from the parent object, which
was really frustrating until I realized that's
what was going on, because it seems so counter-intuitive.
It's this great thing in the language but
I can't use it.
Even Object.keys has this, what seems to me,
a flaw.
>> DOUGLAS CROCKFORD: Well, no, it's not a
flaw because it's so hazardous.
So again, the argument is not that it isn't
useful, it's that it's dangerous and error
prone.
The reason that I'm recommending you not use
it isn't because you can't figure out a clever
use for it -- I admire you for having found
a clever use -- I still recommend you not
do it.
>> AUDIENCE MEMBER: Why in the catch statement
do you have to use a different variable name?
>> DOUGLAS CROCKFORD: Why in the catch statement
do you have to use a different name in every
catch?
It's because in some browsers -- and I don't
need to iterate through that list again -- 
all of those become the same variable.
The correct way to do it should be to make
every catch clause, every catch block, be
a separate scope.
But in some browsers they don't, so you might
think that each one of these is a unique variable,
and they should be, but they're not.
If they all have the same name they are all
the same variable, and that is a confusion,
and we don't want to be confused.
OK, so that's that.
Thank you very much everybody.
Be careful going home.
Good night.
[applause]
