Home

Feature Design with Mitchell Hashimoto

Welcome to my nineteenth post in the Advent of Writing series.

Today Mitchell Hashimoto posted on Twitter/X a 17 minute video on “feature design”, or rather, the lack of it. The core idea is that feature design is the “planning step behind how you’re going to solve one or more user problems with a product feature”. It’s explicitly not visual or architectural design.

I watched the video, found it brilliant, and want to share it more widely. That’s why I’ll try to condense it into a short post with the key points and add my own thoughts and commentary. You should still watch the original video, don’t think of this as a replacement, but rather a complement to it.

Ketchup and Ice-Cream

When I was a kid or teenager, someone taught me about the ketchup and ice-cream compromise. One kid wants to eat ketchup and the other one wants to eat ice-cream, so both get ice-cream with ketchup. A combo that, unsurprisingly, no one likes. Unfortunately, this is what a lot of products look like without feature design.

And this is also the first point that Mitchell makes, using two feature requests for Ghostty. Users wanted a dedicated “copy mode” (Vim-like selection and copying) and Vim-like navigation (e.g., hjkl keys for moving around). As he says, the naïve approach would be to go ahead and implement these features separately. After all, users requested them. If you do this, you should stop, take a break, and take a step back.

We don’t want to eat ketchup with ice-cream.

Instead, we should figure out if there’s a way to solve both of the underlying problems those two users have with a more general approach that fits into the product more natively. In Mitchell’s case, he designed “key tables”—named sets of key bindings that act like switchable scopes or modes. This solves both requests generically, allows users to define their own modes, and sets the stage for future features like chained keybinds. Maybe there is such a unifying solution; maybe there isn’t. But it’s worth looking for.

And importantly, you shouldn’t expect users to be able to figure this out. Users won’t have a holistic understanding of your application or of other users’ requests. It’s up to you to look for patterns and opportunities to solve multiple related problems with one underlying system.

What does good feel like?

Once you have an understanding of 1) what needs to be solved and 2) what’s the general approach to solve it, it’s time to play around. Mitchell uses the example of doodling a configuration syntax for Ghostty in a throwaway file. But you should apply this to whatever is the relevant place for you: mock your UI, quickly prototype a rough interface in code, sketch out function skeletons without implementing them, and write some code where you’re pretending to call them. Whatever the correct playground is for you.

The key point is that humans interact with software emotionally; good design evokes positive feelings. So keep on doodling until it makes you feel good.

I’d optimize for quick iterations and focus on having an environment where you can throw stuff away fast and recreate it from scratch. Also, as Mitchell points out, just because it feels good doesn’t mean the feature makes sense yet. And it’s easy to confuse the two.

Cohesive integration

At this stage it’s tempting to say: “I’ve got it.” I know what this should look and feel like. I have a doodle that feels good, let’s implement it. But this is the crucial place to hold your horses. Not yet.

The key question now is: how does this fit in the big picture? The example Mitchell brings up in Ghostty is a new way to configure keybindings for reusable key tables. And Ghostty already has a whole section and way to configure keybindings; so how does the newly proposed feature fit the existing keybindings?

Similarly you could think of a product where you can configure dark/light mode, but now you introduce completely new themes. So are themes a separate thing, each with a light and dark mode implementation, or are light and dark modes themselves themes, just like any other?

Or maybe your new feature is a completely novel thing that doesn’t fit with anything you have so far.

Whichever it is, it’s crucial to integrate the feature smoothly. The last thing you want is to have made all this effort, only to slap the feature in a place where no one finds it, where it doesn’t make sense, or even worse where it contradicts the current way of using your product.

It’s easy to kill a good, well-made feature by putting it in an awkward spot.

Implementation time

Finally we get to the part that we as engineers know and love: implementation. What’s the technical spec, what database do we use, which algorithm is best here? This is the place we’re comfortable with and the space we know how to navigate.

No feelings or emotions to evaluate, just execute and use good judgement. I won’t put much thought here, since I think many find this place easy to work in.

But two important things to note:

  • This stage isn’t trivial. Just because it’s the one engineers are most familiar with doesn’t mean you can handwave it. Good technical implementation still matters, and failing here can easily kill the feature.
  • Implementation details are conditioned on every previous step. If you happen to change your view in one of the previous steps, you might need to revise.

A few good tips that Mitchell also mentions:

  • Write out the design: Writing isn’t just documentation, it’s a forcing function for clarity. It forces you to take a breath, reveals flaws, and uncovers overlooked edge cases or incompatibilities with planned features (like how key tables interact with upcoming chained keybinds). Do it.
  • Use AI as a rubber duck: It’s a solid way to double-check your logic and have it play devil’s advocate. But remember, you can’t outsource your judgement and cirtical thinking.

Last touch

Finally, I think this is something you have to practice a lot to become good at. And I try to practice it myself every time I get an opportunity. The difficult part is that feedback is sparse and unclear. Once you implement a feature, you won’t automatically know if your process led to a good decision. You have to set that system up: qualitative user feedback, revenue metrics, usage statistics. Whatever metric is relevant for your case. And it might take a long time before you actually receive any real signal. Try to pull that feedback forward as much as possible.

For Mitchell, this stuff is second nature, as he mentions, but it comes from years and years of practice.

So if there’s any takeaway from this blog and video, it’s that you should get into real scenarios as much as possible and practice building things that truly solve people’s problems. There’s no shortcut to learning that.

Huge thanks to Mitchell for making the video.