Garden City Ruby 2015
WAT!! ActiveRecord Callbacks
Summarized using AI

WAT!! ActiveRecord Callbacks

by Monika M

In the video "WAT!! ActiveRecord Callbacks" presented by Monika M at the Garden City Ruby 2015 conference, the speaker explores the nuances and potential pitfalls of using ActiveRecord callbacks in Ruby on Rails applications. She discusses the simplicity of getting started with callbacks, but stresses their tendency to lead developers into unexpected behaviors in a production environment. Monika emphasizes that callbacks can be very unobtrusive and may be easily forgotten, creating potential landmines in code.

Key points discussed include:

- Understanding Callbacks: The talk begins with an audience engagement approach, testing familiarity with Rails and ActiveRecord callbacks. Monika shares her personal journey of learning about callbacks amidst various projects.

- Common Pitfalls: An example is shared from early in her career where a simple callback intended to activate user accounts led to unexpected failures due to misunderstanding how Ruby methods return values, highlighting the need for awareness around callback behavior.

- Performance Impact: A story about a project experiencing a ten-minute spike in test execution time reveals that callbacks can accumulate delayed jobs when creating user objects, leading to performance bottlenecks.

- Callback Exception Handling: Monika explains that earlier versions of Rails suppressed exceptions in after_commit callbacks, which could lead to unnoticed errors. Fortunately, Rails 4.2 made improvements by allowing exceptions to be thrown again, enhancing reliability.

- Best Practices: She concludes with practical advice on using callbacks judiciously, stressing their appropriate use should align with an object’s internal state rather than relying on external parameters. This insight differentiates effective callback usage from poor implementations.

The speaker's anecdotes, rooted in her own experiences, serve to illustrate the broader challenges developers face when working with callbacks, and she encourages a disciplined approach to understanding and implementing them effectively in code. Monika’s talk aims to equip Rails developers, particularly at a beginner to intermediate level, with the knowledge to navigate the complexities of ActiveRecord callbacks and avoid common traps in software development.

00:00:13.800 My name is Monika. I loved it when my first C program printed 'Hello, World!' on the screen. It gave me a kick every time I did it with either Java, Python, Hadoop, or Ruby on Rails. Recently, there’s one more thing I want you to know about me: I applied for a role, and I was damn sure I would get it. Unfortunately, they rejected my application. With this, I realized one thing: even after a lot of preparation and experience, sometimes things can go wrong. Even though I've been practicing speaking at Toastmasters, this is my first tech talk at a tech conference, so please don't shoot me if I stammer or freeze in between.
00:01:43.110 This talk is a series of incidents that made me go "WAT!" Definitely, this is not my style of presentation. The style I’m using for this talk is inspired by an awesome talk given by Grady Booch. If you’ve already watched it, please don’t judge me too harshly if I don’t do justice to the presentation. If you haven’t watched it yet, I definitely recommend you do so. You will have a lot of laughs. Okay, how many of you know Rails? Please be humble and raise your hands. How many of you know ActiveRecord? How many of you know ActiveRecord callbacks? I was advised to ask questions to engage the audience, so I hope I did that. Now, there was a night when my friend called me. He asked, "Can you see any difference in this code?" I thought, "Dude, I know I have experience, but I still can’t pick it out." He explained that one was a CustomersController and the other was a CommentsController. It turned out he wanted me to identify which model was using callbacks and which was not.
00:02:40.360 I thought for a moment and gave him a thoughtful gap before I answered that it was difficult to identify just based on those pieces of code. The point is, callbacks can be unobtrusive, and often they’re something you just use and forget without realizing the implications. Forwarding along, I remember my first assignment and it being the springtime in my career. I was proud to have written my first production code. The requirement was to activate an account only when the password matches. Like any good programmer, I was excited to test it. The idea was to add a method that returns either true or false, checks the password match, and there it was, the moment of adding the callback to the code. I believed I was savvy—activating the account when the password matches was straightforward, right? I ran the test, and bingo! It ran successfully, which fed my confidence. But of course, I added more tests to check that the account should not activate when the password doesn’t match. I was expecting the test to pass, but oh no—the code did not behave as expected!
00:04:28.120 I thought, what could possibly go wrong with this three or four lines of code? It must be some setup error. After spending hours on it, I finally realized it was the callback that was causing the test to fail. If any of you already know why this was failing, please help me out because I had a terrible time figuring it out. The reason it failed had to do with how Ruby methods return the value of the last statement. I had ignored the point that before callbacks can exit the transaction if they return false. Thus, storing the failed result meant my code would fail! Failure in this was quite the shock.
00:06:34.440 Fast forward to summer, and I was on another project. There was a spike in test execution time by ten minutes, and frankly speaking, we had no idea why. For an entire month, we ignored it, simply because we didn’t know where to look. Waiting ten extra minutes for your tests to run can be quite irritating. Eventually, we traced the issue back to a callback causing this madness. We were astonished—it was such an innocent-looking bit of code that tracked down the time spike. My colleague explained that the user object, being most frequently created, triggered the callback and created a delayed job. If you create a user object multiple times, causing numerous delayed jobs, the time adds up.
00:08:05.450 Despite knowing we could create jobs asynchronously, we didn’t realize how much overhead the callbacks added. After this experience, I decided to be more disciplined with my coding. I dove into the documentation and learned that the after_commit callback suppresses exceptions. I was quite intrigued by the prospect of writing code that doesn’t throw exceptions, but the truth is that if exceptions occur in your after_commit, they won’t be updated in your user’s cache either. You won’t be notified about it until it’s too late, which can be quite dangerous.
00:10:01.500 The silver lining is, in Rails 4.2, the after_commit and after_rollback callbacks began throwing exceptions instead of suppressing them, which is definitely a good change! As winter approached, I hoped to master callbacks fully and be that person who smiled all the time. However, I faced a dilemma—the callbacks troubled me everywhere! After engaging with many people and researching extensively, I discovered the secret sauce for using callbacks correctly. But before I share that, let me ask: can you assign parameters to callbacks? Please don’t tell me to use the various high-key ways to send parameters because that wasn’t how callbacks were designed to work. The proper use of callbacks should be in line with the internal state of the object. If you’re using callbacks, they should only function based on the internal state of that object. That's where they excel!
Explore all talks recorded at Garden City Ruby 2015
+8