Skip to content

Instantly share code, notes, and snippets.

@jonmagic
Last active December 29, 2016 20:21
Show Gist options
  • Save jonmagic/36ad718823a47ef41ad158746eb3056a to your computer and use it in GitHub Desktop.
Save jonmagic/36ad718823a47ef41ad158746eb3056a to your computer and use it in GitHub Desktop.
layout title
post
Arca

Arca is a callback analyzer for ActiveRecord models ideally suited for digging yourself out of callback hell.

Arca was created in July of last year while I was working on tools for migrating customer data from github.com to GitHub Enterprise and for consolidating GitHub Enterprise instances. The tools we built had just shipped and as customers began using the tool we started getting reports that some imports were failing.

Our investigation into these bugs eventually led us to ActiveRecord callbacks. We found two patterns that I’d like to talk about.

Callbacks for a single model were defined in multiple files

I ❤️ me some Ruby modules and think they are an excellent building block for sharing and organizing code. But they can also obfuscate behavior when you are reading code or at best make it a pain to read the code because you have to keep jumping between files. You can run the code and debug it to understand how it works of course, but do we actually do that every time we build a new feature? Guessing not or nothing would ever 🚢

In this case we were defining shared behaviors (including ActiveRecord callbacks) in modules and then including those modules in our models. This made reading and understanding the lifecycle of a model instance more difficult which led to bugs when someone updated the model implementation without reading through every included module.

For this pattern we actually used Arca to audit our models, generated a whitelist with all of the model callbacks that were defined in a module, and then wrote a test that fails when someone tries to add a new callback outside of the model class file (credit to @jch for suggesting we use Arca in our automated tests ✨). The idea here is simply to encourage the developer to stop and consider whether the callback they are adding should be defined in the model class file or if they want to add another entry to the whitelist.

Conditional callbacks

ActiveRecord callbacks support the :if and :unless conditions as well as :on for filtering by action type (create, update, destroy). Whenever I start a greenfield Rails project I love using callbacks and conditional callbacks and the myriad of other shortcuts built into Rails. However, my tune changes whenever I have to work on a real app at scale.

The interplay between conditional callbacks in particular is a nightmare, especially in larger older models. As the number of ways you can create or update a model increase exponentially thanks to this interplay you can bet that you won’t be writing and trying to maintain a test for every permutation. And this leads to bugs, usually edge cases that you didn’t consider or considered and decided to ignore on that quest to ship product.

We did not use Arca for any automated testing around conditional callbacks but I did use the reporting capability to give me more insight into some specific model life cycles while I was debugging customer issues.

Conclusion

The readme for the Arca project shows how to use it so I won’t go into that here. I may have a grudge against the two patterns I described above but I’m not going to tell you to not use them. What I will say is that when you are in a bad situation caused by those patterns Arca is a great way to stop the bleeding or at least give you more insight and reporting abilities around your models and their callbacks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment