1 month ago

Transitioning Tuist Cloud from Ruby to Elixir

We’ve recently started moving Tuist Cloud’s current implementation from Ruby to Elixir. The TL;DR version of the motivation is that Ruby is not the most suitable runtime for apps that are IO-heavy—something that might change in the future. As part of the decision-making process, we also evaluated Swift, which powers the Tuist CLI, and some organizations are using it server-side. Ultimately, we decided on Elixir for various reasons that I’d like to share in this blog post in order of importance.

I don’t like the debates around a technology’s ability to scale because, at the end of the day, any technology can scale if you throw enough money at the problem. However, since we are a small bootstrapped company, we can’t afford to throw money at a problem—we need low-cost, easy scaling of not just the production servers but also development, and Elixir and the VM (BEAM) are uniquely positioned there. Thanks to the virtual machine and the functional nature of the language, you can scale by increasing cores and memory instead of horizontally adding more servers, which comes with its part of complexity.

Someone at this point might wonder: Isn’t this easy scaling also achievable in JavaScript with serverless JavaScript runtimes? Yes and no. The provider of the serverless environments supposedly abstracts that away from you, very likely with a proprietary runtime that looks like Node but it’s not Node. But that, at the end of the day, is a loss-leading commercial strategy for you to eventually pay more than what you’d pay if you had it as a long-running process in a server. And that goes without talking about the pain points of having inconsistent runtimes across environments. A JavaScript/TypeScript developer would tell you WinterCG is here to fix all these fragmentations caused by cloud providers, but that’s just a flat illusion, like many things in the ecosystem: Serverless, Lambdas, Functions, JamStack. They are constantly trying to reinvent everything to try to sell services with significantly more costs than value. So as you can imagine, JavaScript was a no-go for us.

Swift’s production servers can scale easily and cheaply. However, development might not because of Apple’s continuous strong focus on their platforms. The ecosystem lacks many tools and workflows that can play a significant difference in productivity. One of the workflows, for instance, that we find extremely valuable these days is being able to open a remote console with the runtime and run code in it. Obviously, this is a workflow that’s not a good idea long-term, but in this current phase, it’s life-changing.

We had a bit of a moment of thinking: should we bet on Swift and help move the ecosystem forward? However, we don’t have the financial luxury of making this investment. We were afraid the decision would lead us to rabbit holes of Swift issues in Linux environments that would distract us from shipping a great product. We are not entirely opposed to using Swift on the server. We just think that right now is not the best time for it. We remain excited about what the future holds for Swift on Linux and Server.

It was also important for us to have access to an ecosystem of community packages to help us with various problems and needs we’d face. Swift was way behind here compared to ecosystems like Ruby, NodeJS, Rust, or Go, which have plenty of tools for building server apps that run on Linux servers. From that list, we also discarded Rust and Go because we’d lack hot-reloading, which is a small issue at a small scale but can become significant when reached a certain scale. We deem it important for our productivity to change code and see it automatically hot-reloaded in the runtime. Once again, the combination of functional programming in Elixir plus Erlang’s VM capabilities make that possible. It’s insanely fast.

And last, and potentially very important in the future, is having access to primitives that will allow us to build real-time features around collaboration, without having to introduce additional pieces of infrastructure. Elixir makes that extremely easy. So easy that even platforms like Supabase offer that as a service for other ecosystems. We can see some Tuist Cloud features being real-time, like seeing builds test results data flowing into a dashboard and getting automatically refreshed.

We believe this is the best decision for the project, and we can’t wait to start investing in a unified dashboard for Xcode teams.

About Pedro Piñera

I created XcodeProj and Tuist, and co-founded Tuist Cloud. My work is trusted by companies like Adidas, American Express, and Etsy. I enjoy building delightful tools for developers and open-source communities.