-
Book Review: Sustainable Web Development with Ruby on Rails
by David Bryan Copeland
Working on Ruby on Rails apps can be a joyful experience. As application get larger, it is often the case that productivity nose-dives and it becomes harder to ship new features or change existing behavior. It doesn’t have to be. This book focuses on opinionated strategies to keep Rails applications maintainable.
The overarching theme is that keeping things maintainable means investing in keeping them that way every day: Agreeing with team members on standards and sticking to them. Automate when possible. Make it easy to know the “right” way to add new code. Avoid surprising or magic behavior. I think of this as resisting entropy.
The book goes into a lot of details: Application setup, and
bin/
scripts, where to put the business logic, routing, HTML templates, helpers, css, javascript, models, database, controllers, jobs, and more. Throughout, the example show the recommended code and how to test it.Of course, I don’t agree with every single piece of advise that Copeland makes. Every engineer develops their own scars based on their past experiences, and try to protect against different future pain. Sometimes there are trade-offs, and reasonable people can disagree on what to optimize for.
Overall, I got a lot of ideas on how to improve maintainability of the apps I am currently working on, and expect that most folks would too.
Links:
-
The REPL: Issue 128 - April 2025
Conway’s Law
A good explanation why Conway’s law makes sense as a response to real communication problems. The solution to those problems is to minimize the communication paths to avoid being bogged down. Of course, less communication paths also means less collaboration and silos. There is no silver bullet, but knowing about the phenomena makes it easier to organize towards goals.
Ruby might be faster than you think
Like the a not-for-polite-company adage says, everyone has a benchmark. A recent project made the rounds adding support for using crystal to speed up Ruby very easily. The author of this post shows, that a bit of work on what is actually benchmarked makes it so the Ruby-only version performs faster than the Crystal version. Well, that is interesting. Which benchmark should you trust? The one that is appropriate for your use case, naturally 😄.
An unfair advantage: multi-tenant queues in Postgres
I didn’t look very closely at the algorithm, but the idea is that if you distribute jobs at write time, you save work at read-time, making the dequeuing faster, and avoids doing coordination work when you read. I’ve seen this too in production systems that have very “hot” queues.
-
Scripts With Rails Application Loaded
I often need to write some scripts for my Rails applications. These are sometimes intended to be run in development or production environments, and require that the Rails application is loaded. The most common way I’ve seen of doing this is with a
rake
task:namespace :import do desc "Import people. Requires a file name as argument" task :people, %i[file_path] => :environment do |_t, args| puts "Importing people from #{args[:file_path]}" People::Import.new(args[:file_path]).perform puts "Done" end end
rake
tasks have their benefits, but the argument handling is not like most other unix programs. They are passed as an array at the end of the task name:bash-5.2$ rake import:people[people.csv] Importing people from people.csv Done
Even more troubling, is that if you use
zsh
(and I am!), the[
and]
need to be escaped, or the whole argument torake
quoted:$ rake import:people\[people.csv\] # OR rake "import:people[people.csv]"
Rails runner
You can use
rails runner
to run any ruby file in the context of the rails application:# import.rb puts "Importing people from #{ARGV.first}" People::Import.new(ARGV.first).perform puts "Done"
And run it by passing your file as the first argument:
$ rails runner import.rb people.csv
But you can also use
rails runner
as a shebang line.#!/usr/bin/env rails runner # bin/import puts "Importing people from #{ARGV.first}" People::Import.new(ARGV.first).perform puts "Done"
And now you can invoke that directly:
$ chmod +x bin/import $ bin/import people.csv
The shebang line allows your script to be directly executable. Now, you can make it more ergonomic, and build up a unix-like command:
#!/usr/bin/env rails runner # bin/import options = {} OptionParser.new do |parser| parser.banner = "Usage: rails runner example.rb [options]" parser.on("-f", "--file FILE", "Import from FILE") do |file| options[:file] = file end parser.on("-h", "--help", "Prints this help") do puts parser exit end end.tap(&:parse!) puts "Importing people from #{options[:file]}" # ...
$ bin/import --file people.csv # ... $ bin/import -h Usage: rails runner example.rb [options] -f, --file FILE Import from FILE -h, --help Prints this help
Conclusion
Using
rails runner
as a shebang allows full access to the Rails environment in your script, without having to sacrifice command-line ergonomics. -
The REPL: Issue 127 - March 2025
Bash Debugging
Julia Evans, in here signature comic/zine style, explains how to debug bash. I was today years old when I learned that you can have a step debugger for a bash script.
How we migrated from Sidekiq to Solid Queue
Chirag Shah at BigBinary explain in detail how they migrated an app from Sidekiq to SolidQueue. From the configuration it seems that the queue usage is on the low side (4 types of workers, each with a single process and 3 threads).
The article doesn’t mention in the article what they hoped to achieve or what their results where. I assume positive, because they close by saying they plan on doing the migration on more apps.
If I had to guess, I would say that they gained a simpler infrastructure (because they don’t use redis for jobs), but more importantly, they gained transactionality: All-or-nothing writes for the models and the jobs, which is impossible using 2 separate data stores.
How Figma’s Databases Team Lived to Tell the Scale
The folks at Figma tell their battle story about scaling Postgres. Having a DB proxy that checks the queries and routes to the correct shard (and even aggregates among shards) is wild.
The use of logical partitioning to prove their point before doing actual physical partitioning seems very clever.
-
How I'm Productive In The Command Line
I spend a lot of time on the command line. My most frequently used commands are
git
(by far), andrails
(mostly forrails test
) orrspec
(depending on the project). Most invocation of both commands require arguments. And most of those arguments are paths to files. In big projects, typing paths to files can be tedious, even with tab completion. My productivity trick for that is using Zsh Line Editor widgets.Let’s see a widget in action: