Credit & Thanks to Claire Webster/@clairikine

Elm + Rails + Webpack + Heroku

So! I’ve been building a side project in Elm. It’s been really fun. Elm is the first statically typed language I’ve worked with and the first functional language I’ve built anything significant in since college, and it’s stretching me in good ways.

Last week, I got my project (about books and Twitter) to the point I was ready to put it online using Heroku. It was straightforward to get the Rails backend1 and Elm frontend set up locally (thanks to Abe Voelker’s helpful blog post), but I ran into a few additional snags getting it hosted.

Here’s what I learned, in the hope it will be useful to others:


Heroku’s built-in buildpacks (Settings > Buildpacks) are all you need, but the order of the buildpacks matters. The Node.js buildpack (which handles all the npm work required for webpack, which in turns turns Elm into browser-compatible Javascript) needs to be first, the Ruby buildpack second.

When mine were in the wrong order, Heroku expected that the web dyno would run npm start, which doesn’t work (no such npm task being defined).

Properly set up, my dynos (Resources > Free Dynos) look like this — yours should probably look similar:

Precompiling Elm

Locally, Webpack will compile your Elm files as needed. That’s not going to work on Heroku, though — they have to be compiled when the slug is built (that is, when Heroku packages up your app).

This may all change if/when Webpack is supported in Rails 5.1, but for now there’s a little bit of work to do.

Fortunately, it’s just a little bit of work, following Jan Dudek’s example: add a Rake task that uses Webpack to compile Elm, and hook it into the assets:precompile task.

namespace :webpack do
  desc 'compile assets using webpack'
  task :compile do
    sh '`npm bin`/webpack --config $PATH_TO_YOUR_WEBPACK_CONFIG_JS_FILE'

Rake::Task['assets:precompile'].enhance ['webpack:compile']

Heroku is Case-Sensitive

One final gotcha for those of us developing on Macs: Heroku is case-sensitive, OS X is not.

I extracted some view code into a views/ directory — creating, for instance, a module Views.Home that lived in views/Home.elm. Locally it worked fine and everything looked right, but on Heroku it failed with this error:

 ERROR in ./webpack/elm/Main.elm
       Module build failed: Error: Compiler process exited with error Compilation failed
       I cannot find module 'Views.Home'.
       Module 'Main' is trying to import it.
       Potential problems could be:
       * Misspelled the module name
       * Need to add a source directory or new dependency to elm-package.json

On Heroku, it expected to find the file at Views/Home.elm. Keep that in mind when setting up your directory structure/namespaces.

That’s it!

Other than these relatively small issues, everything’s worked smoothly and my app is up and running (for me, at least: it’s way too ugly to share at the moment 😝). Hopefully this may save someone the few hours I spent figuring this stuff out.

Have a great 2017!

  1. The advantage of Rails is that I know it; in two hours I had all the CRUD endpoints I needed built and could focus on learning Elm. Perhaps someday I’ll port the backend to, say, Elixir, but only after I’ve got the frontend down.

How We Distributed a Personalized iOS Curriculum to Students Across the U.S.

At eSpark Learning, we’re building a platform for personalized education for K-8 students in over 120 public school districts using iPads. There are incredible challenges in understanding students’ learning needs and ability levels and how they learn from and respond to different educational materials; there’s also a huge challenge in simply getting the materials to the students.

Our iPad curriculum is built from third-party iOS apps, videos, and web content — no one company could produce nearly as much amazing, creative content as the iOS developer community has1. As it’s turned out, though, there’s a huge challenge to distributing a constantly-changing set of applications to iPads clustered throughout the country; solving this challenge was my primary responsibility for my first two years.

As the inaugural post of the eSpark engineering team’s engineering blog, I’ve written a post on how we solved that app management problem, allowing us to scale up from clicking buttons in iTunes in one school to managing millions of app installations across the country.

Check it out!

  1. I also love the virtuous cycle this creates: the teachers on staff at eSpark pick great iOS apps, schools buy those apps, the app developers thus rewarded can create even more great educational content.

Under the Sunset

I picked up Under the Sunset after seeing it mentioned in a Slate article about Bram Stoker. For such a short book — it couldn’t have taken me more than a few hours —, Stoker’s first work was a slog.

This collection of Victorian children’s stories is set in a fantasy world, one nominally populated by humans just like us (so asserts the introduction). It’s actually just a gathering place for beings of either simple virtue or plain wickedness: kings think only of the good of their people, brave and beautiful princes stand ready to sacrifice themselves to save their land, everyone weeps for the sadness of some misfortune, good wins out before there’s even time to build some suspense.

I suppose it’s fine that there’s no nuance: this is a children’s book. What I find harder to bear is that there’s no humor. Everyone is so deathly earnest about everything. All stories are filled with this weirdly urgent Manichaean division: the good and innocent, so beautiful they moves everyone to tears, and the hard-hearted guilty, who either meet the swift death or (if they are lucky) are saved by an overwhelming sense of remorse and repentance. Stoker’s writing leaves no space for humor, let alone nuance. You emerge from this book coated in treacly virtue.

Read on →

A Dream After Discussing Kafka and Borges and Skipping an Awesome Foundation Meeting

There was a booth at the end of the subway station, standing between the staircases, the large window in its door covered by a curtain.

