
How One Missing `var` Ruined our Launch - Trindaz
http://blog.meloncard.com/post/12175941935/how-one-missing-var-ruined-our-launch
======
mst
Am I right in thinking that the javascript

    
    
      /* "use strict" */
    

construct would have caught this mistake (just like it would have done for me
in perl code)? Seems to me that some such feature is absolutely and utterly
necessary in any environment where you're doing a lot of closure creation ..

~~~
Raticide
Yeah, that's all he needed. Making it a comment isn't necessary either.

Maybe Node should be strict by default? I can understand it not being the case
for browsers that need to support legacy code, but for Node it doesn't really
need to care about that.

~~~
morsch
Huh. On the scale from pragmatic idiosyncrasy to simply bizarre, making a
string literal expression change the runtime behaviour in that manner is
fairly wide towards the bizarre end of the scale.

I think, if anything, requiring it to be in a comment would have been less
odd; at least comments imply a sense of "meta"-ness.

~~~
masklinn
> On the scale from pragmatic idiosyncrasy to simply bizarre, making a string
> literal expression change the runtime behaviour in that manner is fairly
> wide towards the bizarre end of the scale.

Yes, on the other hand it's quite necessary to not have non-compliant browsers
blow up. `"use strict";` is just a noop in e.g. IE6. `use strict;` would be an
error in it.

> I think, if anything, requiring it to be in a comment would have been less
> odd; at least comments imply a sense of "meta"-ness.

Javascript compressors definitely strip comments. They probably don't strip
strings.

------
untog
Reminds me of one of the more confusing bugs I've ever encountered in my life.
I was throwing together a quick UI with Adobe Flex, and for some reason every
time you clicked a particular button, the entire UI would shift 20 or so
pixels to the right. I spent hours scratching my head until I noticed this for
loop:

    
    
        for (x=0;x<variable.length;x++) {
        // blah
        }
    

I wasn't declaring the x variable, so it was using the x part of the x/y
positioning of the UI container. Woops.

edit: initialise/declare brain freeze

~~~
cperciva
Now that I understand what you're saying: This is one of the reasons I hate
the "feature" in C++ and C99 that you can declare variables anywhere. If you
stick to declaring all your variables in one place, it's much easier to notice
when you've already used a variable name.

~~~
JoshTriplett
Have you tried the GCC -Wshadow warning flag? It will generate a warning
whenever you define a variable with the same name as one declared in an outer
scope.

Between that, and using -Werror to ensure that warnings never get ignored, I
find C99-style declare-anywhere quite useful. It helps me keep the scope of
variables limited to the places that need them.

That said, I rarely use C99's ability to declare a variable in the middle of a
block. I primarily use the C99 feature of declaring variables as part of a
loop.

~~~
euccastro
(I'm no C expert, I'm posting my take on this mainly because I'm interested in
learning from counterarguments):

Greatgrandparent's error was _lack_ of such inner declaration. -Wshadow
wouldn't help with that.

Also, I imagine enforcing old-style declaration restrictions helps you to
avoid introducing those errors in first place, but it's just as hard to debug
them once they're in.

My choice would be to get in the habit of declaring a variable in the
narrowest scope that makes sense. I can't see much of a problem with this
(esp. in the context of C!) barring old habit. I don't think Scheme
programmers, for example, have this stuff any easier and I don't think scoping
is perceived as a problem there.

~~~
JoshTriplett
I agree with you entirely that -Wshadow (or an equivalent for JavaScript)
would not solve the problem reported in the original article. However, it does
solve the problem cperciva mentioned in the comment I replied to: "If you
stick to declaring all your variables in one place, it's much easier to notice
when you've already used a variable name.". -Wshadow detects when you've
already used a variable name and reports that as a warning (or an error if you
use -Werror, which you should).

I also agree about declaring a variable in the narrowest scope that makes
sense. I often see code that attempts to reuse the same variable for several
different purposes, rather than declaring separate variables in narrower
scopes.

