Sunday, October 18, 2015

Hacking on Atom Part II: Building a Development Process

Over one year ago, I wrote a blog post: “Hacking on Atom Part I: CoffeeScript”. This post (Part II) is long overdue, but I kept putting it off because I continued to learn and improve the way I developed for Atom such that it was hard to reach a “stopping point” where I felt that the best practices I would write up this week wouldn't end up becoming obsolete by something we discovered next week.

Honestly, I don't feel like we're anywhere near a stopping point, but I still think it's important to share some of the things we have learned thus far. (In fact, I know we still have some exciting improvements in the pipeline for our developer process, but those are gated by the Babel 6.0 release, so I'll save those for another post once we've built them out.)

I should also clarify that when I say “we,” I am referring to the Nuclide team, of which I am the tech lead. Nuclide is a a collection of packages for Atom to provide IDE-like functionality for a variety of programming languages and technologies. The code is available on GitHub (and we accept contributions!), but it is primarily developed by my team at Facebook. At the time of this writing, Nuclide is composed of 40 Atom packages, so we have quite a bit of Atom development experience under our belts.

My Transpiler Quest

When I spun up the Nuclide project, I knew that we were going to produce a lot of JavaScript code. Transpilers such as Traceur were not very mature yet, but I strongly believed that ES6 was the future and I didn't want to start writing Nuclide in ES5 and have to port everything to ES6 later. On a high level, I was primarily concerned about leveraging the following language extensions:
  • Standardized class syntax
  • async/await
  • JSX (for React)
  • type annotations
Note that of those four things, only the first one is specified by ES6. async/await appears to be on track for ES7, though I don't know if the TC39 will ever be able to agree on a standard for type annotations or let JSX in, but we'll see.

Because of my diverse set of requirements, it was hard to find a transpiler that could provide all of these things:
  • Traceur provided class syntax and other ES6 features, but more experimental things like async/await were very buggy.
  • TypeScript provided class syntax and type annotations, but I knew that Flow was in the works at Facebook, so ultimately, that is what we would use for type annotations.
  • React came with jstransform, which supported JSX and a number of ES6 features.
  • recast provided a general JavaScript AST transformation pipeline. Most notably, the regenerator transform to provide support for yield and async/await was built on recast.
Given my constraints and the available tools, it seemed like investing in recast by adding more transforms for the other features we wanted seemed like the most promising way to go. In fact, someone had already been working on such an endeavor internally at Facebook, but the performance was so far behind that of jstransform that it was hard to justify the switch.

