stevencodes.swe - September 7, 2025

Dev tool recs, book update

👋 Hey friends,

Here’s what I’ve got in store for you this week:

  • Snippet from Chapter 4 of The Backend Lowdown

  • An update about the book

  • Dev tool recommendations

Let’s get into it 👇

The Backend Lowdown: Chapter 4 Preview

Every newsletter will include a snippet from my book in progress, The Backend Lowdown, available for $1 right now on Gumroad!

Get The Backend Lowdown →

Bust-on-Write (keep cache-aside correct)

With cache-aside, your cache only updates when there's a miss - it doesn't know when the underlying data changes. To handle updates correctly, your write path needs to delete (or "bust") the affected cache keys, forcing the next read to fetch fresh data and repopulate the cache.

When it helps

  • You want users to see their changes immediately but prefer to keep your read path simple (pure cache-aside)

  • You have derived caches (product lists, search indexes, count aggregates) that become stale when individual items change

  • Your data is read frequently but written occasionally, making invalidation cheaper than constant updates

Here are 3 ways to go about implementing bust-on-write:
Newsletter note: only showing one example here

1. Direct deletes (entity + known lists)

After your database write commits, directly delete the cached entity plus any lists or indexes you know contain this item.

class Product < ApplicationRecord
  after_commit :bust_caches

  def bust_caches
    Rails.cache.delete_multi(entity_and_list_keys)
  end

  private

  # Centralize key construction so reads & writes stay in sync
  def entity_and_list_keys
    locales = %w[en es] # Your supported locales

    # Delete all locale variants of this product
    entity = locales.map { |loc| "v3:product:#{id}:#{loc}" }

    # Delete specific lists that we know include this product
    lists = []
    lists << "v3:products:category:#{category_id}:page:1"
    lists << "v3:products:category:#{category_id}:featured"
    # Add other small, stable lists that definitely contain this item

    entity + lists
  end
end

Notes

  • Works best when you have a small, predictable set of derived caches to invalidate

  • Extract key generation into shared methods. If your reads and writes build keys differently, you'll get stale data

The Backend Lowdown: Book Update

Chapter 4 is almost here! With it, The Backend Lowdown will pass 100 pages - a milestone I honestly didn’t imagine hitting when I first started writing.

With this release, the minimum price will shift from $1+ PWYW to $5+ PWYW. This new floor simply reflects how much the book has grown and the value it now provides at over 100 pages, while still keeping it affordable and flexible.

Thank you so much to everyone who’s purchased, shared, or left a review or even a comment on a video about it so far. Your support has turned this from a side project into something real, and I’m excited to keep building it with you.

Dev Tool Recommendations: CLI Showdown

This week I did a video recommending 3 new CLI tools which I thought I’d highlight here for those who missed it:

  • Hyperfine - a CLI tool for doing some micro-benchmarking on commands

Benchmarking jq vs fx

  • Oha - a CLI tool for doing some quick load testing. This comes with tui animation which I love

Look at those sweet, sweet tui animations

  • Toxiproxy - A TCP proxy to simulate network and system conditions for chaos and resiliency testing. I didn’t get a chance to demo this one, but it would be awesome to use this to simulate a bad network between your app and Postgres

Using toxiproxy to simulate a bad network between your app and Postgres

That’s a wrap for this week. If something here made your day smoother, feel free to reply and tell me about it. And if you think a friend or teammate would enjoy this too, I’d be grateful if you shared it with them.

Until next time,
Steven