
Dropbox dives into CoffeeScript - varenc
https://tech.dropbox.com/?p=361
======
crazygringo
Where I work, we moved the project I work on to CoffeeScript about a year ago,
and I've been using it ever since.

Putting syntactic sugar aside, while some things are very welcome (list
comprehensions, ===, ?), there are two main reasons why I would be wary of
using CoffeeScript again:

1\. Complete lack of documentation for syntax. Because there are basically no
more braces and parentheses, CoffeeScript just tries to guess what you're
doing, as far as I can tell, based on a bunch of internal heuristics.
Unfortunately, there's no way for me to learn how to write parseable code
without constantly pasting into the coffeescript.org site, and seeing if
CoffeeScript understands it or not. This is the first language I've ever used
where the syntax rules are essentially unknowable, and a lot of time gets
wasted trying to discover them through trial and error.

2\. Unexpected side effects. For example, functions return the last evaluated
value by default. If you're using $.each(), and your function's last line is
something that returns false (like a separate function you call), then your
$.each() loop will terminate unexpectedly early, since jQuery does that when
it receives a false. So CoffeeScript isn't just a wrapper around JavaScript,
but it really changes its behavior. Another example: CoffeeScript gets rid of
function hoisting. A significant JavaScript feature, completely gone.

I personally am slower to code in CoffeeScript, because I know JavaScript 100%
inside and out, but with CoffeeScript that isn't really possible, because so
much of its implementation is undocumented. I mean, many times you're forced
to end a line with a backslash in order to continue it, and even the existence
of that necessary feature isn't mentioned once in the docs.

But a lot of people seem to love the syntax, and that seems to outweigh the
negatives for them. I personally don't find JavaScript that ugly, but coding
in a language I can't ever fully understand gives me a huge headache.

~~~
jlongster
CoffeeScript can't really claim that "it's just javascript" either. I'd have
to figure out how to hook up the CoffeeScript compiler into every single one
of my workflows where I use javascript.

For example, I use swank (<https://github.com/swank-js/swank-js>) to send
javascript to the current page in my browser from Emacs. I couldn't live
without it. I'd have to figure out how to dynamically compile it, and I'm not
sure if there's any restrictions with piece-meal compilation.

It's definitely a separate community and I'd lose out on lots of good tools if
I had to use it. I'm glad nobody wants to use it where I work.

~~~
lowboy
"It's just javascript" !== "You don't have to change your workflow at all"

------
jlongster
This sounds so much like some geeks wanting to hack. That's it. There isn't
really a good reason to convert a codebase with tens of thousands of lines of
code from js to CoffeeScript.

Not that there's anything wrong with that. But seriously, every single problem
with javascript they mention is never a problem for javascript developers. You
simply learn what's broken, and deal with it. Dealing with it is usually one
line of code (or even less), making sure you just use ===, etc. It's really
not a problem.

These kinds of posts smell a little like FUD to me, which is what I have a
problem with.

~~~
ilaksh
The reason to use CoffeeScript over JavaScript is because it is better
software engineering.

Number of lines of code has been shown to be one of the few good indicators
for predicting defects. CoffeeScript significantly reduces the number of lines
of code in a project and therefore the number of defects.

CoffeeScript is cleaner and easier to read, which is better software
engineering. CoffeeScript solves many of the issues with JavaScript. The fewer
warts and plumbing people have to deal with related to the language, the more
they can focus on the actual problems they wanted to solve.

This is a little bit like the architectural decision to program user
applications in languages and platforms with garbage collection and built-in
frameworks rather than using a language like C or C++ with manual memory
management and minimal standard libraries. Sure you get less control over the
lower-level details such as allocation and deallocation of memory, but those
lower level details actually are distracting from the application domain and
were actually repetitive and could be automated. So the best way to solve
those problems is to move to a platform that abstracts them away or handles
them for you.

The reason that developers don't like CoffeeScript (other than the fact that
they haven't learned it yet, and don't want to take the time) is simple,
psychological rather than logical, and its the same reason that they don't
like platforms like the ones I was talking about above: it makes things
significantly easier, and that is problematic psychologically for programmers
for two reasons:

