Rails on OCaml
March 19, 2019
I’ve been programming with Reason/OCaml for over a year now and have come around to the idea that typed functional programming based on the ML-family of programming languages will be the “next big thing” in programming languages. It is in quotes because even though ML has been around for over 40 years, it is yet to find mainstream adoption. But two languages are changing this for the better: Reason and Elm, and thanks to them I hope more of us get to enjoy Typed FP in the future.
How is this applicable to Rails? I think at some point — not in the near future — but somewhere in the next 10 years — we’ll realize that a paradigm shift has occurred in how we build web applications. Rails itself was a major change at the time — instead of J2EE’s XML madness and Java’s anemic type system (which forced complex class hierarchies where, in dynamic languages, simple functions would’ve sufficed), DHH built Rails by reifying PoEAA with “convention over configuration”, and delivered it in a programming aesthetic based on the notion that programming is writing. Systems built on Rails has transacted billions of dollars already — there is no question about its commercial significance. More importantly for us, it has also broadened our taste of how programs could be written.
The next big shift in web development, in my opinion, will affect both these — real-world commerce and programming taste. The internet, and computing in general, is only getting started. We’re not a mature industry, and it is both good and bad. Good because of the immense scope of creative work to be done, bad because software today sucks so badly, and layers of cruft are only accumulating, not simplifying.
Types help commerce because it lets us program with a mind-blowingly high degree of correctness than we’re used to. There are two kinds of correctness — the immediate-feedback correctness, and the long-tail correctness. Unfortunately we tend to think of the latter when we think of correctness — bugs that get deployed to production and comes back to bite us. We can get rid of it to a large extent with a good enough process — tests, code reviews, QA, CI, operational monitoring, and the like. Types help here, but as a maker I don’t care about it deeply enough — fewer bugs and stable programs is sort of disconnected from my day-to-day existence, and let the bean counters care about it if they have to.
What I’m more interested in is the immediate-feedback correctness — my experience as a programmer during the long hours I spend in front of the computer. This writing code and trying to run it and things not working and spending hours to come back to rather silly, simple bugs. This knot in the stomach when I work with the complex, critical parts of a system — the hours or weeks of procrastination before working up the courage to get down there and get the damn thing done. I would have brushed off all these as the essential parts of the programming experience, but thankfully I’ve begun to understand the idea of “perfection” in programming that pervades the Typed FP community. There I found a much more pleasant way of programming, and a path to mastery that I’ve been clueless about for a decade or so of being a professional programmer.
What I’d like to talk about tonight is an obsession of mine that’s been with me since I started programming as a teenager, I think it is an obsession I share with the people in the audience - obsession with the perfect piece of software. The perfect computer program.
The one that does exactly what it should do, no more, no less, every time, with perfect reliability, and forever. The kind of perfection that you can get from mathematical definitions, which software is to a large extent, or from philosophical concepts.
— In search of software perfection. The 2016 Milner Award lecture by Dr. Xavier Leroy, author of OCaml
Typed FP expands our taste in programming because like how Ruby and Rails showed how programming is writing, Typed FP shows how programming is mathematics. Not arithmetic, algebra, calculus, or any of the stuff that is conventionally deemed difficult and boring; but the kind of thought programmers themselves care deeply about: composition, abstraction, and correctness.
I realized just how little I knew about software, there was an entire world out there that was unknown to me! What I knew until that moment, all my expertise in a narrow field was just a tip of the iceberg. And this realization removed a barrier I had that prevented me from trying to learn new languages and experimenting with new things. Where previously I would dismiss these things as irrelevant, I suddenly gained interest in things that I never had interest in before. In the past year alone I’ve used Haskell, Clojure, and Rust. I’ve looked at Erlang, Elm and PureScript. I am working my way through SICP and learning Category Theory. I’ve done all that because for the first time in a long time, I am genuinely curious about what these languages/paradigms can teach me! I really don’t remember the last time I was this excited about learning. Genuinely proud of being able to say – “I don’t know everything!” – is incredibly liberating!
Typed programs are also orders of magnitude more efficient1. When we compare two numbers in Ruby, it has to figure out what both their types are, coerce them into Fixnum, Float, or Bignum, and then do the comparison. These are many machine instructions. But when there is a type system, there is no need for costly runtime type checking, and most of your code can translate to almost the exact machine code that needs to be executed. As the scale of the web grows, our MVPs have to handle more traffic and our data centers when run at scale want to consume less power and emit less heat. Types help.
Typed FP improves correctness, gives you better tools for thought, runs fast, consumes less energy, and brings a distinctive aesthetic to programming. But more than everything else: it is so much fun to program in this paradigm.
At Protoship, we build Codegen, a tool for web development teams that converts UI designs made in Sketch into production-ready HTML & CSS based on the box model, flexboxes, grids, design scales, and aims to generate better CSS than what front-end programmers would manually write.
I’m very much in love with this language and want to be able to use it for all of my day-to-day programming. But our web application is currently served by Rails and we use it for database-backed operations like user authentication, reporting, and conventional SaaS functions.
While I love Rails to bits — that magical moment of witnessing a whole avalanche of functionality from just a
rails generate scaffold never fades — I have started missing the clarity, safety, and utter refactorability that OCaml’s types bring to my thought process. While writing Ruby and Rails was like writing poetry — oh so careful, sometimes maddenning and temperamental, but always beautiful — programming in OCaml is more like haphazardly throwing together blocks of Lego — but made of rugged iron and steel — and clarity and precision emerging out of it in no time. If Ruby is poetry, OCaml code is classic prose — no hedges, contortions, or obscurities that undercut the reader’s ability to understand the flow of data and the pathways through which it flows2.
However there are no server-side frameworks today in any of the Typed FP languages that can replace Rails in its ergonomics, community, and how much it has pushed the web forward. But there is scope for one. And when you start from scratch you can build something that has first-class support for streaming, concurrency, isomorphic programming (share the same code on server and client), simpler deployments (single file binaries), typed ORMs, declarative data-management (like GraphQL), alongwith the things that made Rails so great: conventions that distill the essence of the web model, vibrant community with strong opinions, and a large library ecosystem. I think the future belongs to a framework that hits the sweet spot here. It doesn’t exist yet; and until it does, I will be enjoying Rails!
Addendum: Why OCaml, among all other typed functional languages? To borrow from Yaron Minsky, it sits at a sweet spot in the language design space — it is a typed functional language that also permits mutation and side-effects, has a blazing fast compiler, produces native binaries with predictable performance, runs very well on the browser through js-of-ocaml and BuckleScript (opening the possibility of sharing the same codebase on server and client), has a growing community thanks to ReasonML, and is well-placed to produce great wasm output. It was more approachable to me as a beginner than Haskell, has a tinier surface area than Scala, and can even cross-compile into unikernals and mobile devices.
(This post originated from a discussion about the future of Rails in the London Ruby User Group)