A small Makefile habit
Whenever I start on a project, mine or somebody else's, the first thing I add is a Makefile with the same handful of targets. It does not matter what the project is written in or which build tool it already uses. The Makefile is not there to replace any of that. It is a front door.
The targets are always the same names: help, setup, check and run. setup installs whatever the project needs, check runs everything that can tell me I broke something, run starts the thing. help is the default, so typing make on its own prints the list instead of doing something I did not ask for.
The help target is the part people copy from me most often, so here it is. Each target gets a comment after two hash marks, and the help target greps for those:
help: ## show this list @grep -E '^[a-z-]+:.*## ' Makefile | sed 's/:.*## /\t/' check: ## lint and tests, the same as the build server runs ./scripts/lint ./scripts/test
That is all of it. There are fancier versions with colours and column alignment. I have used them and gone back, because the plain one is short enough to read in one glance, and a help target that needs explaining has missed the point.
Why bother, when the language already has its own task runner? Because I move between projects a lot, and every one of them has its own idea of how you run the tests. One wants a script in a folder, one wants a command with three flags that someone once wrote down in a wiki page, one has a task runner I have to install first. After a few months away I remember none of it. With the Makefile I only have to remember one word, and the word is the same everywhere.
There is a second, quieter benefit. Writing the check target forces me to find out what checking the project actually means. More than once that has turned up a test suite nobody ran locally any more, or a linter configured in the build server and nowhere else. Putting it behind one name makes the gap visible, and usually it gets closed the same afternoon.
I try to keep the Makefile dull. No logic beyond calling other things, no variables unless they save real repetition, no clever pattern rules. If a target grows past a few lines, the lines move into a script with a proper name, and the Makefile calls the script. The file should read like a table of contents.
Colleagues have occasionally removed it, and that is fine. It costs ten minutes to write and it pays for itself the first time I come back to the project after a long gap and type four letters instead of searching old messages for the right incantation.