<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Chris Kottom's Tech and Business Blog</title>
  <id>https://chriskottom.com/articles</id>
  <link href="https://chriskottom.com/articles"/>
  <link href="https://chriskottom.com/feed.xml" rel="self"/>
  <updated>2025-06-20T09:11:00+02:00</updated>
  <author>
    <name>Chris Kottom</name>
  </author>
  <entry>
    <title>Solid Service Objects with Interactor</title>
    <link rel="alternate" href="https://chriskottom.com/articles/solid-service-objects-using-interactor/"/>
    <id>https://chriskottom.com/articles/solid-service-objects-using-interactor/</id>
    <published>2025-06-20T09:11:00+02:00</published>
    <updated>2025-06-20T14:54:39+02:00</updated>
    <author>
      <name>Chris Kottom</name>
    </author>
    <summary type="html">&lt;p&gt;Most non-trivial Rails applications eventually outgrow the basic MVC pattern. You start with simple controller actions and model methods, but as your business logic gets more complex, you need somewhere to put all that code. The choice between fat...&lt;/p&gt;</summary>
  </entry>
  <entry>
    <title>Minitest Assertions with Spec-Style Blocks</title>
    <link rel="alternate" href="https://chriskottom.com/articles/minitest-assertions-with-spec-style-blocks/"/>
    <id>https://chriskottom.com/articles/minitest-assertions-with-spec-style-blocks/</id>
    <published>2025-06-11T13:52:00+02:00</published>
    <updated>2025-06-11T13:55:55+02:00</updated>
    <author>
      <name>Chris Kottom</name>
    </author>
    <summary type="html">&lt;p&gt;I just recently started using Minitest again on some greenfield projects after spending several years working primarily in RSpec. Having been over to the other side, I can say there was certainly a mix of things I liked and things I didn’t, but without...&lt;/p&gt;</summary>
  </entry>
  <entry>
    <title>Working in Public Update - September 5, 2022</title>
    <link rel="alternate" href="https://chriskottom.com/articles/working-in-public-update-september-5-2022/"/>
    <id>https://chriskottom.com/articles/working-in-public-update-september-5-2022/</id>
    <published>2022-09-05T02:00:00+02:00</published>
    <updated>2025-06-09T16:15:25+02:00</updated>
    <author>
      <name>Chris Kottom</name>
    </author>
    <summary type="html">&lt;h2&gt;What I’ve been working on&lt;/h2&gt;

&lt;p&gt;I spent a lot of time last week investing in areas that I think will help me go faster as I build out &lt;a href="https://huddleup.dev/"&gt;HuddleUp&lt;/a&gt; over the next weeks and months, so even though I didn’t cross as many items off the to-do list as I would have...&lt;/p&gt;</summary>
  </entry>
  <entry>
    <title>Working in Public Update - August 29, 2022</title>
    <link rel="alternate" href="https://chriskottom.com/articles/working-in-public-update-august-29-2022/"/>
    <id>https://chriskottom.com/articles/working-in-public-update-august-29-2022/</id>
    <published>2022-08-29T11:00:00+02:00</published>
    <updated>2022-08-29T10:55:00+02:00</updated>
    <author>
      <name>Chris Kottom</name>
    </author>
    <summary type="html">&lt;p&gt;I spent the past two weeks in Italy enjoying the sights and sounds and, let’s be honest here, tastes that the country has to offer.
&lt;/p&gt;&lt;div class="w-full max-w-2xl p-6 mx-auto dark:my-6 dark:bg-white"&gt;
  &lt;img src="/images/spaghetti_al_scoglio.jpg" title="Spaghetti al Scoglio, spaghetti with seafood" alt="Spaghetti al Scoglio, spaghetti with seafood" class="w-full"&gt;
&lt;/div&gt;

&lt;p&gt;We’ve been taking our family there for the past 13 years - same town, same apartment, same everything - and it’s always been a great source of inspiration as well as a place to catch our breath before the start of school and the final push through the end of the year.
&lt;/p&gt;&lt;div class="w-full max-w-2xl p-6 mx-auto dark:my-6 dark:bg-white"&gt;
  &lt;img src="/images/sunrise_lido.jpg" title="Sunrise at Lido di Dante" alt="Sunrise at Lido di Dante" class="w-full"&gt;