------
almost
> I would posit here that nothing I could do in best practice (manual front-
> end testing, unit testing, error handling, etc.) would have caught the
> offending line.

jshint would have caught it. You need to run jshint on your code or you will
get silly errors like this. Simple.

~~~
apike
Even better is setting your editor to run JSHint when you save a .js file, and
let you know if there are problems. Not only does it avoid stupid bugs, it
saves time round-tripping to the browser for trivial issues like syntax
errors.

~~~
almost
Sounds like a good idea. I know emacs flymake mode can be set up to underline
problems detected by jshint. Personally I like to have the tests and jshint
run by a hotkey so I can happily move the code through invalid states (towards
a valid goal) without being constantly complained at :)

~~~
daleharvey
I wrote a jshint mode for emacs

<https://github.com/daleharvey/jshint-mode>

~~~
wahnfrieden
I use jshint in vim as well: <https://github.com/wookiehangover/jshint.vim>

~~~
eric-hu
does this work for coffeescript as well?

~~~
philjackson
Unless you use backticks, coffee will always pass jslint tests.

------
tikhonj
Since everyone is chiming in with ways to prevent this sort of thing, here is
another: js2 mode for Emacs[1]. This is a mode originally written by Steve
Yegge and then modified by some other people (be sure to get that version)
that actually parses the code and, among other things, highlights global
variables in a different color than local ones. I find this, along with the
other things js2 does, helps prevent a whole host of annoying JavaScript
issues, as I type.

[1]: <https://github.com/mooz/js2-mode>

~~~
almost
Have you had any luck getting it to handle modern JavaScript style? Whenever
I've tried js2-mode it really hasn't liked jQuery style nested anonymous
functions.

~~~
tikhonj
Try using the version I linked rather than the original. It has a bunch of
improvements including how it handles indenting functions.

I've done some moderately complicated jQuery development with it, as well as
some node.js stuff for fun, and have had no issues in either case.

------
DanielRibeiro
This is why I like both Scala and Coffeescript approaches. On Coffeescript
vars are created for you, and on Scala, you can't not use it (you either use
var or val, making it easy to change from re-assignable variables to final
ones).

Note that nowadays going to Coffeescript from Javascript is quite easy:
<http://js2coffee.org/>

~~~
finnw
I don't know Coffeescript - does it implicitly create a local var when there
is already a global with the same name?

~~~
YmMot
CoffeeScript doesn't allow you to shadow variables in enclosing scopes. The
compiler will declare the variable in the "outer-most" scope in which is is
used and then any uses in enclosed scopes refer to that one.

In this case as long as OP was not using the variable in an enclosing scope,
it would have been made local to the function.

~~~
geraldalewis
This is true for the most part, but there's a subtle edge case. Within a
nested function, variables used in loops will redeclare within the inner
function:

    
    
      ->
        outerVar = "outer"
        ->
          # this will output "undefined" 
          # as CoffeeScript has redeclared it for the loop:
          console.log outerVar 
          0 for outerVar in [0]

~~~
jashkenas
Huh -- that looks like a (new) bug to me. We should reuse the external
declaration.

------
dikbrouwer
One thing you can do to help avoid this: use JSLint (or something equivalent)
to check for missing var keywords. And, the obvious (as you already mentioned)
coffeescript. Would love to hear of other suggestions on how to effectively
debug this, especially in node.

~~~
NegativeK
JSLint was my first response, but I have to agree with someone higher up --
use strict is probably a better solution, since it'll happen whether you like
it (or forget it) or not.

~~~
dikbrouwer
using strict sounds like a great idea - I wonder what other implications that
has, need to look into it.

------
mzarate06
_I'm not an expert in JavaScript..._

Given that you said that, and that the problem you hit is a common pitfall for
Javascript developers (especially if you're not very seasoned with the
language), I'd strongly recommend picking up a copy of Douglas Crockford's
_Javascript: The Good Parts_. Not only does he inform readers of this
particular gotcha, but he also elaborates on Javascript best practices and
tools that others are bringing up in their comments.

~~~
mturmon
Excellent advice. You simply _have_ to understand JS scope rules, and the
Crockford post lays it out compactly. It's an idiosyncratic language.

~~~
sirclueless
I think the author of the blog post understands JS scope rules. His point
isn't that you shouldn't need to have a "var" in front of your declarations or
that javascript is stupid and he doesn't understand it, it's that there should
be a better way to find bugs like the one that bit him.

Of course, there is a way to find his particular bug (JSLint, "use strict")
that he didn't know about. Still, the point about debugging being a nightmare
is absolutely true.

~~~
mturmon
After I posted, I realized this. You're correct.

------
rayiner
Why has it become popular for dynamic languages to conflate establishing a
binding with assigning it a new value? Ruby, Python, and Javascript are all
guilty of this.

Scheme got it right sometime in the 1970's.

    
    
        (let ((x initial-value)) ; binding
          (set! x new-value))    ; assignment
    

Or in infix syntax (Dylan):

    
    
        let x = initial-value ;
        x := new-value ;

~~~
MostAwesomeDude
Python doesn't let you write outside of local scope without a special keyword.
Exactly the inverse of JS. If you want to write to global state, and you're
_aware_ that you're writing to global state, then you use the "global"
keyword. That's all.

~~~
rayiner
It still conjures up variables out of thin air.

    
    
        sum = 0
        for v in someList:
            smu += v
        print sum # prints 0, doh!

~~~
tlb
Exactly. The claim is that implicit local variables are less dangerous than
implicit global variables. I've been bitten badly by both. Perl was the worst,
where implicit variables were scoped differently according to Larry's
philosophy when he implemented it. All for the sake of brevity.

Can someone please implement strict mode for Node?

~~~
masklinn
> Can someone please implement strict mode for Node?

It's already implemented, you just have to enable it.

------
JonnieCache
_Ouch._

I always thought JS's global-variables-by-default schtick was it's worst
crime, but I've never seen such terrible consequences for it up close before.

Note to self: before products get to forbes, do some load testing. Even if I
am using node, with its magic event loop of invulnerability.

~~~
vonkow
As a rule, in js I declare every var at the top of the function (or globe) in
one giant var statement just because of this. Still, it's easy to get lost in
the moment and mess up just once. I used to think this was just the way things
were but pair-programming/code-review and/or a language with better scoping
rules would've prevented this from happening.

~~~
masklinn
> Still, it's easy to get lost in the moment and mess up just once.

Get a better editor, and JSHint, and "use strict";

Implicitly declared globals can be statically checked, there is no reason not
to.

------
nikcub
You will probably get hundreds of comments with unsolocited advice, but let me
just say to checkout and setup JSLint:

<https://github.com/douglascrockford/JSLint>

Setup and how you use it is more important than just using it. I run it in
three places:

1) In my IDE (bound in vim on save, same in TextMate)

2) As a Git checking hook

3) In deployment / build scripts

Turn all the warnings way up and it always catches redeclaration bugs.

Set it up once and don't allow any code to get checked in or deployed with
even a single warning present.

I also pass all Javascript through the Google Closure Compiler, but with the
lowest compilation setting, because it is very good at picking up small errors
as well.

(if anybody is interested in how to set this all up I can publish my configs
and scripts)

~~~
philbo
I'd love to see them. I'm starting a new job soon and it is going to be pretty
much greenfield javascript development all the way. I'm really keen to make
sure that I'm ticking every box on the best practices front, right from day
one.

------
brendoncrawford
This was a problem of laziness more than anything else. To the beginner
developers out there: Learn to write good code and to pay attention to the
details. Don't become just another co-founder trying to do the bare minimum
just to make a buck. Take pride in your work and use best practices. Be
careful to avoid the careless mistakes made by the author...

    
    
      1. Did a major last minute code change
      2. Did not run jslint
      3. Did not use strict mode
      4. Did not run load tests
      5. Did not use an editor that catches scoping problems

