Don't make me think, or why I switched to Rails from JavaScript SPAs

February 2, 2022

I picked Ruby on Rails over React-based SPA to build Reviewbunny and it was wonderful. I didn't procrastinate determining the perfect setup or choosing dependencies. Instead, I procrastinated after having finished the MVP. I'd rather do the latter!

I still enjoy React, but why is it so much harder to create apps in the JavaScript ecosystem, compared to Rails? We have all the necessary tools after all.

I think it all comes down to this. When I start a new JavaScript app, I have to make a lot of decisions on my own. I don't want to, but reality is, I have to.

Package manager

npm, Yarn 1 or 2 (yes, they're completely different), pnpm or Snowpack?

Framework

Next.js, Remix, Gatsby, Vite, Create React App, Koa or Express?

Tooling

Set up TypeScript, Prettier, linter and test framework.

Project structure

There are no conventions on this. Every company or project has their own. Or doesn't.

At the last company I worked at, I could count at least 6 different ways of writing and organizing UI code. I can't quickly jump into a new JavaScript codebase and start working productively.

Today's frameworks have rules on how to create pages, which is great. But I'm on my own where to place everything else.

Data storage

SQL databases, MongoDB, Firebase, Fauna, Cloudflare Durable Objects or Planetscale?

Serverless platforms can spawn many instances of my app, so I need connection pools in front of a SQL database to avoid making thousands of connections. MongoDB and Firebase are too flexible, because there's no schema. I got bitten by that before. SaaS offerings cost more and there are additional steps to set up a local environment.

Oh, and database migrations? Start looking for another package to do that for you or attempt to do it yourself.

Data fetching

GraphQL or REST? Apollo, SWR, react-query, Relay or fetch?

Remix's approach is the one I'm looking forward to the most. It tells me exactly how to fetch the data.

Authentication

Passport, Auth0, Firebase or something custom?

Either way, I'll also need to design and code "log in", "sign up", "forgot password" and "reset password" pages. They're not fun to work on.

Background jobs

Reviewbunny has background jobs for ingesting data from GitHub. I'd need to pick a queue library, set up Redis and create another entrypoint to process these jobs.

Serverless environments are not designed to have long-running processes. Now I have to deploy my app elsewhere, like Render or Heroku.

Email delivery

After background jobs, I need to find and set up the library for sending emails. Then, pair it with a template library to render the emails themselves.

Real-time updates

Reviewbunny has a page where progress of a background job is streamed via Websockets.

As far as I know, serverless platforms don't support Websockets, so I'd probably lean into using a SaaS like Pusher, which isn't cheap.

If you got bored reading this, imagine having to do all of this whenever you start a new project.

Compare this to Rails:

  • Package manager — Bundler.
  • Framework — Ruby on Rails.
  • Tooling — Sorbet (type checker, doesn't even require transpiling), Prettier, Rubocop (linter), Minitest (built-in test framework).
  • Project structure — Follow the Rails conventions.
  • Data storage — Active Record with support for SQLite, MySQL and PostgreSQL by default. Database migrations are baked in too.
  • Data fetching — Happens on the server, talking directly to the database.
  • Authentication — Devise + Omniauth for OAuth. Log in, sign up and other pages are provided for you.
  • Background jobs — Action Job. Integrates with all popular libraries, like Sidekiq or Resque, in one line of code.
  • Email delivery - Action Mailer.
  • Real-time updates - Action Cable + Turbo.

See the difference? All the answers to common problems any app might have are there.

As soon as I run rails new, I've got all of that. Things like controllers, models, migrations, views, mailers, background jobs can even be auto-generated via rails generate. It's magical to run rails generate migration AddEmailToUsers email:string and watch it generate a database migration to add an email column to users table.

So where I'm going with this...

There's a huge opportunity to optimize JavaScript developer experience for happiness. We need:

  • More strong opinions and conventions to relieve us from making unnecessary choices.
  • Less configuration and manual labor to start working on anything.

When I think about these principles, XO and Parcel come to mind. They're configurable and very flexible. However, I don't have to do anything to start using them, because their authors made sure to pre-configure them with the best choices based on community feedback.

In my opinion, that's exactly what we, JavaScript developers, need more of when creating apps. Until we have more guidance and conventions, we'll keep spending a week to set up the perfect app boilerplate built to "scale".

I'm still very much invested in JavaScript community, but for now I'm going to stick with Rails and enjoy building web apps.

Pull requests are stuck in review?

Try Reviewbunny and unblock your team.

Learn more