I vaguely knew what it was and that I didn’t have the time to get involved, and yet when I saw someone in a mask look out from behind the curtain, I knocked on the wooden door. I wanted to be involved.

The person opened the door, told me a bit about this Awesome Foundation project, and then left me, gratefully and hurriedly, to take over for him. I debated whether or not to just walk away – I was on my way to work and had a lot to do – everyone knew it would happen sooner or later, someone would pick up the line and meet with silence, that’s inevitable, given who people are, but I didn’t want to be that person, didn’t want to be responsible for that expected disappointment, and so I went inside.

Inside the House of 1001 Ruined Identities, there were masks along the shelf above my head, and the bench below was covered in papers. When I picked up the dangling phone, a woman’s voice at the other end of the line told me that she was participating from another booth in New Zealand. She asked if I’d seen the article about maintenance from the Times yet, and so I started looking at the newspaper clippings and sheets of printer paper, filled with arrangements of numbers whose meanings I expected to understand as time went on.

It was the second Times article that I found, something about migration and border patrols and yet also about us in these booths. She said that was it. Before I started to read it I remarked with with curiosity and a slight alarm that I was going to get hungry and that I ought to do something about that. I knew that was a futile attempt to be excused, but I had to try (and I was hungry). I didn’t expect anyone to relieve me anytime soon, and I wasn’t sure how I was going to smooth this over at work – not that I wasn’t terribly worried. I work at a startup, after all.

* fin *

Dido >:O

A Romp through the early books of the Aeneid

And the hall falls hushed as Dido lifts a prayer:
“Jupiter, you, they say, are the gods who grants
the laws of host and guest. May this day be one
of joy for Tyrians here and exiles come from Troy,
a day our sons will long remember. Bacchus,
giver of bliss, and Juno, generous Juno,
bless us now. And come, my people, celebrate
with all the good will this feast that makes us one!”
— Aeneid 1:874-880

With these words, Dido, the queen of Carthage in Libya, both welcomes Aeneas and his fellow Trojan War refugees to her city and makes the first mortal prayer1 in Virgil’s fan-fiction sequel to the Iliad epic Roman foundation myth.

Piety #1

I was surprised Virgil chose to give Dido the first prayer to the gods.

Read on →

Some Things Don’t Change [Updated]

People are accustomed to believe, and have been encouraged in the belief by some who aspire to the character of philosophers, that their feelings, on subjects of this nature*, are better than reasons, and render reasons unnecessary.

J.S. Mill, On Liberty, 1869

I don’t know whether to cry1 or to laugh2, but either way, some problems are not new, and probably not going away.

* 3 (update 12/22)

  1. 144 years later and people still think their feelings alone justify passing laws?

  2. Try as they have, people who think like this clearly haven’t been able to stop progress.

  3. “Some rules of conduct, therefore, must be imposed, by law in the first place, and by opinion on many things which are not fit subjects for the operation of law. What these rules should be, is the principal question in human affairs…”

The Spanish Civil War

As an experiment, I’m going to try writing quick book summaries of the books I read. One session, about 10 minutes. Revising allowed later. Go!

Read: September/October 2012

Until just a few years ago, I knew very little about Spain’s troubles in the 20th century. Actually, that’s too weak: I didn’t even know that I knew very little about Spain’s troubles. I barely knew there were troubles at all. There’d been a dictatorship, of course, which (shockingly to me) lasted until 1977; there’d also been a civil war, which I, err, learned about from Pan’s Labyrinth. Beyond that, I held a (perhaps understandable) American view of Europe as a simple collection of ethnically-based nation-states: Spain is filled with Spaniards, Germany is a uniform collection of Germans, and so on1.

This state of affairs lasted until someone very close to me, who had studied in the Basque Country, told me about brutal repression of the Basques under Franco. In Europe, I made friends early on with a great group of Catalans, whose attitudes toward toward el Centro (Madrid), Spain as a country, and toward Spanish history were (and are) endlessly fascinating. It’s possible these sympathetic early exposures to people from the regions gave me a bit of bias in Iberian matters, but after reading this history, it’s hard to imagine any other conclusion with regard to the war than this:

Everyone involved gets an F

Read on →

A Leap Into Something New

Tonight I wrote my first Leap Motion app, which was also my first Node.js app. If that hadn’t been enough to finally kick off this blog, nothing would be.

For those not familiar with Leap Motion, it’s a small controller design to capture 3D movements — a bit like a Kinect, but designed from the start to be open for developers like me and many others to create with. And create people have — check out the video at for some great examples.

My own little contribution, LeapNoise, is a simple app that lets you control iTunes with gestures:

  • Move forward and backward in your playlist by swiping right and left
  • Raise and lower the volume with vertical movements
  • Pause and play by pressing forward (like you’re hitting a big, invisible button)

I put together the entire app in about two hours, from starting the documentation through recording the demo — I was impressed at how quickly I was able to get up and running with the Javascript library.

At first glance, the SDK seems well designed; I’m looking forward to digging into it more. The controller is a neat piece of technology; there are still many rough edges (seemingly phantom events, control jitters affecting apps in the Airspace store), but those are problems that should be solvable as the software and the community evolve.

I’m excited to continue playing with the Leap Motion, and will post more from time to time on my experiences.

Check out the demo in all its late-night glory:

And, of course, the source code for LeapNoise is up on Github.

That’s it for tonight! See you next time.