On Flaky Tests, Time Precision, and Order Dependence

A flaky test is one that fails unpredictably, without a corresponding change in the code under test. These often show up in CI runs where a test unrelated to any change made suddenly fails, and then mysteriously passes when re-run. There are many type and causes of “flakes”. Today I want to talk about flaky tests caused by time precision, and time-order dependence.

The specific tools mentioned here will be Ruby, Rails, and PostgreSQL specific. But analogs exist in nearly all other languages and frameworks, so the techniques are broadly applicable.

Frye meme: Not sure if I broke something, or it's a flaky test
Not sure if I broke something, or it's a flaky test…

Read on →

So We've Got a Memory Leak…

Memory leaks happen. And if you’re here, reading this, I’d bet you’re dealing with one. First things first - are you sure it’s a leak, and not bloat?

Okay, so it’s a leak. Much has been written about various tools for profiling a leak, understanding heap dumps, common causes of leaks, work being done to improve Ruby’s memory layout, and so much more. Ben Sheldon’s recent “The answer is in your heap: debugging a big memory increase in Ruby on Rails” is a great example. Ben mentions and shows how he and some teammates used several different tools to generate heap dumps, analyze and interrogate them, and ultimately find and fix the source of a leak in Rails itself.

These are all great resources, and can be crucial knowledge in our hunt for a leak. But they all suppose we already have an idea of where to start looking, or use stripped down examples to showcase the tools. The memory_profiler Gem can profile memory allocations around some suspect code, if we already know that code is suspect. Derailed Benchmarks can get us started on tracking down a leak in the overall stack, or a known problematic resource, and generate heap dumps for us. Comparing those dumps with heapy can point us in the right direction by revealing memory being unexpectedly retained over time. We can use sheap to track down exactly where problematic objects allocations are happening, once we’ve identified those problematic objects.

But what if we’ve reviewed all recent code changes, and nothing stands out? Or if the leaks don’t happen consistently, across all instances of the running app? Or memory starts leaking different times? Where do we even start?

Read on →

Cherry-picking Specific Active Support Behavior

The Active Support library has always (or, close enough to always) allowed us to cherry-pick specific extensions/behaviors, to load only strictly needed dependencies. That is, rather than loading the entirety of the library, we can load just the bits and pieces we need. This helps keep the amount of things loaded in memory smaller, and faster by doing less work. It can also aide in understanding by making more explicit the dependencies some code relies on.

I’ve been using this technique for years, and it’s been solid. Until today, while working on a Rails 7 code base, when I started seeing an error:

uninitialized constant ActiveSupport::IsolatedExecutionState (NameError)

As it happens, what I’d been doing for years worked, but more by accident than design. Active Support 7 has fixed the glitch.

Read on →

A Rails 7 compatible bin/dev for heroku local

Rails 7 introduced a new bin/dev wrapper to launch and manage your Rails server, CSS watcher, and JS bundler into a single process, managed by foreman. This is quite handy for running everything with a single command. But what if you’re deploying to Heroku and using the Heroku CLI’s heroku local to run things locally? Or if you’re a fan of one of the other tools that manage processes based on your Procfile?

I’ve got you covered!

bin/dev for heroku local

The biggest, and most obvious change is swapping out the executable. Mostly this is to do with heroku local using the :<subcommand> style CLI interface. Let’s compare foreman, heroku local, and bin/dev doing similar things to see how their CLIs differ.

# start the web and css processes
$ foreman start web,css
$ heroku local:start web,css
$ bin/dev web,css

It turns out bin/dev explicitly calls the foreman start command. So a quick heroku local version of the same would be:

Read on →

Verbose Shell Scripts for Future You

Command line tools and shell builtins can offer both a short- and long-form way to specify options. Sometimes these are also called short and long flags, respectively. The upshot is a user experience with two ways to specify the same option. A short and terse way. And a longer, more verbose way.

$ curl -HLsS http://stevenharman.net
# ⬆ is the same as ⬇
$ curl --head --location --silent --show-error http://stevenharman.net

Both ways are useful, neither right nor wrong, and each with their own trade offs to consider.

Why Both?

Meme: Girl shrugging and asking, "Why don't we have both?" Why are there two ways to say the same thing?

It’s a good question. One I’ve asked too. But I’ve not found a definitive answer. Perhaps the truth is lost to history at this point?

From what I can tell, originally (i.e., the early/original *nix flavored OSes) there were only single-character options. At some point multi-character options were added, possibly via GNU.

Along the way the sheer number of options also grew, a lot. Is this a cause and effect relationship, a correlation, or pure happenstance? I don’t know. But today we have A LOT of options, and often multiple ways to express them.

Let’s talk about the trade offs and when to use each style.