&lt;/div&gt;
</summary>
  </entry>
  <entry>
    <title>Comparing Timestamps in Rails</title>
    <link rel="alternate" href="https://chriskottom.com/articles/comparing-timestamps-in-rails/"/>
    <id>https://chriskottom.com/articles/comparing-timestamps-in-rails/</id>
    <published>2018-01-14T01:00:00+01:00</published>
    <updated>2022-04-24T10:30:23+02:00</updated>
    <author>
      <name>Chris Kottom</name>
    </author>
    <summary type="html">&lt;div class="w-full mb-6 px-4 py-3 border border-l-8 border-sky-500 bg-sky-100 text-sky-900"&gt;
  &lt;p class="font-semibold uppercase text-base" style="margin-bottom: 2px !important"&gt;
    It’s not old, it’s vintage.
  &lt;/p&gt;
  &lt;p class="m-0 text-base" style="margin-bottom: 2px !important"&gt;
    This post was last updated some years ago and hasn’t been updated recently. Be aware that some of the content, tools, and techniques described may not be completely up-to-date.
  &lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;The Ruby core language and standard library include two classes that represent timestamps: &lt;code&gt;Time&lt;/code&gt; and &lt;code&gt;DateTime&lt;/code&gt;.  And even though they fill similar needs, they have different internals and aren’t comparable.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="codehilite ruby"&gt;&lt;code&gt;&lt;table class="rouge-table"&gt;&lt;tbody&gt;&lt;tr&gt;
&lt;td class="rouge-gutter gl"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
8
9
10
11
&lt;/pre&gt;&lt;/td&gt;
&lt;td class="rouge-code"&gt;&lt;pre&gt;&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mo"&gt;001&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'date'&lt;/span&gt;
&lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mo"&gt;002&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;
&lt;span class="mi"&gt;2018&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mo"&gt;01&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mo"&gt;0100&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mo"&gt;003&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;
&lt;span class="c1"&gt;#&amp;lt;DateTime: 2018-01-14T16:40:40+01:00 ((2458133j,56440s,60191240n),+3600s,2299161j)&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mo"&gt;004&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;
&lt;span class="no"&gt;ArgumentError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;comparison&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="no"&gt;Time&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="no"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;failed&lt;/span&gt;
        &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="ss"&gt;:in&lt;/span&gt; &lt;span class="sb"&gt;`&amp;lt;'
        from (irb):5
        from /home/chris/.rbenv/versions/2.4.2/bin/irb:11:in `&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;</summary>
  </entry>
  <entry>
    <title>Rails Helper Testing Made Simple</title>
    <link rel="alternate" href="https://chriskottom.com/articles/rails-helper-testing-made-simple/"/>
    <id>https://chriskottom.com/articles/rails-helper-testing-made-simple/</id>
    <published>2017-06-13T02:00:00+02:00</published>
    <updated>2022-04-24T10:30:18+02:00</updated>
    <author>
      <name>Chris Kottom</name>
    </author>
    <summary type="html">&lt;div class="w-full mb-6 px-4 py-3 border border-l-8 border-sky-500 bg-sky-100 text-sky-900"&gt;
  &lt;p class="font-semibold uppercase text-base" style="margin-bottom: 2px !important"&gt;
    It’s not old, it’s vintage.
  &lt;/p&gt;
  &lt;p class="m-0 text-base" style="margin-bottom: 2px !important"&gt;
    This post was last updated some years ago and hasn’t been updated recently. Be aware that some of the content, tools, and techniques described may not be completely up-to-date.
  &lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Rails relies on a standard project structure and a strong set of conventions to keep things neat and tidy - models separated from controllers, configuration in another folder structured just so. The exception that proves the rule in this case, though, would have to be Rails view helpers. Helpers tend to be a dumping ground for all the random bits of view logic, formatting, and utility code that accumulate in every web application, and if you’re not disciplined (and most of us aren’t), &lt;code&gt;app/helpers&lt;/code&gt; can degenerate into a jungle quickly.&lt;/p&gt;

