ArticlesRuby programmingEngineering
An experience report of writing and publishing a Ruby gem
A couple nights ago I was overcome with the urge to publish a Ruby gem. I have been writing Ruby for over 5 years and realized that it was time to give Ruby development outside of Stripe's Ruby infra a shot.
The package is
eclair
which I've wanted to build on and off for about three years now.
It's worth its own article and context, so that's all I'll say
about the gem itself here.
I wanted to put a strong foot forward when publishing the gem. I do a lot of advocacy for writing high-quality Ruby code, mostly internal to Stripe, but also in public. Check out Ruby style guide and Effective Sorbet for most of the advice.
However, I haven't shared a whole Ruby library in public before. While I didn't expect to do a perfect job with the new stuff, I did want to get some things right.
Requirements:
strict
typing as the minimum.
rubyfmt
.Plus the stuff I would do in any design:
I learned much more about the Ruby language's built-in
tooling. It's cool to see ruby
,
irb
, bundle
, and
gem
all coming as a unit. Never really knew
they flocked together. Getting Ruby to a newer version got
all these things to a newer version too.
I'm a big fan of Clojure. In that ecosystem the mantra is
everything is data. You often write configuration files as
Clojure data structures. It was cool to see Ruby doing a
similar thing, even if it forgot the data part.
Gemfile
, Gemspec
,
Rakefile
are all Ruby code. I've definitely
touched Stripe Gemfiles before but working with the RubyGem
registry made it so much clearer how everything was fitting
together.
The Sorbet VSCode extension can be slow at Stripe scale. On a few hundred billion lines less of Ruby it was amazing.
The minitest
style of tests were nice. Having
really only written RSpec-like tests,
minitest
feels a lot less magical and much
smaller. Definitely reminded me of Go tests.
I wanted to follow Effective Sorbet precisely but there was one thing that I could not do because I felt it was not appropriate for an open-source project.
Despite recommending them heavily, I didn't use
T::Struct
. I had used
T::Struct
initially but switched to plain old Ruby
objects (POROs).
The reasoning: too many methods and too many
bad methods, e.g. with
, from_hash
, etc. I can't
feel comfortable shipping a gem with that much baggage of
unexpected behavior.
Stripes write friction logs. A friction log is basically a stream of conscious document that details everything and anything that went wrong or felt off about doing something. As a platform team lead, I get friction logs from folks across the company all the time. Those logs feed into what we choose to prioritize. It's a good system.
Here's a distillation of my frictions:
By far I wasted the most time trying to get Ruby set up on my Macbook. Stripe-issued laptops solve this problem so I hadn't felt the pain before.
Apple ships an old version of Ruby (~v2.6) but all the tooling I worked with expected Ruby 3.0. In retrospect, had I got the Ruby version issue fixed earlier in the process so many things would have been smoother.
I felt this pain most when setting up Sorbet, in particular
initializing my project with
Tapioca. The
exception thrown running
bundle exec tapioca init
wasn't super helpful but
luckily enough to search me up a
lead on how to fix it.
Once I eventually got rbenv
setup and working, and
had rebooted everything to use it instead of the Mac-default
Ruby version things got better.
In terms of wall-clock time spent, RubyGems caused me the greatest time loss. RubyGems is great but the search page results were a bit all too easy to misread. When I started my gem-ing, the first thing I did was see if the name "eclair" was available. I got so excited because I saw it was.
It was only after a long night of working on the gem itself that
I finally went to publish my gem and it turned out
eclair
was not available. The gem had been recently
"yanked," meaning taken down by its author. The gem
was unused but I wouldn't be able to claim it for 3 months.
Betrayal, the worst of all.
Luckily only a little more than a day later after reaching out to the current gem owner, they graciously transferred the gem over to me. Thanks again, Cyrus!
rubyfmt
The Ruby formatter rubyfmt
doesn't seem to
integrate with the
Ruby LSP extension. It probably works with the old "Ruby" extension but
VSCode steers people away from downloading that one.
This isn't a big deal, I just didn't manage to get format-on-save working.
Overall publishing a Ruby gem was a pleasant experience. I
learned a good amount from it and it was nice learning how to
set up Sorbet, rubyfmt
, and other things I'd only
previously used because someone else installed them for me.
Thanks for reading!