Read on →

Well-behaved Ruby Objects: Equality

A “well-behaved” object in Ruby needs to understand the following:

What makes two Ruby objects “equal”?
And which version of “equal” (there are several in Ruby)?
And what makes an object usable as a Hash key?
And is that the same thing that makes them Comparable?

Because I can never seem to remember the specifics. And because my searching the Interwebs seems to find related, but not specific help. And because I’ve got this blurgh-thing… I might as well use it to help future-me (and maybe you?).

Gimme the gist

Implement hash and eql? for use as a Hash key, and then alias the eql? method to == for the expected developer ergonomics. Something like this:

class Message
  attr_reader :body, :subject

  def initialize(subject:, body:)
    @subject = subject
    @body = body
  end

  def eql?(other)
    other.class == self.class &&
      other.body == body &&
      other.subject == subject
  end
  alias == eql?

  def hash
    [self.class, body, subject].hash
  end
end

What to know more about the specifics, or how to also make these objects Comparable? Read on, friend…

Read on →

Debugging Homebrew with Pry

Over the years I’ve written a few Homebrew formulas and sent the occasional Pull Request to update a formula or two. But I’ve never done any work within Homebrew. I’ve never needed to debug how Homebrew itself worked. Until now.

I assumed our typical Ruby debugging tools, like Pry and Pry-Byebug would work. Homebrew is just Ruby, after all. Which is true. But it’s also a bit special, and we can’t do the normal require "pry-byebug"; binding.pry tricks.

But we can, with a little poking around, still use those tools!

Read on →

In Search Of… Enumerable#transform for Ruby

In Search Of… a Ruby method with the semantics of Enumerable#map and Enumerable#inject. That is, to transform values while also having access to the prior iteration return value. Sounds odd, I know.

Given the following “value object”

class Snapshot
  def initialize(value = 0)
    @value = value
  end

  def apply(new_value)
    self.class.new(@value + new_value)
  end
end

I want to build an array of snapshots, based on some set of inputs. Meaning, I think I’d like something that looks like this

(1..10).transform(Snapshot.new) { |prev_snap, i|
  prev_snap.apply(i)
}

Resulting in this

#=> [#<Snapshot:0x00007fe550d12558 @value=1>,
#=>  #<Snapshot:0x00007fe550d12508 @value=3>,
#=>  #<Snapshot:0x00007fe550d124e0 @value=6>,
#=>  #<Snapshot:0x00007fe550d124b8 @value=10>,
#=>  #<Snapshot:0x00007fe550d12468 @value=15>,
#=>  #<Snapshot:0x00007fe550d12440 @value=21>,
#=>  #<Snapshot:0x00007fe550d12418 @value=28>,
#=>  #<Snapshot:0x00007fe550d123c8 @value=36>,
#=>  #<Snapshot:0x00007fe550d123a0 @value=45>,
#=>  #<Snapshot:0x00007fe550d12378 @value=55>]

Right now, as of Ruby 2.5, I don’t know of a clean way of doing that. Clean being in the eye of the beholder, I suppose. It can be done with Enumerable#map or Enumerable#inject, but it ain’t pretty.

Read on →

Reclaim Your Domain Model from Rails

TL,DR; When building an application using Rails, I prefer to keep all my model in app/models/. I reserve lib/ for those other things - those not-my-domain-things. I’d like to explain the what and why.

Boundaries Amongst the Fields; Deep Greens Rails has a history of co-opting names, as happened when the ActiveRecord library used the active record pattern name. A similar co-opting has happened with the MVC pattern wherein many believe Rails is an example of the MVC design pattern. In truth, it’s probably closer to MVC Model 2… but I digress.

Model View What’s-that-now?

MVC stands for Model, View, Controller. In Rails-land we know what the Controllers are. And while we don’t have Views in the way that MVC meant, we do have view-templates, and we call those our views. The Model is meant to be all the things it takes to model our problem domain. As applied to Rails, the Model seems the most misunderstood/misused of the MVC triumvirate.

Read on →

The No Man's Land of Web Development

I think about the current state of web development experiences as a continuum. On one end we have traditional Rails-era web apps - full page loads, with bits of dynamism haphazardly mixed in. On the other are rich client-side JavaScript apps with their own structure and life cycles, standing alone and/or talking to an HTTP API.

No Man's Land Flanders Field France 1919.

Rails-era web apps have some great tooling and deliver a pretty nice development experience. The shift toward rich client-side web experiences has lead to some great tooling that makes for a 1st-class web development experience.

A no man’s land

Between these two approaches lies a no man’s land. The tooling and techniques are focused largely on either end of the continuum despite the large population of apps living in the middle.

Read on →