1) The whole point of being a programmer is that you are mastering complex
ASCII codes that other people can't decipher. Making things less complex takes
away part of your identity as a programmer (not for everyone obviously, but
for many).

2) Many programmers instinctively and falsely believe that any system which
makes their job significantly easier must automatically come with compensatory
trade-offs in things like performance or flexibility. This is intuitive, but
false.

CoffeeScript improvements: indenting two spaces and using -> plus no closing
parens and curly braces makes nested callbacks much easier to read and write,
fat arrow binds this making it easier to use classes, class and extends
provide a standard, simple way to create and extend classes, iterating over
arrays and objects is much easier and cleaner, control flow and function
definition is cleaner, better variable scoping, simplified closer wrapper in
loops, more straightforward boolean operators, existential operator for
cleanly and simply checking for variable existence.

Thought of one other explanation for not liking CoffeeScript: plain old status
quo bias. <http://en.wikipedia.org/wiki/Status_quo_bias>

~~~
dmpk2k
_better variable scoping_

CS's scoping is a bit... dangerous, because there's no indication of a
variable's scope. If you're not paying attention to your environment, you'll
inadvertently stomp on higher scopes or globals. You can lose assignments
through typos too.

JS made a mistake by allowing globals by omitting "var", but that at least can
be worked around by using a linter or "use strict". A number of languages have
made this mistake, and many later followed a similar path to fix it.

CS has a lot of nice properties, but we should not laud conflating variable
definition and assignment. It has always been a mistake, and I hope CS's
author eventually comes around and fixes it.

~~~
eurleif
>CS's scoping is a bit... dangerous, because there's no indication of a
variable's scope. If you're not paying attention to your environment, you'll
inadvertently stomp on higher scopes or globals. You can lose assignments
through typos too.

Not just that, but adding a variable to an outer scope can break functions
that were previously just fine. Isn't the whole point of scoping that changing
code in one place won't affect unrelated code in another place?

------
sync
Big, big fan of CoffeeScript and glad to see Dropbox hopping aboard.

That being said, some of their examples are lackluster.

    
    
      @originalStyle = {}
      for k in ['top', 'left', 'width', 'height']
        @originalStyle[k] = @element.style[k]
    

Should really be something like:

    
    
      @originalStyle = ['top', 'left', 'width', 'height'].reduce (hash, position) -> 
        hash[position] = @element.style[position]
        hash
      , {}
    

... though that shows off some CoffeeScript warts.

Also,

    
    
      Sharing =
        init: (sf_info) ->
          for list in [sf_info.current, sf_info.past]
            for info in list
              @_decode_sort_key info
    

Why aren't they using CoffeeScript classes?

    
    
      class Sharing
        constructor: (sfInfo) ->
          ...

~~~
rgarcia
Really they should just use underscore:

    
    
        @originalStyle = _(@element.style).pick ['top', 'left', 'width', 'height']

------
BadassFractal
I'm a little surprised by the number of negative comments in this thread
accusing the three Dropbox engineers of wasting company time.

~~~
adgar
Why? It seems like a complete waste of time to this typical software engineer
with 100x more objectives than time.

Why not convert all your Java code to Scala? Because you have real work to do
and reskinning your existing code provides no benefits, that's why. If it
works, don't rewrite it, go make more stuff work.

Maybe the dropbox folks don't have anything else to do, though. Not my place
to judge.

~~~
mamcx
Improve the codebase (make it small, cleaner, more easy to read, and fix
issues of pastime) is NOT a wasted time. Not necessarily the BEST USE of time
at a given moment, but dedicate some time to refresh the code with better
tools, better syntax, better libraries, etc is a excellent way to move
forward.

For a related sample, with obj-c I move to ARC ASAP, and plan to introduce the
syntax literals as soon as possible. I certainly move the whole app codebase
to python if exist a cheap way -and still 100% interface compatible to the
coccoa-api - as like move js->coffescript for sure!

