ReasonML first impressions

In the broadband team at uSwitch, we’re constantly looking to make comparison a quick and simple experience for our customers. That means investigating new tools, approaches and technologies to improve the user experience.

The key area we keep looking into is making our site faster across a wide range of different devices and connections.

One technology that recently caught our attention is ReasonML. It promises a good, but not overly complex, static type system combined with a very solid set of functional tools which should help us write code with less bugs, make refactoring easier, and create better documentation. The compiled output it creates appears to be optimised, production-ready, small-size, readable JavaScript code.

Overall, it has been a great experience with promising results.

What is ReasonML?

ReasonML is an alternate syntax for OCaml that uses Bucklescript compiler backend to output JS. The developers claim it comes with a set of tools focused on great Developer Experience to write type-safe, functional-style programs and that the resulting code achieves pretty quick performance and small bundle sizes.

We’ve been evaluating ReasonML as a candidate to get static typing on the frontend. The main questions we wanted to answer were:

  • What are the features that this new language / platform will provide us?
  • How difficult is to integrate in our workflow?
  • What does the ecosystem look like?

 ReasonML features

You can expect most OCaml features when writing a ReasonML program: concise syntax, type inference and functional goodies like currying and pattern matching. On top of that, any ReasonML module gets exported as CommonJS so you can use your usual bundler and publish or consume code from npm in the way you normally would.

ReasonML’s type system is sound, meaning that the type system provides semantics to ensure that our code is not going to run into an error at runtime. This is a more powerful type system than Typescript, as a comparison, but it is still pragmatic enough to keep it simple and help you get things done.

Integration with our workflow

ReasonML compiler will output any .re file under the source folder that we specify to the same path under a lib/js/src directory. We can either require those files directly as any other CommonJS module, or we can bundle them together with webpack or another similar tool.

ReasonML compiling to CommonJS modules means that we can replace our codebase on a module-by-module basis and migrate in batches. Calling ReasonML functions from the outside world is just requiring the module and calling the function from JS.

Using JS functions (or any runtime value from the environment) from ReasonML requires a bit more work. Bucklescript provides an external declaration mechanism to do exactly that. We found it to be fairly simple to use; you can reference globals, methods and even interpolate raw output so the compiler knows what to do when translating a specific token to JS. The recommended approach in the official docs is surprisingly pragmatic: When translating your JS codebase, start with getting the syntax right, then add the minimum amount of bindings to get it to compile and finally, get the types right.

In general, we found the community has a very hands-on approach to solving the problems exposed to them, which feels very refreshing. They tend not to drift towards theory and abstraction but, rather, try to get the language to be used in real world scenarios.

Investigating the ecosystem also gave us an idea on how healthy the community is, how fast the project advances and the current lifecycle the platform is in.

Area Status
Libraries Complete OCaml standard library, few ports in alpha/beta stage from other libraries
Build System Bucklescript build tools, webpack bs-loader
Package Management npm
Stack Overflow Nine questions
Error messages Elm style, very friendly
Editor Support Atom, VIM, Emacs, VSCode
Support Channels Discord ReasonML

We found that the ports from JS libraries seem a bit lacking at the moment, so prepare to write quite a few bindings to interact with your current code base. On the other hand, the build system, error messages and package management are superb.

We thought the editor support is very good. It makes use of OCaml-merlin, so you can expect to have nice overlay type hints, code completion, exhaustive pattern matching and many more things right in your editor.

Stack Overflow is just empty, but the Discord community is quite active and friendly, with very well-respected and reputable members of the JS and React communities regularly participating.

Beyond ReasonML documentation

ReasonML documentation does a good job explaining the syntax and the basic features, but it lacks an overview on how the platform works as a whole. For anything beyond the simple examples, you’ll end up searching in Google or asking in Discord.

We found the sources of information to be fragmented. To solve most of our problems we had to use a combination of different documents: the official ReasonML docs for syntax and tooling, the Bucklescript manual for JS interops (externals, default modules and some syntax not covered by ReasonML docs) and the OCaml Manual for anything not covered by the previous two sources.

This is not obvious when reading the ReasonML docs for the first time and can be a bit frustrating to realise. This was, however, supplemented with great tools like ReasonML Tools and Reasonably Typed that helped us to move from OCaml syntax to ReasonML and back, and to convert Flow type declarations to ReasonML.

You should expect to use those tools heavily in combination with OCaml tutorials when creating your first programs.

ReasonML minimal config: A tool to iterate over new concepts

After understanding the pros and cons of the platform, we created a minimal build configuration to be able to get a faster development cycle. Failing fast is important when learning a new language, and we don’t want to spend more time compiling than coding.

The project we created consists of a small environment to play with the language, which you can find here:

https://github.com/rlucha/reasonml-minimal-config

You’ll need to install the ReasonML platform before the tool. To do so, just follow the steps from the official Docs.

https://facebook.github.io/reason/jsWorkflow.html

This is what you can expect to find:

  • Small static http server using Browsersync
  • Bundling with webpack, including stats.json to check with any bundle analyzer
  • Source code files watching and reloading of both the bundle and the http server
  • Production ready minified file with dead code elimination

Conclusion

We were surprised by how easy it was to start getting results, and it looks like potential integration with our current workflow won’t pose many problems. In particular, we were impressed with how good the editor support was.

For now we might be using it in a pet project to gain more knowledge, but we hope to incrementally adopt the technology and get something into production eventually.

Before you consider adopting ReasonML, you need to know that it isn’t without its drawbacks: Learning typed languages might have a steep learning curve, and mixed syntaxes and fragmented source of documentation might slow down the process of adoption. But thanks to the great tooling and active community, we found it easy and quick to get the solutions to any problems we came across.

All in all, assessing ReasonML has been one of the most pleasurable experiences we’ve had with languages that transpile to JS. It’s certainly grabbed our attention, and we hope it’s piqued your interest, too.