~~~
xentronium
Sure, blame the victim, not the idea that default variable scope is global.

~~~
viraptor
There are libraries in other languages providing node-like capabilities. He
could use those and not have the global scope problem. Not saying that the
idea makes any sense either...

------
FuzzyDunlop
JS is so easy to cock up in, I commonly find myself logging to the console
just to make myself sure of the scope and other things.

This technique totally went to shit when I came across one of our scripts that
gratuitously used `apply()` all over the place.

The other common error is array iteration, and I've not quite understood why
iterating through one array in the same scope as where it was created works
fine, but passing it to another function and performing the exact same routine
also goes through the prototype methods after the elements.

Of course, particularly with the var mistake, you'd never really understand
the magnitude of it until you attempted to use JS on the server side. This
post has, quite thankfully, likely exposed a bug in my own code I couldn't
quite understand a while ago. :)

~~~
bzbarsky

        > also goes through the prototype methods after the
        > elements.
    

That shouldn't be happening. If you see it happening, your JS implementation
is just buggy.

In fact, this testcase:

    
    
        <script>
          window.onload = function() {
            var arr = window[0].arr;
            for (var i in arr) { alert(i); }
          }
        </script>
        <iframe src="data:text/html,<script>arr=[1];</script>">
        </iframe>
    

alerts only "0" in WebKit+JSC, Gecko, Presto. Chrome has some sort of bizarre
security policy here that keeps the script from working, so no idea what
WebKit+V8 does.

------
jessedhillon
Do I understand this right -- global variables are shared across all requests
in node.js?

If so, that is an insane design.

~~~
fennecfoxen
Global variables are basically instance variables on the process itself.
They're going to be shared across all requests in all environments that handle
more than a single request per process. If they had different semantics, they
wouldn't really be what normal people call "global variables", would they?

So you just don't use them and everything's good. Which brings you to the real
problem: JavaScript makes it distressingly easy to use a global variable where
you meant to use a local one.

~~~
bzbarsky

        > Global variables are basically instance variables on the
        > process itself.
    

Not in JS. See my response to ww520 below.

~~~
fennecfoxen
Ah, I see what you're talking about.

Seems like jesseedhillon was expecting that Node works like a browser: there's
a lot of backend code in another language that handles the HTTP request, and
then forks it over to a little JavaScript, and each request gets a new global
scope.

It's not like that. There's a teeny bit of C-based backend code; it's the
JavaScript part that controls alll the interesting stuff like opening sockets
and parsing HTTP headers and the like to determine a request. In a single
process, with a single global object, with lots of asynchronous I/O.

Node is JavaScript as a first-class programming language, not subservient to
the DOM.

~~~
bzbarsky
This has nothing to do with the DOM. There are existing server-side JS
deployments that have no DOM, but do create separate globals per request.

There is nothing other than a conscious design decision that forces the Node
code that you write to run against the same global as the code that handles
the I/O guts in Node...

In particular, you could have the code that listens on the socket and chunks
up the byte stream into HTTP requests running against one global while all
further processing of those requests runs against a different global or set of
globals. It's just that Node chose not to do that. But that's not an inherent
limitation of either JS the language or the V8 implementation.

------
kwamenum86
"I would posit here that nothing I could do in best practice (manual front-end
testing, unit testing, error handling, etc.) would have caught the offending
line."

Running your code through JSLint (or something similar) would have been
helpful here. Performing this check before committing code is considered a
best practice and it's really easy to setup a pre-commit hook in most version
control systems. JSLint has a Node.js mode. It would have said something like
"variable used before being defined". <http://www.jslint.com/>

