So you’ve mastered React, Redux, ES6, etc and you find yourself in a better position than a couple of years ago; now you’ve got a more maintainable source code with unidirectional data flow, fast DOM manipulation with Virtual DOM and other nice perks such as (HMR) Hot Module Reload. Not bad! But it’s never enough in the world of software development, is it? We still have to suffer from:
- Javascript fatigue: You need at least 10 different libraries to get started on a react project. And those libraries change over time. Our typical project has around 20–40 dependencies.
- A language unfit for purpose: Javascript lets you do things that you shouldn’t (99% of the time), like mutating object values. I can’t remember where I read this phrase but it’s along the lines of “If a language lets you do a particular thing then someone is bound to do it.” You might use libraries such as immutable.js or seamless-immutable to achieve immutability but you can’t be sure that your junior colleague will or knows when to use them.
At Wraptime we’ve been mitigating some of those pains by using boilerplates for our web and React Native projects. It has helped to get us to just get started on project without spending too much time setting up the development environment using the latest libraries. We also keep our code as functional as possible using Ramda.js to make our code concise.
React is becoming so prevalent now that it has even been labelled the new jQuery. But after sometime you feel like we’re trying to bend Javascript into a language that it’s not: a functional immutable language, 2 concepts that the React ecosystem draws upon. So we thought why don’t we actually use a functional immutable language?
Elm
Elm is probably the only strongly-typed functional language I’ve seen out there that feels like it’s actually going to be mainstream in the foreseeable future, with focus on practicality over purity and typical academic pedantic-ness that comes with languages in that category such as Haskell. To summarise, Elm and its ecosystem is awesome because:
- You don’t need gazillions of libraries to get started. Install the Elm CLI and start coding.
- Elm Architecture, which Redux is inspired by. It allows you to write modular and highly composable components with unidirectional data flow without having to learn and use another library (e.g. combineReducer, createStore, etc in Redux). It works as a consequence of the language itself.
- The language and syntax: Everything is immutable. Functions are curried by default. Easily model your problem using types and type aliases. And not saying compiled languages are always better than interpreted ones, but being able to have full confidence that your code runs exactly how it needs to after it compiles is pretty neat. It’s a dream to maintain.
I’m not going to write a whole tutorial on how to start writing Elm yet, but a few tips if you want to give it a try:
- Go to the Elm Slack channel: There’s a lively community that’s very helpful to beginners and everyone else, and being a strongly typed functional language, full of seasoned developers. Ask questions and in my experience someone will help within 5 minutes.
- Elm can be run and compiles using the Elm CLI on its own, but for real-world application development you’d want to use a setup like this: https://github.com/moarwick/elm-webpack-starter, which includes Hot Reloading and a CSS processor among others.
The obstacles (from the perspective of a javascript developer) of Elm that I’ve encountered so far:
- Nothing can be left unhandled. Trying to parse a string as a number? What if it fails? Elm forces you to handle every possible outcome. Of course it’s a huge advantage to prevent bugs, but it’d mean it takes longer to develop smaller apps that would otherwise be very quick to prototype in JS. So, good for big projects, but probably not the best tool for smaller projects or for prototyping.
- No global app context. Have a logout button nested 4 components deep into the application? With redux you can just wire it up to call an action. Not in Elm. All the ancestors need to be able to handle the logout action and “bubble” it up.
- Writing side effects can be painful: Need to run a setTimeout timer? Need to cancel it before it triggers? Some trivial things in JS are not so trivial in Elm. This is understandable since side effects can make your code a debugging nightmare, but again sometimes it can be a culture shock to see the difference between the trivial JS implementation compared to Elm’s.
- Type safety: Again it’s nice to write type-safe applications but it can be hard to get your head around and explain to others in some cases. For example, when composing components, you need to “map” certain types of the child into its parent’s type:
view = Html.App.map ChildAction (Child.view model)
Conclusion
To summarise, Elm is awesome and is most suitable to write medium to large scale applications where reliability and maintainability are main concerns.
In a galaxy far far away: Elm currently compiles to Javascript but some time in the future it might be possible to compile it to WebAssembly, which means near-native performance. Does it mean we’re going to be able to let go of JS (and it’s derivatives like TypeScript) and tailor a language that will better the lives of front-end developers?
Future Plans
I’m in the process of writing a book called “Elm for React Developers”. I’d really like to see Elm adopted by more people. But to bring Elm to the mainstream, you need to bring the mainstream to Elm. The book is going to go through Elm and functional programming concepts from the perspective of a React developer, with less emphasis on theoretical correctness and more on getting the point across.