&lt;p&gt;But helpers fill a necessary role in our applications by removing presentation logic from our templates and moving it to methods which makes it easier to test. So even though they’re going to be hard to organize almost by definition, we can still be disciplined about testing them. In other words: your view helpers might still look like spaghetti, but at least we can make sure it’s well-tested spaghetti.&lt;/p&gt;</summary>
  </entry>
  <entry>
    <title>Full-Stack Testing with Rails System Tests</title>
    <link rel="alternate" href="https://chriskottom.com/articles/full-stack-testing-with-rails-system-tests/"/>
    <id>https://chriskottom.com/articles/full-stack-testing-with-rails-system-tests/</id>
    <published>2017-04-26T10:29:46+02:00</published>
    <updated>2022-04-24T10:30:10+02:00</updated>
    <author>
      <name>Chris Kottom</name>
    </author>
    <summary type="html">&lt;div class="w-full mb-6 px-4 py-3 border border-l-8 border-sky-500 bg-sky-100 text-sky-900"&gt;
  &lt;p class="font-semibold uppercase text-base" style="margin-bottom: 2px !important"&gt;
    It’s not old, it’s vintage.
  &lt;/p&gt;
  &lt;p class="m-0 text-base" style="margin-bottom: 2px !important"&gt;
    This post was last updated some years ago and hasn’t been updated recently. Be aware that some of the content, tools, and techniques described may not be completely up-to-date.
  &lt;/p&gt;
&lt;/div&gt;

&lt;div class="w-full max-w-lg mx-auto mb-6 px-6 dark:py-6 dark:bg-white lg:float-right lg:pr-0 lg:dark:pr-6 lg:dark:ml-6"&gt;
  &lt;img src="/images/unit-tests-passing-no-integration-tests.jpg" title="Two unit tests passing, no integration tests" alt="Two unit tests passing, no integration tests" class="w-full"&gt;
&lt;/div&gt;

&lt;p&gt;Ruby on Rails’ bundled support for automated testing has contributed to building a culture of testing within the community, but it’s also been a source of some debate. Differences in testing styles and preferences have spawned long-running discussions and flame wars over the years. Most of this amounts to bikeshedding, but if there’s one area where The Rails Way has lagged behind RSpec, it’s been in the area of end-to-end application testing. RSpec has long had expressive feature specs based on &lt;a href="https://github.com/teamcapybara/capybara"&gt;Capybara&lt;/a&gt;, while Rails default integration tests, though functional, have never been as expressive.&lt;/p&gt;

&lt;p&gt;With the release of version 5.1, Rails introduces &lt;strong&gt;system tests&lt;/strong&gt; built on Capybara. These look like just the thing to fill this longstanding gap, and the fact that they’ll be configured to work right out of the box with no additional setup required will make it easier for more developers to start using them. In this post, we’re going to look at the approach Rails takes toward system tests and what kind of advantages they offer over both old-school integration tests and current solutions for testing apps with Capybara.&lt;/p&gt;</summary>
  </entry>
  <entry>
    <title>Versioning a Rails API</title>
    <link rel="alternate" href="https://chriskottom.com/articles/versioning-a-rails-api/"/>
    <id>https://chriskottom.com/articles/versioning-a-rails-api/</id>
    <published>2017-04-05T02:00:00+02:00</published>
    <updated>2022-04-24T10:30:05+02:00</updated>
    <author>
      <name>Chris Kottom</name>
    </author>
    <summary type="html">&lt;div class="w-full mb-6 px-4 py-3 border border-l-8 border-sky-500 bg-sky-100 text-sky-900"&gt;
  &lt;p class="font-semibold uppercase text-base" style="margin-bottom: 2px !important"&gt;
    It’s not old, it’s vintage.
  &lt;/p&gt;
  &lt;p class="m-0 text-base" style="margin-bottom: 2px !important"&gt;
    This post was last updated some years ago and hasn’t been updated recently. Be aware that some of the content, tools, and techniques described may not be completely up-to-date.
  &lt;/p&gt;
&lt;/div&gt;