For awhile, I tried doing crude things with regular expressions to hack up our source so that we could use regenerator and jstransform. The fundamental problem was that transpilers do not compose  because if they both recognize language features that cause parse errors in the other, then you cannot use them together. Once we started adding early versions of Flow into the mix to get type checking (and Flow's parser recognized even less of ES6 than jstransform did), the problem became even worse. For a long time, in an individual file, we could have async/await or type checking, but not both.

To make matters worse, we also had to run a file-watcher service that would write the transpiled version of the code someplace where Atom could load it. We tried using a combination of gulp and other things, but all too often a change to a file would go unnoticed, the version on disk would not get transpiled correctly, and we would then have a subtle bug (this seemed to happen most often when interactive rebasing in Git).

It started to become questionable whether putting up with the JavaScript of the future was worth it. Fortunately, it was around this time that Babel (née 6to5) came on the scene. It did everything that we needed and more. I happily jettisoned the jstransform/regenerator hack I had cobbled together. Our team was so much happier and more productive, but there were still two looming issues:
  • Babel accepted a much greater input language than Flow.
  • It did not eliminate the need for a file-watching service to transpile on the fly for Atom.
Rather than continue to hack around the problems we were having, we engaged with the Flow and Atom teams directly. For the Flow team, supporting all of ES6 has been an ongoing issue, but we actively lobbied to prioritize to support features that were most important to us (and caused unrecoverable parse errors if they were not addressed), such as support for async/await and following symlinks through require/import statements.

To eliminate our gulp/file-watching contraption, we upstreamed a pull request to Atom to support Babel natively, just as it already had support for CoffeeScript. Because we didn't want to identify Babel files via a special extension (we wanted the files to be named .js rather than .es6 or something), and because (at least at the time), Babel was too slow to categorically transpile all files with a .js extension, we compromised on using the heuristic “if a file has a .js extension and its contents start with 'use babel', then transpile the file with Babel before evaluating it.” This has worked fairly well for us, but it also meant that everyone had to use the set of Babel options that we hardcoded in Atom. However, once Babel 6.0 comes out, we plan to work with Atom to let packages specify a .babelrc file so that every package can specify its own Babel options.

It has been a long road, but now that we are in a world where we can use Babel and Flow to develop Atom packages, we are very happy.

Node vs. Atom Packages

Atom has its own idea of a package that is very similar to an npm package, but differs in some critical ways:
  • Only one version/instance of an Atom package can be loaded globally in the system.
  • An Atom package cannot declare another Atom package as a dependency. (This somewhat follows from the first bullet point because if two Atom packages declared a dependency on different versions of the same Atom package, it is unclear what the right way to resolve it would be.)
  • Because Atom packages cannot depend on each other, it is not possible to pull in another one synchronously via require().
  • Atom packages have special folders such as styles, grammars, snippets, etc. The contents of these folders must adhere to a specific structure, and their corresponding resources are loaded when the Atom package is activated.
This architecture is particularly problematic when trying to build reusable UI components. Organizationally, it makes sense to put something like a combobox widget in its own package that can be reused by other packages. However, because it likely comes with its own stylesheet, it must be bundled as an Atom package rather than a Node package.

To work around these issues, we introduced the concept of three types of packages in Nuclide: Node/npm, Node/apm, and Atom/apm. We have a README that explains this in detail, but the key insight is that a Node/apm package is a package that is available via npm (and can be loaded via require()), but is structured like an Atom package. We achieved this by introducing a utility, nuclide-atom-npm, which loads the code from a Node package, but also installs the resources from the styles/ and grammars/ directories in the package, if present. It also adds a hidden property on global to ensure that the package is loaded only once globally.

Nuclide has many packages that correspond to UI widgets that we use in Atom: nuclide-ui-checkbox, nuclide-ui-dropdown, nuclide-ui-panel, etc. If you look at the implementation of any of these packages, you will see that they load their code using nuclide-atom-npm. Using this technique, we can reliably require the building blocks of our UI synchronously, which would not be the case if our UI components were published as Atom packages. This is especially important to us because we build our UI in Atom using React.


In July 2014, the Atom team had a big blog post that celebrated their move to React for the editor. Months later, they had a very quiet pull request that removed the use of React in Atom. Basically, the Atom team felt that to achieve the best possible performance for their editor, they needed to hand-tune that code rather than risk the overhead of an abstraction, such as React.

This was unfortunate for Nuclide because one of the design limitations of React is that it expects there to be only one instance of the library installed in the environment. When you own all of the code in a web page, it is not a big deal to commit to using only one version (if anything, it's desirable!), but when you are trying to create an extensible platform like Atom, it presents a problem. Either Atom has to choose the version of React that every third-party package must use, or every third-party package must include its own version of React.

The downside of Atom mandating the version of React is that, at some point, some package authors will want them to update it when a newer version of React comes out whereas other package authors will want them to hold back so their packages don't break. The downside of every third-party package (that wants to use React) including its own version is that multiple instances of React are not guaranteed to work together when used in the same environment. (It also increases the amount of code loaded globally at runtime.)

Further, React and Atom also conflict because they both want to control how events propagate through the system. To that end, when Atom was using React for its editor, it created a fork of React that did not interfere with Atom's event dispatch. This was based on React v0.11, which quickly became an outdated version of React.

Because we knew that Atom planned to remove their fork of React from their codebase before doing their 1.0 release, we needed to create our own fork that we could use. To that end, Jonas Gebhardt created the react-for-atom package, which is an Atom-compatible fork of React based off of React v0.13. As we did for the nuclide-atom-npm package, we added special logic that ensured that require('react-for-atom') could be called by various packages loaded by Atom, but it cached the result on the global environment so that subsequent calls to require() would return the cached result rather than load it again, making it act as a singleton.

Atom does not provide any sort of built-in UI library by default. The Atom UI itself does not use a standard library: most of the work is done via raw DOM operations. Although this gives package authors a lot of freedom, it also arrests some via a paradox of choice. On Nuclide, we have been using React very happily and successfully inside of Atom. The combination of Babel/JSX/React has facilitated producing performant and maintainable UI code.


Atom is developed as a collection of over 100 packages, each contained in its own repository. From the outside, this seems like an exhausting way to develop a large software project. Many, many commits to Atom are just minor version bumps to dependencies in package.json files across the various repos. To me, this is a lot of unnecessary noise.

Both Facebook and Google have extolled the benefits of a single, monolithic codebase. One of the key advantages over the multi-repo approach is that it makes it easier to develop and land atomic changes that span multiple parts of a project. For this and other reasons, we decided to develop the 100+ packages for Nuclide in a single repository.

Unfortunately, the Node/npm ecosystem makes developing multiple packages locally out of one repository a challenge. It has a heavy focus on semantic versioning and encourages dependencies to be fetched from Yes, it is true that you can specify local dependencies in a package.json file, but then you cannot publish your package.json file as-is.

Rather than embed local, relative paths in package.json files that get rewritten upon publishing to npm (which I think would be a reasonable approach), we created a script that walks our tree, symlinking local dependendencies under node_modules while using npm install to fetch the rest. By design, we specify the semantic version of a local dependency as 0.0.0 in a package.json file. These version numbers get rewritten when we publish packages to npm/apm.

We also reject the idea of semantic versioning. (Jeremy Ashkenas has a great note about the false promises of semantic versioning, calling it “romantic versioning.”) Most Node packages are published independently, leaving the package author to do the work of determining what the new version number should be based on the changes in the new release. Practically speaking, it is not possible to automate the decision of whether the new release merits a minor or major version bump, which basically means the process is imperfect. Even when the author gets the new version number right, it is likely that he/she sunk a lot of time into doing so.

By comparison, we never publish a new version of an individual Nuclide package: we publish new versions of all of our packages at once, and it is always a minor-minor version bump. (More accurately, we disallow cycles in our own packages' dependencies, so we publish them in topological order, all with the same version number where the code is derived from the same commit hash in our GitHub repo.) It is indeed the case that for many of our packages, there is nothing new from version N to N+1. That is, the only reason N+1 was published is because some other package in our repo needed a new version to be published. We prefer to have some superfluous package publications than to sink time into debating new version numbers and updating scores of package.json files.

Having all of the code in one place makes it easier to add processes that are applied across all packages, such as pre-transpiling Babel code before publishing it to npm or apm or running ESLint. Also, because our packages can be topologically sorted, many of the processes that we run over all of our packages can be parallelized, such as building or publishing. Although this seems to fly in the face of traditional Node development, it makes our workflow dramatically simpler.


I can't say enough good things about using async/await, which is something that we can do because we use Babel. Truth be told, as a side-project, I have been trying to put all of my thoughts around it into writing. I'm at 35 pages and counting, so we'll see where that goes.

An oversimplified explanation of the benefit is that it makes asynchronous code no harder to write than synchronous code. Many times, JavaScript developers know that designing code to be asynchronous will provide a better user experience, but give in to writing synchronous code because it's easier. With async/await, you no longer have to choose, and everyone wins as a result.


Similar to async/await, I can't say enough good things about static typing, particularly optional static typing. I gave a talk at the first mloc.js, “Keeping Your Code in Check,” demonstrating different approaches to static typing in JavaScript, and argued why it is particularly important for large codebases. Flow is a fantastic implementation of static typing in JavaScript.

Closing Thoughts

In creating Nuclide, we have written over 50,000 lines of JavaScript[1] and have created over 100 packages, 40 of which are Atom packages[2]. Our development process and modularized codebase has empowered us to move quickly. As you can tell from this essay (or from our scripts directory), building out this process has been a substantial, deliberate investment, but I think it has been well worth it. We get to use the best JavaScript technologies available to us today with minimal setup and an edit/refresh cycle of a few seconds.

Honestly, the only downside is that we seem to be ahead of Atom in terms of the number of packages it can support. We have an open issue against Atom about how to install a large number of packages more efficiently (note this is a problem when you install Nuclide via nuclide-installer, but not when you build from source). Fortunately, this should [mostly] be a simple matter of programming™: there is no fundamental design flaw in Atom that is getting in the way of a solution. We have had an outstanding working relationship with Atom thus far, finding solutions that improve things for not just Nuclide, but the entire Atom community. It has been a lot of fun to build on top of their platform. For me, working on Atom/Nuclide every day has been extremely satisfying due to the rapid speed of development and the tools we are able to provide to our fellow developers as a result of our work.

[1] To exclude tests and third-party code, I got this number by running:
git clone
cd nuclide
git ls-files pkg | grep -v VendorLib | grep -v hh_ide | grep -v spec | grep -e '\.js$' | xargs wc -l
[2] There is a script in Nuclide that we use to list our packages in topologically sorted order, so I got these numbers by running:
./scripts/dev/packages | wc -l
./scripts/dev/packages --package-type Atom | wc -l

Thursday, March 5, 2015

Trying to prove that WeakMap is actually weak

I don't have a ton of experience with weak maps, but I would expect the following to work:
// File: example.js
var key = {};
var indirectReference = {};
indirectReference['key'] = (function() { var m = {}; m['foo'] = 'bar'; return m; })();
var map = new WeakMap();

map.set(key, indirectReference['key']);
console.log('Has key after setting value: %s', map.has(key));

delete indirectReference['key'];
console.log('Has key after deleting value: %s', map.has(key));

console.log('Has key after performing global.gc(): %s', map.has(key));
I downloaded the latest version of io.js (so that I could have a JavaScript runtime with WeakMap and global.gc() and ran it as follows:
./iojs --expose-gc example.js
Here is what I see:
Has key after setting value: true
Has key after deleting value: true
Has key after performing global.gc(): true
Despite my best efforts, I can't seem to get WeakMap to give up the value that is mapped to key. Am I doing it wrong? Obviously I'm making some assumptions here, so I'm curious where I'm off.

Ultimately, I would like to be able to use WeakMap to write some tests to ensure certain objects get garbage collected and don't leak memory.

Tuesday, August 19, 2014

Hacking on Atom Part I: CoffeeScript

Atom is written in CoffeeScript rather than raw JavaScript. As you can imagine, this is contentious with “pure” JavaScript developers. I had a fairly neutral stance on CoffeeScript coming into Atom, but after spending some time exploring its source code, I am starting to think that this is not a good long-term bet for the project.

Why CoffeeScript Makes Sense for Atom

This may sound silly, but perhaps the best thing that CoffeeScript provides is a standard way to declare JavaScript classes and subclasses. Now before you get out your pitchforks, hear me out:

The “right” way to implement classes and inheritance in JavaScript has been of great debate for some time. Almost all options for simulating classes in ES5 are verbose, unnatural, or both. I believe that official class syntax is being introduced in ES6 not because JavaScript wants to be thought of as an object-oriented programming language, but because the desire for developers to project the OO paradigm onto the language today is so strong that it would be irresponsible for the TC39 to ignore their demands. This inference is based on the less aggressive maximally minimal classes proposal that has superseded an earlier, more fully-featured, proposal, as the former states that “[i]t focuses on providing an absolutely minimal class declaration syntax that all interested parties may be able to agree upon.” Hooray for design by committee!

Aside: Rant

The EcmaScript wiki is the most frustrating heap of documentation that I have ever used. Basic questions, such as, “Are Harmony,, and ES6 the same thing?” are extremely difficult to answer. Most importantly, it is impossible to tell what the current state of ES6 is. For example, with classes, there is a proposal under harmony:classes, but another one at Maximally Minimal Classes. Supposedly the latter supersedes the former. However, the newer one has no mention of static methods, which the former does and both Traceur and JSX support. Perhaps the anti-OO folks on the committee won and the transpilers have yet to be updated to reflect the changes (or do not want to accept the latest proposal)?

In practice, the best information I have found about the latest state of ES6 is at I stumbled upon that via a post in traceur-compiler-discuss that linked to some conference talk that featured the link to the TC39 member’s on GitHub. (The conference talk also has an explicit list of what to expect in ES7, in particular async/await and type annotations, which is not spelled out on the EcmaScript wiki.) Also, apparently using an entire GitHub repo to post a single web page is a thing now. What a world.

To put things in perspective, I ran a git log --follow on some key files in the src directory of the main Atom repo, and one of the earliest commits I found introducing a .coffee file is from August 24, 2011. Now, let’s consider that date in the context of modern JavaScript transpiler releases:

As you can see, at the time Atom was spinning up, CoffeeScript was the only mature transpiler. If I were starting a large JavaScript project at that time (well, we know I would have used Closure...) and wanted to write in a language whose transpilation could be improved later as JavaScript evolved, then CoffeeScript would have made perfect sense. Many arguments about what the “right JavaScript idiom is” (such as how to declare classes and subclasses) go away because CoffeeScript is more of a “there’s only one way to do it” sort of language.

As I mentioned in my comments on creating a CoffeeScript for Objective-C, I see three primary benefits that a transpiled language like CoffeeScript can provide:

  • Avoids boilerplate that exists in the target language.
  • Subsets the features available in the source language to avoid common pitfalls that occur when those features are used in the target language.
  • Introduces explicit programming constructs in place of unofficial idioms.

Note that if you have ownership of the target language, then you are in a position to fix these things yourself. However, most of us are not, and even those who are may not be that patient, so building a transpiler may be the best option. As such, there is one other potential benefit that I did not mention in my original post, but has certainly been the case for CoffeeScript:

  • Influences what the next version of the target language looks like.

But back to Atom. If you were going to run a large, open source project in JavaScript, you could potentially waste a lot of time trying to get your contributors to write JavaScript in the same way as the core members of the project. With CoffeeScript, there is much less debate.

Another benefit of using CoffeeScript throughout the project is that config files are in CSON rather than JSON. (And if you have been following this blog, you know that the limitations of JSON really irritate me. Go JSON5!) However, CSON addresses many of shortcomings of JSON because it supports comments, trailing commas, unquoted keys, and multiline strings (via triple-quote rather than backslashes). Unfortunately, it also supports all of JavaScript as explained in the README:

“CSON is fantastic for developers writing their own configuration to be executed on their own machines, but bad for configuration you can't trust. This is because parsing CSON will execute the CSON input as CoffeeScript code...”
Uh...what? Apparently there’s a project called cson-safe that is not as freewheeling as the cson npm module, and it looks like Atom uses the safe version. One of the unfortunate realities of the npm ecosystem is that the first mover gets the best package name even if he does not have the best implementation. C’est la vie.

Downsides of Atom Using CoffeeScript

I don’t want to get into a debate about the relative merits of CoffeeScript as a language here (though I will at some other time, I assure you), but I want to discuss two practical problems I have run into that would not exist if Atom were written in JavaScript.

First, many (most?) Node modules that are written in CoffeeScript have only the transpiled version of the code as part of the npm package. That means that when I check out Atom and run npm install, I have all of this JavaScript code under my node_modules directory that has only a vague resemblance to its source. If you are debugging and have source maps set up properly, then this is fine, but it does not play nice with grep and other tools. Although the JavaScript generated from CoffeeScript is fairly readable, it is not exactly how a JavaScript developer would write it by hand, and more importantly, single-line comments are stripped.

Second, because Atom is based on Chrome and Node, JavaScript developers writing for Atom have the benefit of being able to rely on the presence of ES6 features as they are supported in V8. Ordinary web developers do not have this luxury, so it is very satisfying to be able to exploit it! However, as ES6 introduces language improvements, they will not be available in CoffeeScript until CoffeeScript supports them. Moreover, as JavaScript evolves into a better language (by copying features from language like CoffeeScript), web developers will likely prefer “ordinary” JavaScript because it is likely that they will have better tool support. As the gap between JavaScript and CoffeeScript diminishes, the cost of doing something more nonstandard (i.e., using a transpiler) does not outweigh the benefits as much as it once did. Arguably, the biggest threat to CoffeeScript is CoffeeScript itself!

Closing Thoughts

Personally, I plan to develop Atom packages in JavaScript rather than CoffeeScript. I am optimistic about where JavaScript is going (particularly with respect to ES7), so I would prefer to be able to play with the new language features directly today. I don’t know how long my code will live (or how long ES6/ES7 will take), but I find comfort in knowing that I am less likely to have to rewrite my code down the road when JavaScript evolves. Finally, there are some quirks to CoffeeScript that irk me enough to stick with traditional JavaScript, but I’ll save those for another time.

Hacking on Atom Series

I have started to spend some time hacking on Atom, and I wanted to share some of my thoughts and learnings from this exploration. I have not posted on my blog in awhile, and this seems like the right medium to document what I have discovered (i.e., too long for a tweet; not profound enough for an essay; failing to answer in the form of a question suitable for the Atom discussion forum).

In the best case, in places where I have stumbled with Atom’s design or implementation, I hope that either (1) someone sets me straight on best practices and why things work the way they do, or (2) to spur discussion on how to make things better. Hacking on Atom is a lot of fun, but I still have a lot to learn.

Monday, October 28, 2013

Today I am making Appendix B of my book available for free online

Today I am making one of the appendices of my book available for free: Appendix B: Frequently Misunderstood JavaScript Concepts. You might expect that appendices are just extra junk that authors stick at the end of the book to up their page count, like reference material that is readily available online. And if that were the case, this would be an uncharitable and worthless thing to do.

As it turns out, many have told me that Appendix B has been the most valuable part of the book for them, so I assure you that I am not releasing the "dregs" of the text. Unsurprisingly, many many more folks are interested in JavaScript in general than are interested in Closure Tools, which is presumably why this appendix has been a favorite.

Because the manuscript was written in DocBook XML, it was fairly easy to programmatically translate the XML into HTML. For some reason, I do not have a copy of the figure from Appendix B that appears in the book, so I had to recreate it myself. Lacking real diagramming tools at the time, I created the original illustration using Google Docs. It took several rounds with the illustrator at O'Reilly to get it reproduced correctly for my book. Since I was too embarrassed to include the Google Docs version in this "HTML reprint," I redid it using Omnigraffle, which I think we can all agree looks much better.

In some ways, the HTML version is better than the print or ebook versions in that (1) the code samples are syntax highlighted, and (2) it is possible to hyperlink to individual sections. Depending on how this is received, I may make more chunks of the book available in the future. As I mentioned, the script to convert the XML to HTML is already written, though it does contain some one-off fixes that would need to be generalized to make it reusable for the other chapters.

If you want to read the rest of Closure: The Definitive Guide (O'Reilly), you can find it on Amazon and other web sites that sell dead trees.

Saturday, August 17, 2013

Hello, World!

Traditionally, "Hello, World!" would be the first post for a new blog, but this is post #100 for the Bolinfest Changeblog. However, I have posted so infrequently in the past year and a half that I thought it would be nice to check in and say hello to report on what I have been up to, as well as some of the projects that I maintain, as I have not been able to respond to all of the email requests for status updates. I'll start with the big one:

I moved to California and joined Facebook

The latter was not the cause for the former. I moved to California to co-found a startup (check!), but after killing myself for three months, I decided that the combination of working on consumer software that served millions (now billions) of users and getting a stable paycheck was something I really enjoyed. Now that I was in California, there were more companies where I could do that then there were in New York City, so I shopped around a bit. After working at Google for so long and feeling like Facebook was The Enemy/technically inferior (they write PHP, right?), I never thought that I would end up there.

Fortunately, I decided to test my assumptions about Facebook by talking to engineers there who I knew and greatly respected, and I learned that they were quite happy and doing good work. Facebook in 2012 felt more like the Google that I joined in 2005 than the Google of 2012 did, so I was also excited about that. Basically, Facebook is a lot smaller than Google, yet I feel like my potential for impact (both in the company and in the world) is much larger. I attended Google I/O this year, and although I was in awe of all of the announcements during the keynote, I imagined that whatever I could do at Google would, at best, be one tiny contribution to that presentation. Personally, I found the thought of feeling so small pretty demoralizing.

Fast-forward to life at Facebook, and things are exciting and going well. "Done is better than perfect" is one of our mantras at Facebook, which encourages us to move fast, but inevitably means that there is always some amount of shit that is broken at any given time. Coming from Google, this was pretty irritating at first, but I had to acknowledge that that mentality is what helped Facebook get to where it is today. If you can be Zen about all of the imperfections, you can find motivation in all the potential impact you can have. At least that's what I try to do.

Using Outlook instead of Gmail and Google Calendar is infuriating, though.

I spend my time writing Java instead of JavaScript

In joining a company that made its name on the Web, and knowing a thing or two about JavaScript, I expected that I would be welcomed into the ranks of UI Engineering at Facebook. Luckily for me, that did not turn out to be the case.

At Facebook, there are many web developers who rely on abstractions built by the core UI Engineering (UIE) team. When I joined, my understanding was that if you wanted to be a UIE, first you needed to "pay your dues" as a web developer for at least a year so that you understood the needs of the Web frontend, and then perhaps you could be entrusted as a UIE. In general, this seems like a reasonable system, but all I was thinking was: "I made Google Calendar and Google Tasks work in IE6. I have paid my fucking dues."

Fortunately, some friends steered me toward joining mobile at Facebook, it being the future of the company and whatnot. At first, I was resistant because, to date, I had built a career on writing JavaScript, so I was reluctant to lay that skillset by the wayside and learn a new one. I also realized that that line of thinking is what would likely turn me into a dinosaur one day, so I needed to resist it.

Okay, so Android or iOS? I had just gotten a new iPhone after living miserably on a borrowed Nexus One for the previous six months (my 3GS only lasted 75% of the way through my contact), so the thought of doing Android development, which would require me to live with an Android phone every day again was pretty distasteful. However, my alternative was to write Objective-C (a language where you have to manage your own memory and suffers from dissociative identity disorder, as it has dual C and obj-C constructs for every programming concept) in an IDE I cannot stand (Eclipse figured out how to drag-and-drop editor tabs about a decade ago, why does XCode make organizing my windows so difficult?) on a platform that irritates me (every time the End key takes me to the end of the document instead of the end of the line, I want to shoot someone). As an Android developer, at least I could use Linux and write in Java (a language that I should probably be ashamed to admit that I enjoy, but whose effectiveness in programming in the large continues to make me a supporter).

Historically, the iPhone has always been a beloved piece of hardware (and is the device app developers flock to), whereas Android devices have been reviled (anyone remember the G1?). The same was true at Facebook when I joined: more engineers owned iPhones themselves (for a long time, it felt like the only people who owned Android phones were Google employees who had been given them for free, though obviously that has changed...), so more of them wanted to work on the iPhone app, and hence Facebook's iPhone app was a lot better than its Android app. Again, this is what made the possibility of working on Android simultaneously frustrating and intriguing: the codebase was a nightmare, but there was a huge opportunity for impact. For my own career, it was clear that I should learn at least one of Android or iOS, and Android seemed like the one where I was likely to have the most success, so that's what I went with.

But like I said, the codebase was a nightmare. What was worse was that building was a nightmare. We were using a hacked up version of the standard Ant scripts that Google provides for Android development. Like many things at Facebook, our use case is beyond the scale of ordinary use cases, so the "standard" solution does not work for us. We actually had many Ant scripts that called one another, which very few people understood. As you can imagine, developers' builds frequently got into bad states, in which case people could not build, or would do a clean build every time, which is very slow. In sum, Android development was not fun.

After dealing with this for a couple of weeks and wondering what I had gotten myself into, I said, "Guys, this is ridiculous: I am going to create a new build system. We can't keep going like this." As you can imagine, there were a lot of objections:

  • "Why can't we use an existing build system like Ninja or Gradle?"
  • "What happens when Google fixes its build system? Then we'll have to play catch up."
  • "Would you actually support your custom build system long-term?"
  • "Seriously, why do engineers always think they can build a better build system?"
Resounding support, I had not.

At that point, I had no credibility in Android, and more importantly, no credibility at Facebook. If I decided to go against the grain and my build system was a failure, I would not have a any credibility in the future, either. On the other hand, there was no way I was going to endure life as an Android developer if I had to keep using Ant, so I forged ahead and started working on my own build system.

In about a month and a half, I built and deployed Buck, an Android build system. Builds were twice as fast, so the number of objections decreased considerably. Life at Facebook was, and continues to be, very good.

I spoke at some conferences...

Thus far in 2013, I gave two external talks at conferences, two internal talks at Facebook, and one best man's speech. Public speaking really stresses me out, yet I continue to volunteer to do it. (The best man's speech was the shortest of the five, but probably the most stressful. It's a friendly audience, but expectations are high!) I used to think it was weird when I read that actors like John Malkovich often avoid ever seeing the movies that they are in, but given that I rarely watch recordings of talks I have given, I guess I can understand why. Like listening to your own voice on tape, it always seems worse to you than to anyone else.

This year, for the first time, I was invited to speak at a conference. The name of the conference was mloc.js (mloc = Millon Lines of Code), and the focus was on scaling JavaScript development. Both programming in the large and JavaScript development are topics near and dear to my heart, so this seemed like a great fit for me. I was also honored to be invited to speak anywhere, let alone a foreign country (the conference was in Budapest), so I accepted.

Since some nice group of people was paying me to fly to their country and stay in a hotel, I felt that I owed it to them to give a presentation that did not suck. I also felt like they deserved something new, so rather than rehash one of my talks from 2011 promoting Google Closure, I decided to create a new talk from scratch. The two topics that came to mind were optional typing and async paradigms in JavaScript. Initially, I sketched out one talk about both topics, but I quickly realized that I would only have time for one of the two. Although I feel like someone needs to go in and slap the Node community around until they stop creating APIs based on callbacks instead of Promises (in hopes that we ultimately get an await keyword in JavaScript that takes a Promise), I decided that I could deliver a more thought-provoking talk about optional typing that included references to Legoes and OCaml. And so that's what I did:

(The title of the talk was Keeping Your Code In Check, which is not very specific to what I actually spoke about. Often, conference organizers want talk names and abstracts early in the process so they can make schedules, create programs, etc. In contrast, conference presenters want to do things at the last minute, so I supplied an amorphous title for my talk, figuring that whatever I ended up speaking about could fit the title. I'd say that it worked.)

I spent hours and hours working on this talk. I was so exhausted when I got to the end of the presentation that I botched some of the Q&A, but whatever. The slides are available online, but I always find it hard to get much from a deck alone, and watching the full video takes a long time. In the future, I hope to convert the talk into an essay that is easier (and faster) to consume.

I tried my best not to make Google Closure the focus of my talk, instead trying to expose people to the tradeoffs of various type systems. Google Closure was mainly in there because (1) I did not have to spend any time researching it, (2) it is one of the few successful examples of optional typing out there, and (3) if I sold you on optional typing during my talk, then Google Closure would be something that you as a JavaScript developer could go home and use. I even gave TypeScript some airtime during my talk (though I omitted Dart, since Google was a sponsor of the conference, so they had their chance to pitch), so I thought that was pretty fair. By comparison, if you look at the conference schedule, almost everyone else in the lineup was shilling their own technology, which might be the perfect solution for a handful of members of the audience, but was less likely to be of universal interest. That was my thinking, anyway.

...which included open sourcing the Android build tool that I wrote (Buck)

The second conference I talk I gave was at Facebook's own mobile developer conference in New York City. As I mentioned above, the whole custom Android build system thing worked out pretty well internally, so we deemed it worthy to open source it. This conference seemed like a good vehicle in which to do so, so once we launched Facebook Home on April 4 (which I worked on!), I focused 100% on my conference talk on April 18th.

Though the presentation itself was only a small portion of what I needed to do. We had to clean up the code, excise any comments that referred to secret, internal stuff, and generate sufficient documentation so that people could actually use the thing. For once, I successfully delegated, and everything got done on time, which was great. The only downside was that I was not able to spend as much time rehearsing my talk as I would have liked, but I think that it came out okay:

Note that the title of the talk was How Facebook builds Facebook for Android, which does not mention anything about Buck or a build system at all. This is because we decided to make the open sourcing a surprise! I asked whether I should do "the big reveal" at the beginning or the end of the talk. I was advised that if I did it at at the beginning, then people would stop paying attention to me and start reading up on it on their laptops. If I did it at the end, then I would not leave myself any time to talk about Buck. So clearly, the only reasonable alternative was to "do it live," which is what I ended up doing. If you fast-forward to around 22 minutes in, you can see my "showmansip" (that term definitely deserves to be in quotes) where I get the audience to ask me to flip the switch in GitHub from private to public. It was nerve-wracking, but great fun.

I updated plovr

With so much going on professionally, and my new focus on Android, it has not left much time for plovr. This makes me sad, as the October 2012 release of plovr was downloaded over 9000 times, so that's a lot of developers' lives who could be improved by an updated release. Last month, I finally put out a new release. Part of the reason this took so long is that, in the past 18 months, Oracle dropped support for Java 6 and Google moved some of the SVN repos for Closure Tools over to Git. Both of these things broke the "turn the crank" workflow I had put in place to facilitate turning out new versions of plovr with updated versions of Closure Tools. I finally created a new workflow, and as part of that work, I moved plovr off of Google Code and onto GitHub. I have already accepted a couple of pull requests, so this seems like progress.

Admittedly, now that I am writing Java rather than JavaScript every day, I don't have as much skin in the game when it comes to moving plovr forward. I am hoping to delegate more of that responsibility to those who are using plovr actively. I have some specific individuals in mind, though unfortunately have not to made the effort to reach out quite yet.


Chickenfoot is the venerable end-user programming tool for customizing and automating the Web that I built as part of my Master's thesis at MIT in 2005. It was built as a Firefox extension, as Firefox gave us a unique way to make invasive modifications to a real web browser, while also providing a distribution channel to share our experimental changes with ordinary people (i.e., non-programmers). This was pretty spectacular.

The last official release of Chickenfoot (1.0.7) by MIT was in 2009, and targeted Firefox 3. As the current release of Firefox is version 23.0.1, clearly Chickenfoot 1.0.7 is a bit behind. After the NSF grant for Chickenfoot at MIT ran out (which is what effectively ended "official" development), I moved the source code to GitHub and got some help to release Chickenfoot 1.0.8, which was verified to work on Firefox 4.0-7.0. It may very well also work on Firefox 23.0.1, but I have not kept up.

Historically, we hosted Chickenfoot downloads on MIT's site (instead of Mozilla's offical Add-ons site) because we wanted to control our releases. My experience with submitting an extension to the Mozilla Add-ons site has been no better than my experience with submitting an iOS app to Apple's app store, in that a review on the vendor's end is required, and rejections are frustrating and do happen. Since we were not going to host releases on MIT's site anymore, I decided to give the Add-ons store another try. Here are the contents of the rejection letter from January 19, 2012 (emphasis is mine):

Your add-on, Chickenfoot 1.0.9, has been reviewed by an editor and did not meet the criteria for being hosted in our gallery. Reviewer: Nils Maier Comments: Your version was rejected because of the following problems: 1) This version contains binary, obfuscated or minified code. We need to review all of your source code in order to approve it. Please send the following items to * A link to your add-on listing. * Whether you're nominating this version for Full Review or Preliminary Review. * The source files of your add-on, either as an attachment or a link to a downloadable package. * For updates, including the source code of the previously approved version or a diff is also helpful. You can read our policies regarding source code handling here: 2) Your add-on uses the 'eval' function to parse JSON strings. This can be a security problem and we normally don't allow it. Please read for more information about safer alternatives. 3) Your add-on uses the 'eval' function unnecessarily, which is something we normally don't accept. There are many reasons *not* to use 'eval', and also simple alternatives to using it. You can read more about it here: 4) Your add-on creates DOM nodes from HTML strings containing unsanitized data, by assigning to innerHTML or through similar means. Aside from being inefficient, this is a major security risk. For more information, see (All of the above is already marked by the validator as warnings. I stopped at this point; there might be more issues) Please fix them and submit again. Thank you. This version of your add-on has been disabled. You may re-request review by addressing the editor's comments and uploading a new version. To learn more about the review process, please visit If you have any questions or comments on this review, please reply to this email or join #amo-editors on

An underlying principle of Chickenfoot is to empower an end-user to be able to write a script, which we would eval(), and that script could modify whatever the user wanted. Clearly, our goals flew in the face of the security model that extension reviewers at Mozilla are trying to maintain. The thought of trying to clean things up and then convince a reviewer that what we were doing was legitimate seemed overwhelming. (Also, the code had been bastardized by graduate students over the years, so the thought of me trying to decipher it after seven years of writing JavaScript in an industry setting was equally overwhelming.)

(This experience is what engendered my (arguably ill-advised) quip to Mike Shaver during my first week at Facebook: "I used to like Firefox." I didn't know that, prior to Facebook, Mike had been the VP of Engineering at Mozilla, but I'm pretty sure that everyone within earshot did. Awk-ward. I think we spent the next hour or two complaining about calendaring standards and timezones. We're friends now.)

Given the uphill battle of getting Chickenfoot into the Add-ons site coupled with the general need for a full-on rewrite, people sometimes ask: when are we going to port Chickenfoot to Chrome? To be honest, I am not sure whether that's possible. For starters, Chickenfoot leverages Thread.sleep() from XPCOM so that we can do a busy-wait to suspend JavaScript execution while pages are loading, which enables end-user programmers to write linear code. (I think we would have to run a JavaScript interpreter written in JavaScript to get around this, which is doable, albeit a bit crazy.) Further, for security reasons (or maybe for forward/backward-compatibility reasons), the APIs available to browser extensions are historically more restricted in Chrome than they are in Firefox. (Last I checked, Mozilla would not allow you to declare your extension compatible with all future versions of Firefox, so you had to specify a maxVersion and update your extension with every new Firefox release, which drove me insane.) In Firefox, the entire browser is scriptable, so if you can get a reference to any part of the Firefox UI in JavaScript, you can basically do whatever you want with it. This has not been my experience with Chrome. (On the bright side, I have never seen an instance where a Chrome user has lost half of his screen real-estate to browser toolbars, which I have certainly seen in both Firefox and more notably, Internet Explorer.)

It actually breaks my heart when I get an email from an end-user programmer who asks for a new version of Chickenfoot. Unlike a full-fledged programmer, most of these folks don't have the tools or knowledge in order to build an alternative solution. Some of them continue to run Firefox 2.0 or 3.0 just so the workflow they created around Chickenfoot still works. I would love to have a clean Chickenfoot codebase from which I could pop out an up-to-date extension, a piece of software that leverages everything I have learned about development over the past decade, but I don't have the cycles.

What's next?

At Facebook, I am extremely excited about the work that we're doing on Buck, and on mobile in general. We are consistently making Android developers' lives better, and we are frequently exporting these improvements to the community. I expect to continue working on Buck until we run out of ideas for how we can make developers more efficient, or at least until we have enough support for Buck in place that I feel comfortable focusing on something else. I should probably also mention that we're most definitely hiring at Facebook, so if you're also interested in working on a high-quality, open source build tool, then please drop me a line.

Saturday, May 18, 2013

Chromebook Pixel gives me an excuse to fork JSNES

For a long time, I have been intrigued by NES emulators. I was extremely excited when Ben Firshman released an NES emulator in JavaScript (JSNES) over three years ago. At the time, I noted that JSNES ran at almost 60fps in Chrome, but barely trickled along in Firefox. It's pretty shocking to see that that is still the case today: in Firefox 21.0 on Ubuntu, I am seeing at most 2fps while sitting idle on the title screen for Dr. Mario. That's pretty sad. (It turns out I was getting 1fps because I had Firebug enabled. Maybe that's why my perception of Firefox has diminished over time. Someone at Mozilla should look into that...) This is the only browser benchmark I care about these days.

When the Gamepad API was first announced for Chrome, I tried to get my USB NES RetroPort controllers to work, but Chrome did not seem to recognize them. I made a mental note to check back later, assuming the API would eventually be more polished. Fast-forward to this week where I was fortunate enough to attend Google I/O and score a Chromebook Pixel. It seemed like it was time to give my controllers another try.

Last night, I plugged a RetroPort into the Pixel and visited the Gamepad API test page, and it worked! Obviously the next thing I had to do was wire this up to JSNES, so that was the first thing I did when I woke up this morning. I now have my own fork of the JSNES project where I added support for the RetroPort controllers as well as loading local ROMs from disk. As I admit in my, there are already outstanding pull requests for these types of things, but I wanted to have the fun of doing it myself (and an excuse to poke around the JSNES code).

Finally, the one outstanding feature I hoped to add was loading ROMs from Dropbox or GDrive using pure JavaScript. Neither product appears to have a simple JavaScript API that will give you access to file data like the W3C File API does. Perhaps I'll host my fork of JSNES if I can ever add such a feature...

P.S. I should admit that one does not need a Pixel to do these types of things. However, having a new piece of hardware and APIs that have been around long enough that you expect them to be stable is certainly a motivating factor. It's nice to have a project that doesn't involve any yak-shaving, such as figuring out how to install a version of Chrome from the Beta channel!