Blog

Thoughts on software engineering, web development, and technology

S
Sam Lee

The Weekly Score That Landed One Column Early

Weekly numbers imported from QuickBooks showed up one column early. Our app files a week under the Sunday after it, so the fix was to shift the date right where the data comes in.

Jul 09, 2026·.NET
S
Sam Lee

When a Bulk Import Only Half Works

A bulk import can fully work, partly fail, fully fail, or never answer at all. Keeping one result per item, and treating a missing result as a failure, made it manageable.

Jul 06, 2026·TypeScript
S
Sam Lee

Why localhost Broke My Local Redis

On my Mac, localhost turned into the IPv6 address first, but Docker only exposed Redis on IPv4. Pointing the local Redis connection strings at 127.0.0.1 fixed it.

Jun 22, 2026·Redis
S
Sam Lee

From Hotwire to MobX

Hotwire sends HTML from the server, while a React + MobX app keeps state in the browser and gets only data. Here's what replaces each Hotwire habit.

May 25, 2026·MobX
S
Sam Lee

What My Rails Instincts Got Wrong About NHibernate

Five Rails habits point the wrong way on a .NET backend that uses NHibernate. Here's what each one gets wrong and what to do instead.

May 11, 2026·NHibernate
S
Sam Lee

When Your SDK Does Too Much (And Not Enough)

Refactored a shared API client gem to separate payload signing from HTTP transport, added Faraday with retry and rate-limiting, and built backward compatibility into the breaking change so existing callers keep working during migration.

Apr 03, 2026·SDK Design
S
Sam Lee

When Turbo Stream Replace Kills Your Search Input

Every keystroke in a search bar was resetting the cursor because one big Turbo Stream replace was swapping the entire container — including the input. Splitting the stream into targeted update and replace actions for metrics and table separately fixed it.

Mar 30, 2026·Hotwire
S
Sam Lee

The Unbounded Query That Took Down an Endpoint

An endpoint was loading every row in a table because the controller used Model.all instead of scoping by the profile parameter already in the URL. Scoping the query, eager loading, and handling orphaned attachments and a Turbo Frame mismatch brought it from 228 queries and 504 timeouts to 30 queries and fast loads.

Mar 25, 2026·Ruby on Rails
S
Sam Lee

The N+1 That Was Hiding Next to Its Own Fix

The dashboard fired about 48 queries per load—one per active subscription. The batch preloader and resolver logic already existed 15 lines away for a sibling feature. Wiring the same pattern and fixing missing-hash keys dropped it to one query.

Mar 19, 2026·Ruby on Rails
S
Sam Lee

Why EXISTS Beats JOIN When You Just Need to Filter

Was JOINing a table just to filter by it, which created duplicate rows and needed DISTINCT. Switched to EXISTS — no extra rows, no deduplication, and moved N+1 lookups into a single SQL subselect.

Mar 18, 2026·SQL

Built by Sam Lee with

 ♥