&lt;figure class="flex flex-col w-full mx-auto mb-6 md:max-w-lg md:float-right md:mr-0 md:ml-4 md:mb-3"&gt;
  &lt;img src="/images/versioning-commitstrip.jpg"&gt;
  &lt;figcaption class="text-center mt-0 text-base"&gt;
    &lt;a href="http://www.commitstrip.com/en/2014/05/05/when-i-finally-manage-to-master-an-api-or-a-framework/"&gt;When I finally manage to master an API or framework&lt;/a&gt;&lt;br&gt;by &lt;a href="http://www.commitstrip.com"&gt;CommitStrip.com&lt;/a&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;API versioning is one of those topics that divides developers into two camps: those who just know that their way is the best way, and those that are confused by the first camp and would rather pass on the whole thing. Once we set aside the bikeshedding, there are sound, sane justifications for choosing one method over another, but in a lot of cases, discussions move from theoretical to hypothetical problems instead of worrying about making things that work.&lt;/p&gt;

&lt;p&gt;The good news for Rails developers is that adding versions to an existing application doesn’t have to be painful. If you know what to do, you can implement it and maintain it with little effort.&lt;/p&gt;

&lt;p&gt;In this article, we’ll look at what you get by versioning your API, why you need to think really hard before deciding not to, and how to update your application to make it work.
&lt;/p&gt;</summary>
  </entry>
  <entry>
    <title>Minitest Cheat Sheet</title>
    <link rel="alternate" href="https://chriskottom.com/articles/minitest-cheat-sheet/"/>
    <id>https://chriskottom.com/articles/minitest-cheat-sheet/</id>
    <published>2016-08-10T18:28:59+02:00</published>
    <updated>2022-04-24T10:30:00+02:00</updated>
    <author>
      <name>Chris Kottom</name>
    </author>
    <summary type="html">&lt;div class="w-full mb-6 px-4 py-3 border border-l-8 border-sky-500 bg-sky-100 text-sky-900"&gt;
  &lt;p class="font-semibold uppercase text-base" style="margin-bottom: 2px !important"&gt;
    It’s not old, it’s vintage.
  &lt;/p&gt;
  &lt;p class="m-0 text-base" style="margin-bottom: 2px !important"&gt;
    This post was last updated some years ago and hasn’t been updated recently. Be aware that some of the content, tools, and techniques described may not be completely up-to-date.
  &lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Recently I came across &lt;a href="https://medium.com/@bryanp/the-minitest-dilemma-f17ad1c7dafd"&gt;a post that called out a perceived lack of documentation and learning materials for Minitest&lt;/a&gt; in contrast with RSpec.  And while I’m not entirely sure I agree with the premise, the main point of the article had the ring of truth to it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If there’s a problem to be solved here, it’s that the obvious parts
of Minitest need to be better documented. Organize the new documentation
in the format of “I want to do xyz thing”,with an example.&lt;/p&gt;

&lt;p&gt;Bryan Powell&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Honestly, what project couldn’t use better docs - more focused, more examples, and detailed explanations?  That was exactly the same line of thinking that got me thinking about writing &lt;a href="/minitestcookbook"&gt;The Minitest Cookbook&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I released a cheat sheet with the book that I thought might provide people with a partial solution, so I prepared a simplified version that includes a reference to the basic methods and syntax for &lt;code&gt;Minitest&lt;/code&gt; and &lt;code&gt;Minitest::Spec&lt;/code&gt; as well as a full listing of all assertions and expectations for each along with simple code examples for context.  (The full version also includes Rails-specific helpers and assertions and a list of the most commonly used Capybara methods.)&lt;/p&gt;</summary>
  </entry>
  <entry>
    <title>Testing Rails Background Workers</title>
    <link rel="alternate" href="https://chriskottom.com/articles/testing-rails-background-workers/"/>
    <id>https://chriskottom.com/articles/testing-rails-background-workers/</id>
    <published>2015-11-24T01:00:00+01:00</published>
    <updated>2022-04-24T10:29:37+02:00</updated>
    <author>
      <name>Chris Kottom</name>
    </author>
    <summary type="html">&lt;div class="w-full mb-6 px-4 py-3 border border-l-8 border-sky-500 bg-sky-100 text-sky-900"&gt;
  &lt;p class="font-semibold uppercase text-base" style="margin-bottom: 2px !important"&gt;
    It’s not old, it’s vintage.
  &lt;/p&gt;
  &lt;p class="m-0 text-base" style="margin-bottom: 2px !important"&gt;
    This post was last updated some years ago and hasn’t been updated recently. Be aware that some of the content, tools, and techniques described may not be completely up-to-date.
  &lt;/p&gt;
