Leaving memory for a machine
My game's instruction file had a rule against copying the project's numbers. Thirty lines above it, the numbers were copied, and wrong.
by Nicola Sabaini 4 min read Project: ExaWar
On 17 September I reopened the instruction file for ExaWar, the strategy game I build. At the bottom there was a line I had written for myself: the project counts live in one file, and copying them elsewhere only makes them drift.
Thirty lines above, in the same file, it said the project had about 424 Python files and 133 thousand lines, and that the test suite ran 1311 tests.
The real numbers, measured that day, were 471 files, 145 thousand lines, 1690 tests.
The file that forbade copying the counts had the counts copied, a year of work out of date. I had written them myself, in both places.
Every session starts from nothing
I almost always work with a machine beside me, and that machine remembers nothing of last time. It opens the project without knowing what is inside, what has already been tried, what must not be touched.
What it finds written in the repository is the whole difference between one that becomes useful in five minutes and one that takes an hour asking questions I have answered three times already.
The conversation is not memory: it ends when I close the window. The files stay.
It holds for the machine and it holds for me. In six months, on a module I have not touched in a year, I am also someone opening the project without knowing what is inside.
Rules are scars
The ExaWar instruction file has eight invariants, with «do not break these» written above them. None of them came from thinking it through in the abstract.
«Never carry on with red tests» is there because the opposite happened. «Changes to AI behaviour are validated in a direct match» I wrote on 16 September, after half a day lost chasing metrics that were all going up while the opponent got weaker. «Fog of war applies only to what the player sees, never to the AI’s knowledge» guards against a perfectly reasonable change that would make the opponent stupid without anyone deciding to make it stupid.
On NucleoOS, the operating system that runs on a microcontroller, the most important rule is not about code: never send firmware to the device on your own initiative. Build, test on the PC, run the gates. Shipping happens only when I ask for it, because that is the step you do not get back.
A rule with no scar behind it is decoration. Those pile up, nobody reads them, and they bury the four that matter.
Where things go
The other half of the job is stopping memory from becoming a warehouse.
| For | Goes in | Tracked by git |
|---|---|---|
| a rule that holds every time | the instruction file | yes |
| how a system works | the architecture documents | yes |
| how a recurring job is done | a written procedure | yes |
| the project counts | one file only | yes |
| the scrap of one session | an ignored folder | no |
The last row does the dirty work. A script thrown together to fix one thing and then never used again does not get committed: its trace is the commit that applied the change, not the file.
With a machine this counts double. Forty dead scripts around the repository are not just ugly: they are material. They get read, taken as good, imitated, and the next session you find new code modelled on something you abandoned in May.
The part that rots
Rules do not expire. Numbers do, and quickly.
So the counts live in one place and everywhere else carries the pointer, not the copy. Which is exactly the rule I had written, and broke in the same file where I wrote it.
I do not think more discipline fixes that. Having one file to look at when the doubt arrives fixes it, instead of six that say different things: then correcting it costs ten seconds, and you do it.
The machine remembers nothing of last time. Neither do I, after six months. The difference is that I am convinced I do.