From PHP to Gleam: A Startup's 3-Week Rewrite Success Story

software development

A startup successfully rewrote its entire PHP backend to Gleam in just three weeks, achieving a robust, production-ready system with zero issues. This article details the motivation, challenges, and benefits of migrating to Gleam, highlighting its advantages for concurrent, functional programming and streamlined deployment.

Our startup, Numenon, is now officially running on Gleam, with our new codebase live on production servers, completely free of PHP. This transition fills us with both excitement and a touch of apprehension.

Numenon is an ambitious knowledge base management system currently in its early stages. Our first closed beta release in May utilized PHP and Laravel for the backend, and Svelte for the frontend. This raises several key questions: Why the rewrite? Why Gleam? Why now? Was it successful? And was it challenging?

What is Gleam?

Gleam is a general-purpose, concurrent, functional, high-level programming language that compiles to either Erlang or JavaScript. It's a statically-typed language operating on Erlang's BEAM virtual machine and features its own type-safe implementation of OTP, Erlang's actor framework.

Why Gleam?

My initial encounter with Gleam three years ago was transformative. It immediately struck me as the ideal language, perfectly aligning with my programming philosophy – small, functional, and statically typed, built exclusively on data and functions. The thoughtful design decisions made during Gleam's development, spearheaded by its creator Louis, have consistently impressed me.

I felt a personal imperative to explore new technologies. For years, I had sought a language that resonated with my programming style, having used PHP, JavaScript, Python, Java, Go, and Elixir. While Go was the closest I came to liking, it still fell short of my ideal. Gleam and Go share some notable similarities: both are compact, simple, statically typed, non-object-oriented, and treat errors as values. They also promote a concise coding style within teams, though their similarities mostly end there.

Furthermore, I felt compelled to support the Gleam creator and contributors for their outstanding work in delivering such an impressive language. I aimed to be an early adopter, demonstrating my gratitude through action by trusting their vision and showcasing another live Gleam codebase to the world.

Why Did We Rewrite and Why Now?

Gleam has been production-ready for over 18 months. Given Numenon's early development stage, a rewrite was still a viable and reasonable undertaking. The prospect of building Numenon on PHP for another decade was a thought I dreaded, not due to PHP's inherent flaws, but because I personally sought a fresh alternative.

As an experienced developer who has navigated numerous rewrites, my usual advice is to avoid them. However, in this specific case, the risks were significantly minimized by two factors. Firstly, the rewrite began as an experiment, never initially intended to replace the existing code. Its success was so overwhelming that proceeding with it became a clear choice. Secondly, the transition to Gleam inherently enhanced the robustness of our code, with immediate and visible gains in productivity.

Three Weeks of Gleam Coding

The entire rewrite was completed in just three weeks, despite my having no prior Gleam experience. The first two days were particularly challenging as I grappled with the use keyword in conjunction with the result module.

The instructional videos by Isaac Harris-Holt were immensely helpful, as was consulting the "Questions" discussions within Gleam's Discord community.

The remainder of the first week was dedicated to ensuring the Gleam ecosystem could support all our requirements. It did. Crucially, while not all necessary libraries were available natively in Gleam, its compilation to Erlang allowed us to leverage existing Erlang or Elixir libraries, a strategy we employed for tasks like sending emails via SMTP.

Once comfortable with the syntax, I developed my development tooling, again with assistance from the Gleam Discord community. The next step involved mapping web server concepts (routes, controllers, middleware) from PHP to Gleam, followed by the rest of the codebase.

Surprisingly, this mapping was straightforward. A significant factor was that my PHP code was already structured in a style conducive to Gleam conversion. I primarily used static functions and maintained maximum type strictness. Classes served mainly for namespacing functions or as data-holding objects, a practice that might well frustrate a traditional PHP developer.

Because Gleam is statically typed, all incoming and outgoing data necessitates explicit decoding and encoding. In our case, this involved converting data between Postgres and Records, and between JSON requests and Records. This was the most time-consuming aspect but also a profoundly valuable part of the rewrite. While my PHP code utilized generics via static analysis for type enforcement, it simply cannot rival a natively statically typed language. Gleam's decode module is an elegantly designed tool, and with the language server's assistance, managing the decoding and encoding of all data types became manageable.

Deployment

What started as an experiment had now become our reality: a codebase entirely free of PHP, consisting solely of Gleam and Svelte. Finalizing the deployment process took just one day.

I opted for a simplified deployment approach, foregoing the Gleam website's official guides in favor of a concise 5-line bash script. This script executes tests, bundles JavaScript, builds the Erlang shipment, uses rsync to deploy it to the server, and restarts the service. The simplicity of this setup is immensely satisfying.

Production

We are now one month into production with zero reported issues. While we lack sufficient traffic to draw meaningful conclusions about performance, the service operates reliably, and our "cron jobs" and queues, now running within the BEAM VM, function flawlessly. It's important to note that performance was not the primary driver for this rewrite.

General Notes and Remarks

Maintaining a clean and organized codebase significantly eased the rewriting process, validating the robust design of our original PHP architecture.

The inclusion of Option, Result, and use keywords in Gleam makes program flow natural and highly readable.

We replaced Laravel queues with the m25 Gleam package. This simplified our infrastructure and streamlined local development.

The only missing library I encountered was a straightforward, typed query builder. We frequently use dynamic queries and consequently had to develop our own. While not perfect, it serves our current needs, and we may release it publicly in the future.

Despite Gleam being a compact language, its ecosystem offers substantial depth for those willing to explore. On the backend, OTP is perfectly suited for concurrent, distributed applications. For the frontend, Lustre provides a pragmatic, Elm-like framework featuring unique concepts for components and their execution.

Gleam is a truly remarkable language. I highly recommend giving it a try.