Is masochist persist in a old way just because is harder. Like when some
refuse to upgrade the same language codebase to improve things (for example, I
will move to LINQ, Lambdas, parallel code, async in C# as I move along) _IF_
the change provide some advantage - reducing lines, better API, more
performance, better clarity, etc -

I tough constant -but careful- refactoring of a live project is very healthy.

Is better doing it when the project is moving, that wait until a major event
happend in the industry -like what happend to my competitors, still on .NET 1
/ VB Classic- and suddenly, your move is damm hard, too costly, and you have
no skills in the "new thing".

I certainly think something that replace or massively fix JS (including, a
better JS) will be very usefull.

If is ok to move from inline styles to CSS, and from HTML to HTML5, then move
from JS with issues related from years of hacking-along-design to anything
else, like CS, is a good effort.

~~~
adgar
> Improve the codebase (make it small, cleaner, more easy to read, and fix
> issues of pastime) is NOT a wasted time. Not necessarily the BEST USE of
> time at a given moment, but dedicate some time to refresh the code with
> better tools, better syntax, better libraries, etc is a excellent way to
> move forward.

And as everybody has been repeatedly pointing out, switching from JavaScript
to Coffeescript isn't what you're describing.

Tools? The tools aren't even close to what's available for JS.

Libraries? Libraries aren't even relevant since Coffeescript can call out to
JS and vice-versa.

Translating to Coffeescript sacrifices tooling and a codebase you know for a
prettier syntax and reliance on the much smaller, much more insular community
driving the language. And I'll say it: syntax is a _stupid_ reason to abandon
code you KNOW for code you're about to write. A stupid, stupid reason.
Engineers need to be more mature than liking to type fewer characters for an
anonymous function or because list comprehensions are 3 lines fewer than a for
loop.

By rewriting in coffeescript, their version history is likely trashed. They
need to relearn the entire codebase. They need to develop new tools to replace
the old ones they relied on, or more likely, will just live without those
tools.

For a prettier syntax and a couple fewer gotchas. And if a team of 3 can't
avoid the common JS gotchas in their day-to-day, I certainly won't trust them
to rewrite an entire codebase in a language with different semantics just to
get better syntax for what already works.

------
malandrew
You guys should use MD5 digests of files instead of mtime for file change
comparison.

mtime works fine until you want to add other steps that are dependent on the
mtime of ephemeral files occuring previously in your process. Steps such as
minification, uglification and comparison for uploading to a CDN all become a
bit more complex if mtime is used since every compile step has the tendency to
modify mtime so recompilations cascade through the process causing at best
unnecessary processing and at worst weird edge cases if the order of
middleware isn't taken into account (the middleware issues can be avoided with
precompilation before production.

------
supersillyus
I agree with them on the readability issue mostly, but I don't understand the
preference for parens-less function calls, especially where there are
arguments.

Maybe it's a matter of training, but

    
    
       @_update_status_position(e, files)
    

looks much clearer to me than

    
    
       @_update_status_position e, files

~~~
crazygringo
The thing that will really bite you is when you call a function:

    
    
        some_function arg_a
    

And then later on, decide it doesn't need an argument after all, and simply
delete it:

    
    
        some_function
    

And then discover it doesn't work, because you have to _remember_ to add the
parentheses back in:

    
    
        some_function()
    

It's the little inconsistencies like that which keep driving you nuts... :)

~~~
tborg
I just opt for parens every time. I really think they shouldn't ever be
optional if in some cases they are mandatory. That this is a matter of
personal style is somewhat frustrating.

~~~
dyselon
I just use parens every time as well.

Remembering to call a function differently depending on whether it has
arguments or not has been a common source of errors for me.

It's also much easier for me to parse the difference between "foo(bar(baz))"
and "foo(bar, baz)" than it is for me to parse the difference between "foo bar
baz" and "foo bar, baz"

------
aaronbrethorst
"I had to be done [with Javascript] in ten days or something worse than JS
would have happened."

I've heard this quote from Eich several times now, but I've never heard what
the "worse than JS" alternative would have been. Anyone know?

~~~
calibraxis
He said it right afterwards: _"Something like PHP only worse..."_

([http://www.jwz.org/blog/2010/10/every-day-i-learn-
something-...](http://www.jwz.org/blog/2010/10/every-day-i-learn-something-
new-and-stupid/#comment-1021))

------
bostonaholic
}); is not a line of code. Please stop counting it as such. Here's a good rule
of thumb:

"If it can be moved to the line above, without any other changes, it's not its
own line of code."

The argument that CoffeeScript saves countless }); }); } } is invalid, IMO. I
would even argue that function definitions are not lines of code. Example:
(ruby)

