I’m quite impressionable when it comes to choosing technologies. I tend to look for alternatives and don’t get stuck with one specific solution. Having said that, I hopped on the Rails bandwagon years ago, when it was just at version 1.3.2. For years, I stayed in a comfortable zone, developing various gems and dozens of applications. A few years ago, I also bought into the hype of node and JS frameworks, using Rails as backends. I used Backbone, then React. In short, after all that, I avoid React for developing complete apps.
Two years ago, I delved into the fascinating world of Elixir. Mesmerized by the tales of distribution, resilience, and high performance. The language is a wonder, it must be said, and its ecosystem echoes Rails, which is great for a Rails developer like me. In some way, it feels like home, but it’s not the same. Anyway, I fully ported Chaskiq.io and learned a lot about the language and its Phoenix framework. My enthusiasm even led me to give a small talk at the Elixir conf, showing how a Rails enthusiast could venture into the Elixir world and achieve the same but scalable things.
I then wrote Rauversion.com, a kind of open-source Soundcloud. I enjoyed diving deep into the development of a series of libraries that didn’t exist in Elixir, like transbank, Oauth adapters for Twitter, Discord, Twitch, Stripe, and some parts of Rails that I missed, namely active_storage and its counterpart active_job, I even named that project ex-rails. I also gave a talk at the Elixir conf the following year. 100% Elixir fan, nothing to argue about.
Rauversion runs in production like clockwork. But a couple of weeks ago, I revisited the project to tweak the file upload system, specifically to upload a batch of audios and process them all together asynchronously. It was then that I realized there was a complexity that starts to overwhelm, especially without the fresh enthusiasm of a newcomer. Having to do archaeology to understand what you wrote a few months ago may indicate that something’s amiss. Not necessarily with the language or the framework, but perhaps my own naiveté with technology.
Meanwhile, a few months ago, I built a couple of Rails applications. My intuition drew me back to Rails because the Hotwire design makes developments very quick and concise. There’s no noise, the kind you only notice when you bounce between technologies. Let’s say, with React, what would take you a day in React can be done in an hour in Hotwire.
Today, I believe that the noise is something that can only be tolerated by a language or technology enthusiast, not by someone who aims to be productive or has to maintain code daily. That’s why I think some things, while seemingly elegant and verbose, are actually a hindrance that adds more complexity than necessary. Revisiting old codes reminds me of this. A complexity that gives stomachaches and makes you want to rewrite everything.
Rewriting is my thing. I enjoy it and recommend undertaking such exercises, because that’s where you learn how to solve from both extremes and realize the good, the bad, and the ugly from both ends.
Thus, I decided to rewrite Rauversion in Ruby on Rails. I’ve done about 90% in two weeks, and I’m still adjusting the remaining 10%.
There’s something refreshing about shedding the unnecessary baggage that functional languages add. Phoenix is a great framework, but there are things I still can’t reconcile. In Rails, the decisions you make are minimal, meaning any developer could understand my software. Everything goes where it should unless you get overly creative. In Phoenix, the design can go any which way, making it hard to understand for those who follow. The libraries I mentioned earlier are no longer my responsibility, which is great. Less work, more focus on what’s important. Relying on a community that’s genuinely committed to developing those specific pieces is gratifying.
The beauty of Elixir is its integrated platform: it has instrumentation, an integrated in-memory key-value DB, and the sockets fly. However, there’s a near-mandatory dependency in Rails, which is Redis. Sockets play a vital role in Rails apps, and Redis is a dependency for them. Also, jobs must run on a separate machine. Seriously speaking, this should also be the case for Phoenix, but you can have it all on one machine naturally. This is a significant loss when reverting to Rails. Essentially, you need more machine power. Another superior feature in Elixir is the Ecto library. When it comes to complex queries, Ecto shines. In Ruby, we have ActiveRecord, which is a more comfortable ORM than Ecto (which isn’t an ORM). But when you have to dive into weird queries, you resort to Arel, poorly documented as it’s kind of a private API, set to change at any moment. We’re warned to use it at our own risk.
Rewrites are a desperate move, a result of dissatisfaction or something going wrong. In my case, it was both. Maybe I should’ve chosen my tech better or stuck with my decision. But well, here we go again. Now I have two versions of Rauversion, one in Phoenix and the other in Rails 😒.
Disclaimer: This isn’t a serious benchmark, just an overview of what I observe on apps without much traffic. Probably the meaningful benchmarks will be with lots of traffic.
Memory consumption is somewhat similar. For Elixir, I had a 2GB machine which I downsized to 1GB for the benchmark. The app, with little to no traffic, hovers around 29% of RAM.
For Rails, the app with minimal traffic runs close to 29% on a 1GB machine. RAM occasionally spikes when processing images or audios.