Back to all notes

Small Tools, Sharp Edges

Why I reach for the smallest tool that can do the job, and the moment that instinct fails.

There is a class of tool I reach for constantly: small, sharp, and single-purpose. ripgrep instead of a search abstraction. A shell pipeline instead of a service. A hundred lines of code instead of a framework. The appeal is real - small tools are fast, legible, and easy to throw away.

But small tools have sharp edges, and I have cut myself on them often enough to have opinions about when the trade is worth it.

Why small wins

A small tool fits in your head. You can read all of it, reason about all of it, and fix all of it. There is no upgrade path to plan and no transitive dependency to audit. For a job you will do once, that is close to ideal.

top-failures.sh
# Count the most common failing endpoints in a day of logs.
rg '"status":5' access.log \
  | jq -r '.path' \
  | sort \
  | uniq -c \
  | sort -rn \
  | head -20

That pipeline is a small program. It is also a liability the moment it becomes load-bearing, because nobody wrote down what it does or what happens when the log format changes.

Where the edges are

  • No contract. Nothing states what the tool promises, so nothing catches it when the promise breaks.
  • Hidden coupling. The script assumes a file, a schema, a working directory - invisibly, until it is wrong.
  • Silent failure. A pipeline that returns nothing looks the same as a pipeline that found nothing.

The rule I use now

Start small. But the moment a tool gets a second consumer, a runbook, or an alert, treat that as a signal. Promote it: give it a test, a name, and an owner. The tool can stay small - the responsibility cannot stay implicit.