def foo end

0 lines of code.

BTW, I'm not a CoffeeScript hater, just trying to level the playing field.

~~~
untog
_The argument that CoffeeScript saves countless }); }); } } is invalid, IMO._

I agree that counting }); as a line isn't necessary, but CoffeeScript saving
you doing any of that is a very valid benefit. It cleans up code dramatically-
ignore line numbers and just think about all the extra stuff that ends up
surrounding multiple function calls.

~~~
thezilch
I'm thinking it doesn't happen that often, and I would counter with having you
think just how much more cognitive effort is used in parsing and debugging the
syntax of CS. Remember, debugging and reading "old" code dominates our days,
so it doesn't add up for me. As well, if you and the many others that like to
claim keystroke reductions, there is no difference in "fu<tab>" for "->" and
numerous other comparisons.

~~~
untog
_just how much more cognitive effort is used in parsing and debugging the
syntax of CS_

Have you tried CS? It's _far_ more readable, by virtue of not having
"function() {}" splattered all over the page. I don't care/worry about
keystroke reductions, I care about readable code. The lack of curly brackets
and addition of significant whitespace absolutely _does_ make for more
readable code.

~~~
thezilch
Sure, I've tried it. Function calls are never splattered all over my page, so
I don't have to care about that. And at best, it only allows me to cram more
crap onto a single line, which is also not often helpful. Instead, I get to --
have to -- think about and end every function with something sane, in the
event, for example with jQuery's .each(), I can't have my function magically
returning false -- the last evalutated variable -- and terminating the each
mapping.

My code already has significant whitespace; it's required by styleguide and
linting. CS has prolific issues with whitespace usage, especially when it
comes to parsing function arguments and lines broken over multiple lines. Just
look through this or any other thread on CS being pushed.

CS often has mind fucks, and I'd rather have to ignore a couple lines with }
on them.

Note: I mostly write in Python, if that gives any indication into how I very
much enjoy significant whitespace.

------
AndyKelley
The middle code example can further be broken down[2] by using coco[1] instead
of coffee-script.

JavaScript:

    
    
        this.originalStyle = {};
        ['top', 'left', 'width', 'height'].each(function (k) {
          this.originalStyle[k] = this.element.style[k];
        }.bind(this));
    

Coffee-script:

    
    
        @originalStyle = {}
        for k in ['top', 'left', 'width', 'height']
          @originalStyle[k] = @element.style[k]
    

coco:

    
    
        @originalStyle = @element.style{'top', 'left', 'width', 'height'}
    
    

coco also solves a rather nasty variable scoping issue[3]

