~ $ cd teaching && cat README.md
The post comes first.
Then the test.
Then the code.
Six autumns, 2017 to 2022, of a fourth-year course at the Tecnocampus in Mataró: Laboratori de Software 2. Teams — of three at first, of five give or take one later — each with its own repository and its own game to build: an adventure game, then planets, then cards, then cities, then cards again. And a term to build it in, the way software is built: a small piece at a time, on a branch, through a pull request, with a test.
It was one of three subjects I designed from scratch there, between 2017 and 2023, alongside Enginyeria del Software III and Arquitectura de Serveis — with a first-year lab, a front-end course and final-project tutoring around them. It is the one I built the most for.
The games are the students'. What is mine is what they stood on.
A post is a test
Before writing code, a student writes a post: a markdown file with a title, a writer, and a list of steps.
* Go to the blog section,
* You should see a list of posts,
* The last post title should be "Hello Blog", this post
The template reads the post and writes the tests — one in Java for the server, one in JavaScript for the client — with one call per step, in the order written: context.goToTheBlogSection(), then context.theLastPostTitleShouldBeSThisPost("Hello Blog"). Those methods do not exist yet. Writing them is the work. The generated test carries the post's checksum, so a post edited after the fact fails until the tests are made again; the file the student fills in is written once and never overwritten.
If that sounds like BDD, it is — reinvented so that the specification is a blog post the team wanted to write anyway, in their own words rather than in Gherkin's, and compiled into the tests rather than interpreted at run time.
One rule, enforced in code: the writer of a post cannot be the coder who implements it. And the compiler read the steps and refused the vague ones. Every post had to have at least one step with should in it, and to end on one. A step could not say given and should at once. A step with there is, has or needs in it had to say which it was, setup or assertion, or it was sent back. Every refusal said what it had found, what it had expected, and what to do about it.
That makes it a harness, in the sense the word has since taken for working with a coding agent: it did not write the code, it made sure the specification was one a machine could hold you to, and it told you plainly when it was not. The same guidance would do an AI good today.
The server answers once
The server is implemented first. While its test runs, every request the test makes and every answer it gets is recorded — and saved only when the test passes. The client's test for the same post then replays the recording: the same steps, the same calls, in the same order, without a server running. The client is tested against what the server actually said. Ask for something the server was never asked and the test stops, with a diff of the two requests.
The error messages were written for people meeting this for the first time:
Did you run the backend tests before the frontend tests?
From 2019 the posts were executed as tests, by an interpreter that read them at run time. From 2022 they were compiled. The same idea, three generations of it.
The week is the unit
One small post at a time — better little, simple and clear, the first day's slide said, and then showed a post that tried to do too much, with the seven questions it left unanswered. The grade was computed week by week and capped, so a burst at the end could not stand in for cadence. Roles rotated every week, and every student did both the server and the client of the same pull request.
The exam is the same thing, alone
At the start of the term a team took a week over one feature. At the exam each student had three, alone, in one sitting: the post first, then the code, with the commit messages prescribed so that the order could be checked. In 2022 every student got a different pairing of scenarios — ninety-four permutations for forty-eight people — and the repositories were harvested every ten minutes throughout, ten times, so the grade could see when each thing happened as well as whether it worked.
From a post to production
On every push and every pull request, the repository compiled the posts into tests, ran the Java suite, ran the JavaScript suite with coverage, refused any line left uncovered, and built both. The pipeline itself is ordinary; what it runs is not. Until 2021 the week's release manager deployed to Heroku with a script that would not push until both suites had passed. In 2022 there was no release environment, and the first day's slide said so.
Reading the repository
Grades did not come from a form. In 2019 and 2020 a dashboard over the GitHub GraphQL API scored each student by role — posts written, pull requests opened, reviews given, merges made, server, client, coverage — and showed each team its own numbers. In 2022 the grader read the git history itself, and wrote one page per student and one per team, week by week. It was written five times in six years, from a GitHub client in 2017 to a reader of git history in 2022, and the last one is the one I would keep.
The 2021 and 2022 templates are public: classroom--cities-game--2021 and classroom--cards-game--2022.