Avoid Hasty Caching

Approach caching with caution. In this post, I’d like to describe some important considerations that I think teams should consider before applying a caching solution. I’ve found: Caching is often applied too early. Caching can be a slippery slope. Caching is hard to do right. Often Applied Too Early Caching is often applied too early. It’s wise to try other alternatives first. Here’s an example: suppose we have an order-management system that fetches all the orders, and it’s performing slowly. Should we cache it? ...

May 26, 2026

How to Unabstract an Abstraction

Abstractions in code are easy to add and challenging to remove. Sometimes we feel stuck with them. But the good news is, you can back out of almost any abstraction with the right mindset. Let’s look at an example. A Breaking Abstraction Imagine a currency formatter. function formatPrice(amount) { return `$${amount.toFixed(2)}` } formatPrice(10) // "$10.00" Soon our company decides to launch in Europe. Let’s add that conditional. function formatPrice(amount, currency) { if (currency === "EUR") return `€${amount.toFixed(2)}` return `$${amount.toFixed(2)}` } formatPrice(10) // "$10.00" formatPrice(10, "EUR") // "€10.00" 😊 Hang on; the Czech Republic puts the currency symbol after the monetary amount. I guess we have to add a conditional that supports this: ...

February 1, 2026

Decoupling Design From Engineering

Often, when you work as an engineer on a small team, you don’t have dedicated designers on staff. How can you deliver beautiful, intuitive software without designers? Here’s a trick that helps me: decoupling my design work from my engineering work. Clarification: I Love Designers! Let me start by saying: I love designers! An expert designer is one of the most vital people in an engineering organization. I’m not a designer. Great designers are rare, which is why, for much of my career, I haven’t had one. ...

August 29, 2024

Naive Implementations

A naive implementation is a programming technique that prioritizes imperfect shortcuts for the sake of speed, simplicity, or lack of knowledge. Naive implementation example What is ’naive’? Here’s the dictionary definition: naive (adjective) marked by unaffected simplicity : ARTLESS, INGENUOUS –Merriam-Webster Dictionary Let’s see it in a programming context! A pangram is a sentence that contains all the letters of the alphabet, such as: “The quick brown fox jumps over the lazy dog.” Consider this problem I borrowed from Exercism, asking us to build a function that detects pangrams. We have written a failing test that describes our desired function. ...

June 23, 2022

PostgreSQL Polymorphism

Scenario: you need a database record that can belong to one record or another, but not both. Polymorphism and exclusivity. One approach is to create a polymorphic-style association at the data layer. By doing so, you’ll get data integrity built in, rather than trusting it will be enforced by each tenant at the application layer. Here’s how I’ve solved this problem in the past. The Database Migration This is a PostgreSQL example, but it could be applied to other databases. ...

May 30, 2022

How to Make Renames Easy

Names in software are hard. But what’s worse than a bad name? Sticking with it because you can’t change it. I want us all to be able to effortlessly and fearlessly fix bad names. That’s the topic of this post. Considering a “Bad” Name What’s a bad name? Here’s a contrived, but not production-unrealistic, example: function longName() { if(useLongName) { return `${this.firstName} ${this.lastName}` } else { return this.firstName[0] } } A few issues I can raise with this name: ...

March 22, 2022

Write Better Code by Knowing When Not To Refactor

When I review code, I sometimes request that refactoring changes be removed. Even when I think the changes are objective improvements, and even when they support my personal preferences. My reasoning? Refactors are not free. In this post, I’ll list a few times when I think a refactor is worse than leaving the code unchanged. No automated tests Do you have automated tests? Can you run them? Do you trust them? If you don’t, don’t refactor. ...

August 26, 2021

Augmenting an Object With the Proxy Pattern

Let’s look at the proxy pattern in Ruby. Here’s a Ruby class that claps: class Hands def clap "👏" end end And here’s me using an instance of it to do something surprising. >> 3.times { hands.clap } "👏" "👏" "👏" => 3 >> hands.times_called(:clap) => 3 times_called is not defined in Hands, or any parent of it. So what gives? Did I leave it off the first code block? What’s going on here? I recently learned about and had the opportunity to implement a proxy class. In this post, I’ll share what I learned, showing how hands gets this special behavior. ...

February 26, 2021