~ $ cd craft && cat README.md
One small step,
and the code
works again.
That is the mantra I try to keep with every change, and the rest of what I hold to grows from it. The links go to where each line runs, here; the numbers, to the essays where I argued it.
In the code
Small, safe steps, always. Not only when testing: it is how I make any change, in steps small enough to check one by one, so that the code is never more than a step away from working: a test that fails is put right before the next step is taken. [1, 2, 3]
A test first, and seen failing. A test that has never failed has not yet shown that it can. At the end of the kata the perfect game passes the moment it is written, so it is made to fail once, and only then gets its 300 back. [1, 2]
A test is an example of use. I write it the way I would explain the code to someone about to use it. Then it survives a refactor, and it catches the bug that the tests looking inside sleep through: an example shows it. [1, 2, 3]
The need comes first, in its own words. A feature starts as the words of whoever needs it — in my course, the post came first — and each sentence becomes a step of its test. [1, 2]
Clean as I go. Before a change, where it will land; while I make it; and once more when it is done, for whoever reads it next. Not as a phase saved for the end, and never by starting again: when the design is wrong, I move the code towards the right one a little with every change. Kent Beck put the first part in one line: make the change easy (warning: this may be hard), then make the easy change. The book is the rest, whole. [1, 2, 3]
To the trunk, small and often. Continuous delivery is small steps for a whole team: every change integrated into the trunk soon after it is made, through a pipeline fast enough that nobody waits for it, so that the code is always releasable — and everyone is working on nearly the same code, as if in a meeting that never interrupts them. When a team integrates too seldom, I look at what is in its way before I look at the team: how often it merges, and what makes merging slow — often the CI, the speed of light of a team, and one that can be changed. This site goes out on every push. [1, 2, 3]
on:
push:
branches: [main]
# …
- run: npm ci
- run: npm run coverage
- run: node tools/architecture-history.mjs
- run: npm run build
I build the tools. When a part of the work can be done by a program, I write the program, so that nothing starts from scratch: a compiler from posts to tests, a reader of Gherkin that names its own steps, graders that read a repository's history, koans, and a game of passing a test in the fewest keystrokes. [1, 2, 3]
With others
Pairing is the better code review. It never stops, I often use it to bring beginners up to speed, and it leaves nobody indispensable — and nobody should be, not even an AI. On the critical parts that all of us will work on later, I would rather we mob, test first. [1, 2, 3]
If they find any problem, it’s been written for only a few seconds; therefore, it can be changed instantly.
Help is a smaller step, not the answer. When someone asks me for help, I often keep the solution to myself and propose trying again in steps so small that the way becomes plain. It looks simple, and it takes practice; that is what katas are for. [1]
Curious before right. In a review I try to understand why the author did it, and ask with genuine curiosity. A comment should block a merge only when the product is at risk; the rest can wait for a later change, or for the whole team, on a Friday. [1, 2]
“Why did you put this variable here?” — or — “I have seen this variable here, I tried to understand how is it here, but I failed, what I am missing?”
Change the environment, not the people. The environment changes us, so a rule that matters goes into the code, where it holds for a person and for an agent alike, rather than into a guide: this site is built that way. And a change to how we work is an experiment, with a date to look back at it together. [1, 2, 3]
The credit is the team's. When a system where every new feature brought new bugs turned around without stopping delivery, it was not me who fixed it: it was my team, working a new way. [1, 2]
The programmer had to separate his ego from the code itself: egoless programming.
Behind it
I started against it. I was a detractor of testing: at meetups everyone showed how, and no one showed why. That began to change when I contributed to AngularJS. So I teach it starting from why — at the Legacy Code Rocks meetup, the talk was Testing: what, how, why? — because it is counterintuitive. In 2017 I told a room of students that doctors have the Hippocratic oath, and we have testing. [1, 2, 3]
Why test code that I know works?
Assume I got it wrong. That, for me, is the essence of agile: leave room to find the mistake and fix it, in the design and in the requirement alike. It takes the cases that fail to tell one rule from another: guess one. [1, 2, 3]
The responsibility stays mine. With an AI, on code I mean to keep, the rhythm is the same: I direct it one step at a time and commit between steps. I ask for the clean step on every cycle, because left alone it forgets the refactor; and I tell it that finding nothing to clean is a correct answer, because pushed, it invents something. When I caught myself letting my assistant do the designing, I switched it off until the design was mine again. [1, 2, 3]
What did the AI do? Add a name = ‘John’ just in case it was empty.
Share what worked. Whoever has something worth sharing should share it: it is what took me to meetups, and what keeps me publishing every Saturday — the essays are gathered by subject. I teach it as well — a recipe for concurrency, a course built on posts that are tests — and say it out loud in talks. [1, 2]
Whoever came to present was presenting something that had actually worked for them.
~/craft $ ls
kata/The kata, one commit at a timeRobert C. Martin's Bowling Game Kata in the commits a student makes, each one run here as you reach it — the rhythm of test, code and clean, the step back to green before the design changes, and the one step I added.a-test-is-an-example/A test is an exampleOne of the first essays I published was about this — a test that reads like the documentation of what it tests survives a refactor, and tests that look inside can pass over a bug. The same tests, run here against three dispatchers.a-sentence-is-a-step/A sentence is a stepIn my course the post came first, and my students got stuck on the expressions that tie each of its sentences to code — so a sentence became the name of its code. The idea, running, and where it went after the course.guess-the-rule/Guess the ruleA rule you cannot see marks sequences of three numbers ✅ or ❌. Test as many as you like, then guess it — the page my old site had in 2020 for my essay on testing and refactoring, played again.architecture@How this site is builtThe source of this site as boxes and arrows, commit by commit — the program an AI wrote, and the rules it is held to.software-lab@The post comes firstSix autumns of Laboratori de Software 2 at Tecnocampus, and the platform built for it — posts in markdown compiled into tests for server and client, the server's answers replayed to the client, and a grader that read the repository.raft@Raft, and a recipe for concurrencyA consensus algorithm as a laboratory assignment in 2013, and the three hints given to simplify it — above all a three-step recipe, simple enough for someone who cannot yet reason about interleavings.