[1]: <https://github.com/satyr/coco/> [2]:
[http://satyr.github.com/cup/#c:@originalStyle%20=%20@element...](http://satyr.github.com/cup/#c:@originalStyle%20=%20@element.style%7Btop,%20left,%20width,%20height%7D)
[3]: <https://github.com/jashkenas/coffee-script/issues/712>

------
funkiee
It's nice to see some more prominent companies using CoffeeScript that people
could point to if they ever wanted to convince their boss.

Did any of the other Dropbox employees have a hard lead-in time getting used
to the syntax in CoffeeScript? Would you say you run into a lot fewer syntax
errors when running validation now?

------
geon
The first comparison is not fair. Audio is 1D, while code is 2D.

Obviously CoffeeScript is less cluttered, but JS is nowhere near as bad as the
audio makes it sound.

~~~
ivanstojic
I'd say it goes further than that, as this isn't 1992 any more. I can't
possibly find code pronunciation to be of imperative importance because I
rarely debug code over the phone.

At any given time, I'm likely to have at least two of the following with me: a
phone, a tablet or a laptop. Just e-mail me the code. Make a gist with the
problematic section. Push it to a branch in our git repo so I can take a look
at it myself. IM it to me. Don't _read_ it to me.

------
jackfoxy
Speaking as someone who has managed coders writing far more lines of
javascript than I will ever write, this is a better articulation of my belief
that javascript should be generated from another language (CoffeeScript being
the leader) than I could ever propose. Thanks Dropbox! This post should be
read by everyone who writes or manages those who write javascript.

------
dustingetz
the question that should motivate a change like this:

what does new-language let your team accomplish that you can't accomplish with
old-language?

question isn't answered in post, the answer is probably somewhere along a 2x
increase in the complexity the same team can handle. i dunno if it is worth
disturbing an existing codebase and the QA cost of making sure you didn't
introduce any defects. meh. where i work, we have maybe 100k lines of
javascript, and its not really a problem other than lack of types when
refactoring imperative code, nothing near the scope of the problem of Java's
lack of higher order functions.

------
seangransee
this is great news! for people who prefer python-like syntax, coffeescript is
a no-brainer. sites like js2coffee.com make it really easy to make the
transition.

------
skilesare
I tell my prospective clients that if their contractors/employees are still
programming in js then they are stealing from them.

Coffee Script is clearer, more concise, more maintainable. It has made me 5x
more efficient in writing code (just the reduction in scrolling is a massive
time savings) and I've seen similar results with my developers.

It takes about 2 days to learn and has a significant long term benefit.
Switch.

------
Ygg2
_In our case, we avoided this problem entirely by instrumenting our server
code: whenever someone reloads a Dropbox page running on their development
server, it compare mtimes between .coffee files and compiled .js equivalents.
Anything needing an update gets compiled._

I wonder how did they achieve this? Is this a feature of node.js or is this
like an automated build system? I suspect the latter.

~~~
reuben_m
They said exactly how they did it, it's right there in your quote: when
someone reloads a page running on their dev server, the server checks if the
CS file has been modified and triggers the compilation… So no, it's not a
build system feature, it's a server feature.

------
kevincennis
Wait, they're looking forward to "Native CoffeeScript support in browsers, so
that during development, we can avoid the compilation to JavaScript
altogether."?

Is there something I don't know about?

------
dotborg
Ctrl+Shift+F - does it work with CoffeeScript in Eclipse?

oh wait, no semicolons :/

------
MatthewPhillips
tldr:

> Disclaimer: we love Python, and it’s Dropbox’s primary language, so we’re
> probably biased.

~~~
lowe
heh, I included this line because it's true, but that whole section is about
why "use coffee because you like python" is the wrong tldr.

~~~
MatthewPhillips
The rest of the article is about how you prefer CoffeeScript syntax, so how is
that tldr wrong?

~~~
scott_s
Because an accurate summary would actually summarize what they said, not just
list their bias. I would summarize it as, "The Dropbox team prefers the
readability of Coffeescript, the conversion took one week, they reduced the
lines of code in their codebase by 20%, and there was no impact on
functionality."

------
lucian303
"We’ve heard many arguments for and against debuggability, and in the end, we
convinced ourselves that it’s easy only after jumping in and trying it."

So, in other words, you have only your own opinion and at best one (1)
anecdotal experience. Congratulations! You've failed to prove your point from
a logical perspective, let alone anything more!

~~~
gfodor
I didn't get the sense they were trying to convince anyone, just pointing out
why it makes sense for them.

------
pjmlp
As I only use the native application, I can care less.

