We Rewrote Our Startup from PHP to Gleam in 3 Weeks
We are officially running our startup in Gleam! Our freshly written Gleam code is now live on our production servers. Not a single line of PHP. I am excited, and a bit frightened.
Numenon is an ambitious knowledge base management system in its early stages. Our first closed beta release was back in May. Built with PHP and Laravel on the backend and Svelte on the front. I know, I have some questions to answer. Why did we rewrite? Why Gleam? Why now? Is it good? Was it hard?
What is Gleam
Gleam is a general-purpose, concurrent, functional, high-level programming language that compiles to Erlang or JavaScript. Gleam is a statically-typed language that runs on Erlang's virtual machine BEAM. It has its own type-safe implementation of OTP, Erlang's actor framework.
Why Gleam
My first contact with Gleam was 3 years ago. It was love at first sight. The first thing I thought looking at this new language was "This is exactly the language I would create if I was as smart as Louis, the creator." A small, functional, statically typed language. Only data and functions. For sure, there have been hundreds of small decisions taken during the design of Gleam and its ecosystem. And every time I enjoy the result (pun not intended) of those decisions, I get a warm feeling in my heart.
I felt an obligation to myself to try something new. I had been waiting for years to switch to a language that makes sense to me. I've used PHP, Javascript, Python, Java, Go, Elixir and I've never felt that the language was in line with my style of programming. Go was the only one that I really liked, but still, far away from my ideal language. It would be fair to say that Gleam and Go have some similarities. They are both small, simple, statically typed, not object-oriented, with errors as values. They both enable teams to have a concise style of coding. And I think we are done with the similarities.
I also felt the need to support the Gleam creator and contributors because they made it. They have released an amazing language. And I love it. I want to be an early adopter. I want to express my gratitude with actions by trusting them and showing the world that another Gleam codebase is live.
Why did we rewrite and Why Now
Gleam has been ready for production for over a year and a half. Numenon is in its early stages, so the rewrite was still viable and not totally unreasonable. If Numenon goes well, building on PHP for the next decade was a thought that filled me with terror. Not because PHP is bad. It's just that personally, I had enough of it and I was looking for an alternative.
I am an experienced developer who has survived many rewrites. If you ask me if a rewrite is a good idea, 9 out of 10 times the answer out of my mouth is going to be no. In my case the answer could still be negative, but there are 2 points that minimized the risk. Firstly, the rewrite started as an experiment, never meant to actually replace the existing code. It went so well that we had no reason not to go forward with it. And secondly, the switch to Gleam made our code feel more robust. The gains in productivity from switching were already visible.
3 weeks of Gleam coding
The rewrite took only 3 weeks. Mind that I'd never written a single line of Gleam code before that. The first 2 days were really hard. I was trying to figure out the use keyword in combination with the result module. The videos of Isaac Harris-Holt helped a lot! Another thing that helped me was browsing the "Questions" discussions in Gleam's Discord community.
I dedicated the rest of the first week to making sure that the ecosystem could support all of our needs. And it did. Not all needed libraries were available in Gleam and here is the great fact about Gleam compiling to Erlang. We can use libraries from Erlang or Elixir. That's what we did for sending emails with SMTP for example.
Once I had gained familiarity with the syntax, I created my dev tooling with the help of the Gleam Discord community again. Then I mapped the webserver concepts (routes, controllers, middleware) from PHP to Gleam and the last part was to map the rest of the codebase.
Surprisingly, that was really easy. One reason is that my PHP code was already written in a style that was easy to convert to Gleam. I was using only static functions and everything was as typed as possible. Classes were used mainly for namespacing functions or as data-holding objects. My PHP code would make a PHP developer furious.
Because Gleam is statically typed, all the incoming and outgoing data has to be decoded and encoded. In my case, from Postgres to Records and back. And from JSON requests to Records and back. This was the most time-consuming thing, but at the same time, it was a really valuable aspect of this rewrite. Although in PHP the data was already as typed as possible (generics via static analysis), you can't compete with a statically typed language. Gleam's decode module is a beautifully written tool and with the help of the language server, the task of decoding and encoding all the data types was bearable.
Deployment
Something that started as an experiment was now real. No PHP in the codebase. Just Gleam and Svelte. It took me a day's work to finalize the deployment process.
On the Gleam website there are deployment guides which I ignored, in order to go with something as simple as a 5-line bash script. It runs the tests, bundles the javascript, builds the Erlang shipment, rsyncs it to the server and restarts the service. That's it. I am a happy person.
Production
We are one month in production and have zero issues. I can't offer any insights regarding performance because we don't have that much traffic to draw any useful remarks. The service runs reliably, the "cron jobs" and the queues that now run in the BEAM VM just work. I have to mention though that performance was not a factor for this rewrite.
General Notes and Remarks
Having a clean and organized codebase made the rewriting task so much easier. That was a validation that our architecture was well designed in PHP.
Having Option, Result and use in the language made the flow of the program natural and very easy to read.
We've replaced Laravel queues with the m25 Gleam package. This made infrastructure simpler and local development easier.
The only library that I was missing was a very simple typed query builder. We have a lot of dynamic queries and we had to create our own query builder. It's not great but does the job for now. Maybe we are going to release it one day.
Although Gleam is a small language, the ecosystem has so much to offer for those who want to challenge themselves and dive deeper. On the backend side, OTP is ideal for concurrent, distributed applications. On the front-end, Lustre is a more compromising/pragmatic Elm-like framework with some unique ideas around components and how you "run" them.
Gleam is a beautiful language. Go and give it a try.