Here at Pivotal Tracker, we have a large product with many pieces in many different tech stacks—some are in Rails RJS, some are plain jQuery, a lot is Backbone, and some is React. We experimented with Redux for a while, and though the architecture was good, it added too much complexity, especially when we tried to integrate it with the existing Backbone code.
Then we tried Elm. At first there was a lot of doubt, suspicion and fear, but after championing it through a few trial runs, it proved itself in the fullest way possible. We received approval to build our new dashboard in Elm. Although we went through some growing pains with Elm at first, it went very well overall, and has recently been released.
This section will likely sound like a broken record if you’ve read any other accounts of companies using Elm. At first the new strange syntax and functional paradigm intimidated some developers, but most of us caught on in less than two days. Learning to think in “FP” can be challenging, but Elm helps ease into it.
Even better though, working with Elm was downright enjoyable. The tools make it so easy and frictionless to develop, and the compiler makes refactoring a cinch. We’ve refactored the entire file system in a day with no regressions, something that would’ve been nearly impossible in our other code bases.
To sum it up, developers were literally bidding on the stories that involved Elm work during our morning stand-ups.
Our end result has been working very well. We’ve had zero run-time failures, the filesize is ridiculously small, and it runs faster than anything else in our code base. We’ve also had fewer bugs, largely because Elm’s type system forces you to model your domain more carefully.
To sum it up, our manager has mandated that all new code be written in Elm.
Despite the positive experience, we still faced challenges. Learning how to organize a large app took a while to get right—and it can still be somewhat confusing to newcomers—but we’ve arrived at a place we’re happy with. Integrating with our Rails app and the build/CI cycle was tricky. We ultimately found a mix of react-on-rails and webpack to allow for a “hot reloading” dev environment and compiling static assets for Rail’s asset pipeline to use. We used package.json scripts to tie it all together, including our Elm tests.
A particular hurdle for us at Pivotal was changing our mindset from the traditional “TDD” approach to a “Types Driven Development” approach, and learning how to write code that made tests unnecessary, while still getting sufficient coverage for our business logic.
In the end, we came up with patterns that work very well for us.
Elm 0.18 added a “time-traveling debugger”—a tool that has quickly become indispensable. In prior versions, we were limited to instrumenting our code with log statements, requiring cleanup and making guesses about code paths. The new debugger is always active in development builds, meaning we can open it after discovering an error state and take a snapshot for deeper investigation. Another bonus: the ability to rewind to before your lazy-load messages come back to examine loading states without mucking around in dev tools’ throttling settings.
Additionally, a challenge I imagine most developers dread was entirely defanged: IE-exclusive bugs. The debugger’s state table showed the cause immediately: an update message fired by input events was being sent too often. This lead brought us directly to a bug report on MSDN. From replication straight to identification, with no special instrumentation required! (Just a bit of additional logic worked around the defect.)
Elm contributor Richard Feldman once presented Elm by saying, “Make the back-end team jealous.” After our experiences using Elm, we can confirm that sentiment.