Ramblings of an aging IT geek
← Ramblings of an aging IT geek
tooling

a makefile is the readme nobody updates but everybody runs

Why I keep reaching for a plain Makefile on Go, Python and Terraform projects, long after I stopped writing C.

A keyboard lit by a terminal

I haven't compiled a serious C project in years, and I still start nearly every repo with a Makefile. Not for the dependency graph, which is the bit Make was actually built for. For the verbs. make test, make lint, make build, make deploy. It's the one interface that survives the language churn underneath it.

The argument against is real: Make's syntax is from another era, tabs versus spaces will bite you, and the moment you want a real conditional you're shelling out to bash anyway. People reach for Task, or Just, or a scripts/ directory full of bash, and those are all fine. But Make is already on every machine I touch, including the CI runner and the colleague who's never heard of Just, and that ubiquity is worth a lot.

The trick is to keep it dumb. Targets are thin wrappers, the real work lives in the tool:

.PHONY: test lint build

test:
	go test ./...

lint:
	golangci-lint run

build:
	go build -o bin/app ./cmd/app

That's it. Nobody has to remember the flags, nobody greps the CI yaml to find out how the thing is actually built, and a new starter can run make and make test on day one. The Makefile becomes the README section nobody keeps current, except this one runs, so it stays honest.