------
kaffeinecoma
You can do some poor man's load testing very simply with siege
(<http://www.joedog.org/index/siege-home>). Put a bunch of URLs in a text
file, and run it with "siege -f urls.txt".

Of course it doesn't _prove_ that your code is bug-free, but if you have
concurrency issues, this will help shake them out. I've used this many times
to reveal problems with DB connection pooling, concurrency issues, and
excessive session size.

------
JayInt
Melon Card.... I just signed up with a random email and it would allow me to
remove the details for that email 'joe.doe@yourwebsite.com'... using your
software as long as I did the captcha I could remove records for anyone's
email as long as you can find them (the recommendation makes that easy)... you
NEED to include verifying the email address before you can perform actions!!

------
ConstantineXVI
Similar, but not quite as world-ending issue we had launching our Android app.
Shortly (~36hrs) after launching, we had noticed that we were compiling with
Cupcake (and we only intended to support Eclair+). We were pushing to have it
out for SXSW; in a rush we just re-compiled, made sure it still launched, and
pushed to the Market.

After everyone got some sleep, we realized that Cupcake didn't have multi-res
support; and later phones quietly re-scaled everything to compensate. Compile
to Eclair and well, things were a bit out of proportion.

------
Hominem
I feel for you man, but did you not test with more than one user at the same
time? I live in constant fear of this kind of thing, I always round up as many
people as possible to test at once.

~~~
vonkow
Screw rounding up >1 users for testing (though it does give needed human
insight), if you aren't spooling up a few multicore VMs with JMeter or better,
you aren't really performance testing.

------
jwatte
I think the main thing missing with Node is best practices. We use jslint with
node. And we run tests in parallel, to flush out any dependencies. We had to
wrap callbacks in a sequencing library to get good stack traces, though.
Node.js also integrates with the Chrome V8 source level debugger, for real
debugging!

Also, C++ can also take down your site with a single character typo that the
compiler may not catch, so even static typing can't save against everything!
(I actually like C++, too, so no hate there)

------
peregrine
Is it just me or is this site completely unusable right now. I keep trying to
say 'This isn't me!' or 'This is me!' with no results... maybe he has another
missing 'var' somewhere?

------
vonkow
Damn, I feel for ya; scope is hell sometimes, and js is all about giving you
the power to shoot yourself in the foot. Interesting how bugs like this, while
terrible and terribly easy to miss, tend to do a lot less damage on the front-
end of things (or doesn't show up in a single thread/user environment). It was
the potential of things like this happening that drove me towards languages
like erlang and java on the server (even if js is still my favorite language).

------
chrisrhoden

        > (function () { internalvariablewithnovardelcaration = "string"; })();
        > internalvariablewithnovardeclaration
        ReferenceError: internalvariablewithnovardeclaration is not defined
            at [object Context]:1:1
            at Interface.<anonymous> (repl.js:179:22)
            at Interface.emit (events.js:64:17)
            at Interface._onLine (readline.js:153:10)
            at Interface._line (readline.js:408:8)
            at Interface._ttyWrite (readline.js:585:14)
            at ReadStream.<anonymous> (readline.js:73:12)
            at ReadStream.emit (events.js:81:20)
            at ReadStream._emitKey (tty_posix.js:307:10)
            at ReadStream.onData (tty_posix.js:70:12)
        > externalwithnovar = 1;
        1
        > (function () { externalwithnovar = "string"; })();
        > externalwithnovar
        'string'
    

You're all wrong. There is no 'global by default for javascript. This guy
clobbered a variable called initial outside of the scope of the callback.

------
Tichy
Well whole rocket launches failed for silly reasons like temperature
conversions, so you shouldn't feel too bad about it.

------
alexchamberlain
This is a major downside of interpreted languages, coupled with JS's
diabolical scoping rules. Interpreted languages by their very nature, only
reveal syntactic errors to you once you run them. I would like to see server
side code written in compiled, statically typed languages, such as C/C++ to
prevent such errors.

------
itay
I hit a similar thing in some code I was writing, and ended up debugging it
for about 5 hours. Couldn't figure out why when some tests ran, one of them
would just die.

Turns out I forgot to use 'var' in a library function, and the tests were
running concurrently, and so one clobbered the other. It was not fun.

Been using JSHint ever since.

------
gopi
A un-initialised varible made our script to mail 20 copies of the same email
to almost 10k users. One of our mass email script basically breaks the email
list in chunks of 500 and emails them. The array variable that hold this 500
email chunk was not initialised. In our test everything was fine as the test
list was never more than 500. When the time came to send emails to the
production list, the script basically kept sending multiple copies of the same
emails (since the array retained the old values across the loop iterations).

I realised this after about 10 minutes but already multiple copies of the same
emails (20/user) was send to more than 10k users!...The end result was annoyed
users unsubscribing in droves and possibly a hit in our email reputation. This
is all because a stupid array variable was not initialised :)

------
dendory
Screams lack of testing. Speaking of which, did you know your site design
breaks when viewed on an iPad?

------
mstepniowski
Use jslint, Luke.

------
jconley
Common problem. Live and learn.

But the problem is a bit more meta than Javascript scoping. Something would
have happened no matter your environment. It's always extremely risky to make
huge changes just before a launch day. Stuff always breaks. Sounds like you
did a good job of communicating with your customers. Ironically, they will
probably be better customers than they would have been if you didn't have any
problems. Overcoming adversity brings people together.

Add some concurrency to your test suite. If you have any system level or black
box tests, you can often just run the same test multiple times in parallel
with different threads. No new tests required. Note that this may (probably
will) also uncover other previously inconceivable concurrency issues.

------
dap
As many have pointed out, there are absolutely tools that would catch this
kind of problem in development. But the experience also speaks to the lack of
sophisticated observability tools for Node (and just about every other popular
dynamic language too).

------
jufo
This is a lesson we all have to learn. At least in Node it is easy to pick up
with a tool like JSLint. In Java, you typically have some classes which have
to be thread-safe (having no per-request state) and others which are
instantiated per request. Developers have to be aware of the distinction, and
to code accordingly. I fell into this trap when submitting a change to JBoss
back in 2000; Rickard Oberg picked it up within hours (the diffs of all
committed changes went out to everyone on the developer mailing list). I'm
grateful to him for that, and I've done the same kind of review for many
others since then.

------
mnutt
This is why I really dislike it when I see

    
    
        var a = "foo",
            b = "bar",
            c = "baz";
    

All it takes is one missed comma and all of a sudden you've turned a _lot_ of
your variables global.

~~~
fuzzythinker
that's why many people favor this variant:

    
    
      var
        a = "foo"
      , b = "bar"
      , c = "baz"
      ;

~~~
webXL
I see this hideous convention used a lot when assigning nodejs modules, so you
can easily comment out modules for debugging purposes (I think). Other than
that, why is "[NL], b = 1" safer or better than "b = 1,[NL]"?

------
sampsonjs
And that is what happens when you throw static type checking and the other
safety features of compiled languages out the window, 'cause all the cool kids
are doing it.

------
jcromartie
Maybe a language where variables are global by default and there are no
concurrency semantics at all isn't so great for serving up web apps to
concurrent users?

------
poundy
This reminds me of something I could not do. How do you load test a nodejs -
socket.io installation? Is there a tool like apache bench to load test
websockets?

------
gambler
I don't see this as a JavaScript specific problem. A similar issue can occur
in IIS, for example. The details would be more elaborate, but the core issue
would remain the same. A variable shared across requests screws something up
under load. Seen it happen.

This is one of the reasons I like shared-nothing architecture where the only
way to share or persist something is via explicit caching or database.

------
ozataman
Thanks for reminding me why I like Haskell so much.

------
codejoust
My var story was a little harder scoping issue where a variable held the
information for a pending call. It would asynchronously process the call, then
mark the call as completed. Well, if there were more than one call going
through, the callback was only getting one record, causing it to repeat the
call about five times before I caught it and fixed the scoping.

------
crichardson917
Very interesting. I've been thinking about delving into Node.js for a while,
and I will definitely keep things like this in mind.

~~~
samgro
Do yourself a favor and use CoffeeScript! You will never have to worry about
this or any number of other trivial JS mistakes, plus your code will be more
readable and more fun to write. Win/win.

------
SimHacker
Do JSLint or JSHint catch the common error of using "this" inside a closure
when you want it to be lexically bound instead of dynamically?

It's easy to forget to go "var me = this;" and use me instead of this inside
of closures. But how would JSLint or JSHint know you made a mistake and didn't
actually mean for "this" to be bound dynamically?

~~~
mark_story
No, because this is still valid inside the anonymous function. It can't tell
which this you intended to get.

It would be able to find out if you used an uninitialized me, _this, that
though and complain. Using self as the this alias is really dangerous as it
leaks to window.self so avoid it like the plague.

------
speleding
I know there seem to be a few HN readers religiously against using an IDE, but
in this case an IDE would have probably helped. Since it colors global and
local variables differently the error would be much more apparent at the time
when it was made (you typically have very few global variables so they stand
out color wise).

~~~
thomblake
No IDE needed - any decent editor will do syntax highlighting.

~~~
speleding
Global versus local variables is not determined by syntax in javascript, it's
determined by semantics (you need to parse javascript to find out). A few
editors can do that, but you could really call those an IDE already.

~~~
thomblake
_Parsing_ is _syntax_. _Interpretation_ is _semantics_. Just parsing JS just
gives you information about its syntax, and any decent editor (like vim or
emacs) has a programmable interface such that you can write a JS parser.

------
johnbender
Steve Yeggae's js2-mode highlights globals during editing, and it's saved me a
good many times.

<http://code.google.com/p/js2-mode/>

Mind you it won't catch globals declared in chained assignments

eg

    
    
        var x = y = 0; // y is defined globally

~~~
thomblake
The fork of js2-mode at <https://github.com/mooz/js2-mode> will catch that, as
will js3-mode.

------
igorgue
I don't always write JavaScript (CoffeeScript FTW) but when I do I use JSLint
(vim-jslint)...

~~~
baudehlo
It's not very good on node.js code. Hell, it's not very good, period.

~~~
igorgue
The plugin uses node as a linter...

let $JS_CMD='node'

------
howardr
Congrats on launching. Saying this ruined your launch is a bit dramatic. The
ability to put out fires when they happened is crucial to startups. Seems like
the problem only existed for a few hours. It could have been worse. Write a
test and move on

------
chetan51
Oh wow. I've faced this exact same problem with missing `var`s more than once
before. It's pretty ridiculous that JavaScript makes variables global by
default.

Sorry to hear about your tragedy, hope it doesn't cause too many issues in the
long run.

------
boscomutunga
Reminds me of a time i had a similar bug.The more i tried the more i found it
hard to discover the bug.One approach i usually use is to take a timeout and
relax.But in your position there was no time for relaxing.

------
firefoxman1
Node definitely needs better error handling, but what's nice about node is
that each module is scoped in its own namespace, so if he had put each of his
routes in its own module, that wouldn't have happened.

------
bryantchou
Ack, stuff likes this makes me very nervous about our production nodejs
backend ... the error tracking is really quite difficult. But it's more a
byproduct of javascript as opposed to node/express.

------
ruidlopes
(Shameless plug, but interesting enough, imho). This is why I created
scopeleaks: <https://github.com/ruidlopes/scopeleaks>

------
kevinkemp
The real failure that opened you up to this race condition is naming. Initial
is not specific enough and thus colided with another variable, that was also
not named specifically enough.

------
ighost
> I would posit here that nothing I could do in best practice would have
> caught the offending line.

bullshit.

jslint or clojure compiler would have found this error at "compile time."

coffeescript would have made it a non-issue.

------
phektus
"It’s beautiful simple..."

I might just be painfully slow, but the implementation he described didn't
sound anything remotely simple to me (though I believe it really is
beautiful).

------
yaix
Wow, thanks for sharing!

It's these small things to remember that can save a lot of debugging time down
the road. Will remember to "use strict" when I use nodeJS again.

------
nt_mark
Exactly why we moved to CoffeeScript, without it you need to rigorously
enforce coding conventions. This entails watching for missing vars, using
jslint, having a script that searches for accidentally declared globals, only
declaring vars at the top of a function, among other best practices. With CS
you get all of that just by using it. If you can write high-standard code
using a simpler, terser syntax, why avoid it?

------
atomical
I just hit your page and it gave me an error that said the server was over
capacity. Not the only reason?

~~~
ricardobeat
That's Tumblr apparently.

------
markokocic
jslint to the rescue. If all your source is JS, there's no excuse to at least
use lint.

------
scotty79
Php shares nothing except session between requests and local scope is default.

------
jroseattle
> I would posit here that nothing I could do in best practice (manual front-
> end testing, unit testing, error handling, etc.) would have caught the
> offending line.

Sorry, that's incorrect. If you cannot fully simulate your environment for
purposes of validation, you're not covering your bases.

~~~
wanorris
Are you saying that the definition of an adequate test setup is one that will
necessarily catch any possible race conditions?

That sounds like a necessary idea if you're building real-time embedded
systems for aircraft operation or something, but for a lot of applications,
developing a test harness to that standard would take considerably more time
and effort than building out the actual product.

~~~
jroseattle
The problem wasn't a race condition, it was an improperly scoped variable. If
a different variable name had been used, the failure would have been easy to
identify. Testing for the result of something improper wouldn't be appropriate
here, either.

But, if the environment is such that it is easy to manifest this condition, I
would argue that such a test setup should definitely be considered, given the
potential for failure.

------
jhuni
Always use JSLINT.

------
jorangreef
for (var key in this) console.log(key);

------
illumen
jslint

------
startupcto
"It’s a damn tragedy. I’m not an expert in JavaScript"

Hell yea, the valley's full of smart kids who don't know what the hell they're
doing with JavaScript and thinks they're one hell of a hacker when they
discovered that they can do shit with a few lines of JS and trumpeting on the
how great NodeJS or whatever the greatest and newest shiny framework out
there.

If you don't really understand scoping in JS, please don't use node and hit
yourself on your foot and then blog the cool shit out of it.

I'm just saying, no hard feelings. :)

~~~
sirclueless
I think "a damn tragedy" is a pretty apt description. Well-designed languages
shouldn't require reams of experience. Just a little intelligence and a
reference for any questions that arise should get you pretty far.

I'm sure this guy "really understand[s] scoping in JS", but he still got
bitten. The blog post isn't frivolous, its point is that javascript is a
minefield. Which is an important lesson. Use JSLint or "use strict" or pay the
price.

------
jwallaceparker
Crazy. Same thing happened to me. Good luck with the next project.

------
mansoor-s
"Now is the point I’d like you to say: you should have used CoffeeScript, and
hey TameJS while you’re at it. You’d be right."

Perfect example of a developer hating JS just because he/she didn't bother to
learn it first and got burned.

~~~
mhansen
It's still very easy to miss a 'var', even if you know the language.
Especially if you've just context-switched from ruby or python.

------
rajeshamara
Actually it is very easy to debug any javascript error. In IE there is a
setting where you can uncheck the Disable Script debugging (Internet Explorer)
and in the status bar you will see any javascript error. If you check the
checkbox IE will not report any errors. In general during your development you
should always uncheck the box.If you double click the javascript status this
will exactly report the line number where the javscript error is. I exactly
don't know if you see these kind of errors in Chrome and firefox. I know
people blame IE but there are quite few nice handy features which are very
helpful during development

~~~
bobralian
There's a lot to say here, but I'll limit my comment to LOL at the idea that
IE reports the _exact_ line number of a javascript error.