&lt;/div&gt;

&lt;div class="w-full max-w-lg mx-auto mb-6 px-6 dark:py-6 dark:bg-white lg:float-right lg:pr-0 lg:dark:pr-6 lg:dark:ml-6"&gt;
  &lt;img src="/images/set_it_and_forget_it.png" title="Set it and forget it" alt="Set it and forget it" class="w-full"&gt;
&lt;/div&gt;

&lt;p&gt;When it was &lt;a href="http://weblog.rubyonrails.org/2014/12/19/Rails-4-2-final/"&gt;released in Rails 4.2&lt;/a&gt;, Active Job was an important addition to the platform.  Background jobs have been a part of the ecosystem for a long time, but this was the first time that developers had a single API to work with a variety of job queuing frameworks.  Having a common interface has led to a shared base of knowledge and patterns for developing and testing workers.&lt;/p&gt;

&lt;p&gt;&lt;a href="/articles/bulletproof-rails-background-jobs"&gt;In the last post, we looked at some good practices for writing well-designed background jobs in Rails using Active Job&lt;/a&gt;, but we  didn’t get around to the question of how to test them.  This post will focus on a step-by-step strategy for testing all of your application’s “set it and forget it” code - one that leverages the unified Active Job interface and the tools Rails and Minitest provide us.&lt;/p&gt;</summary>
  </entry>
  <entry>
    <title>Bulletproof Rails Background Jobs</title>
    <link rel="alternate" href="https://chriskottom.com/articles/bulletproof-rails-background-jobs/"/>
    <id>https://chriskottom.com/articles/bulletproof-rails-background-jobs/</id>
    <published>2015-11-12T01:00:00+01:00</published>
    <updated>2022-04-24T10:29:39+02:00</updated>
    <author>
      <name>Chris Kottom</name>
    </author>
    <summary type="html">&lt;div class="w-full mb-6 px-4 py-3 border border-l-8 border-sky-500 bg-sky-100 text-sky-900"&gt;
  &lt;p class="font-semibold uppercase text-base" style="margin-bottom: 2px !important"&gt;
    It’s not old, it’s vintage.
  &lt;/p&gt;
  &lt;p class="m-0 text-base" style="margin-bottom: 2px !important"&gt;
    This post was last updated some years ago and hasn’t been updated recently. Be aware that some of the content, tools, and techniques described may not be completely up-to-date.
  &lt;/p&gt;
&lt;/div&gt;

&lt;div class="w-full max-w-lg mx-auto mb-6 px-6 dark:py-6 dark:bg-white lg:float-right lg:pr-0 lg:dark:pr-6 lg:dark:ml-6"&gt;
  &lt;img src="/images/bulletproof_superman.jpg" title="Bulletproof Superman" alt="Bulletproof Superman" class="w-full"&gt;
&lt;/div&gt;

&lt;p&gt;The ability to run operations with long or uncertain execution times in the background has become a standard tool for modern web applications, and most frameworks and platforms now include some sort of support for encapsulating pieces of logic that involve heavy lifting out of the main request/response cycle.  For example, I recently finished work on a relatively simple Rails application that had about a dozen different background jobs written for a whole range of standard-ish use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sending bulk notifications to a group of users&lt;/li&gt;
&lt;li&gt;Consuming data from external APIs and updating the database&lt;/li&gt;
&lt;li&gt;Batch creation of work items to users&lt;/li&gt;
&lt;li&gt;Importing records from an uploaded data file&lt;/li&gt;
&lt;li&gt;Complex object state manipulation that doesn’t fit in an AR callback&lt;/li&gt;
&lt;li&gt;Refreshing scores cached in the database after an admin changes the weights used to calculate them&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The way I write and test background workers has evolved over the years, and since I’m getting ready to start a new project that will have a big background processing component, I thought it would be a good time to reflect on my approach and what I’ve learned.&lt;/p&gt;</summary>
  </entry>
</feed>
