Let's talk
engineering

Fifty-seven screens do not divide into seven workers without a foundation

The mobile app had to be rebuilt against a completely different backend: fifty-seven screens, a different data model, a different authentication scheme. Splitting that across seven parallel workstreams is the obvious move and it is how you produce seven incompatible halves of an app.

The evidence for that was already in the project’s own history. Every contract bug up to that point — and there had been a run of them — was between two contributors rather than inside one contributor’s work. Nobody’s own code was wrong. The disagreements were all about the shape of the thing in the middle.

So the rebuild started by asking a narrower question than “how do we divide the work”. It asked: which disagreements are possible, and which of those can be made into build failures?

Three foundations, built before anyone else started

The interface was generated, not agreed. The entire API layer — request functions and types — was produced from the server’s own live schema: ninety-six operations, a hundred and fifty-four types. Nobody writes a call by hand, so nobody can call an endpoint that does not exist, misspell a field, or invent a shape. “Is this button pointing at the right endpoint?” stopped being a review question and became a compile error.

Every file was laid down before any file was filled. All forty-seven routes and every layout were created as stubs first. Partly this was forced: the router uses typed routes, and a link to a screen that does not exist yet fails to compile — so a half-built router would have meant turning that check off for the whole rebuild, which is exactly when you need it most. But the second effect mattered more. Contributors filled files rather than creating them, which means no two of them could disagree about where a screen lives or what it is called. A whole category of merge conflict simply had no way to occur.

The unparallelisable parts were done first, by one person. One migration. The device authentication module. The single function that awards points, so that no call site anywhere ever writes to the ledger directly. Routers pre-registered in the application’s entry point so nobody else had to touch that file. These are the things where two people working carefully still produce a mess, because the file is a single point of coordination.

The demolition happened at the same time: sixteen thousand lines and a hundred and sixty-five files of the old implementation removed outright, rather than left as a reference. Leftover code from the previous architecture is the most reliable source of a contributor copying a pattern that no longer applies.

Where it still went wrong

Worth listing, because the foundation did not catch everything and the misses have a pattern.

The test harness was not part of the foundation, and should have been. The test runner had no mapping for the project’s import alias. Every workstream’s tests passed on their own, because within one feature directory the imports resolved. Five suites broke the moment aliased imports crossed a feature boundary, which is to say the moment the work was combined.

That is the exact failure mode the whole approach was designed to prevent, and it slipped through because I had thought of the shared foundation as production code. Anything that behaves differently when you run one unit versus all of them is shared infrastructure, and test configuration is at the top of that list.

A cross-workstream contract was read from the plan instead of from the code. One workstream built a pairing QR to emit a deep-link URL, as the design document specified. Another workstream had already shipped the scanner, and the scanner treats whatever it reads as the literal code, with no URL parsing at all. Every real scan would have failed.

It was caught by someone reading the other side’s landed code rather than the plan. That is now the rule I would state: when two pieces of work meet, the contract is whichever one is already in the repository, not whichever one is in the document. Plans describe intent. Code describes behaviour, and behaviour is what the user gets.

Two workstreams hit the identical lint rule in the same round and solved it identically and independently. Not a bug, but a useful signal: when two contributors independently hit the same obstacle, that obstacle belongs in the foundation, because everyone after them will hit it too.

Some of my own foundation was wrong. I laid down the child-side shell as a plain stack, on the stated basis that none of those screens has a navigation bar. Five of them do, and those five are the tabs. A foundation error is more expensive than a leaf error because everyone builds on top of it before anyone questions it.

The verification harness needed the same treatment

One more, because it is the same idea applied to evidence rather than code.

A screenshot harness was set up to capture every screen for review. It photographed the same screen twenty-eight times, because the routing scheme groups screens in a way that does not appear in the URL — so twenty-eight distinct routes resolved to one address, and the harness dutifully captured whatever was on screen.

Twenty-eight files, correctly named, all showing the same thing. It looked like coverage.

The harness now hashes every capture and fails the run on duplicates. A tool that produces evidence needs a way to fail, and “produced the expected number of files” is not it. The same harness later returned twenty-nine empty files when a second device was connected and the capture command became ambiguous, and again the only tell was the duplicate check.

What I would keep and what I would change

I would keep all of it. The generated interface removed a class of bug so thoroughly that I cannot give a count for it, which is the nature of prevented bugs.

What I would change is the definition of “foundation”. I had it as: shared code, shared schema, shared file layout. It should be: anything whose absence produces a result that differs between working alone and working together. Test configuration, lint rules, the evidence harness and the document-versus-code precedence rule all belong in it, and none of them were in mine.

Working on something like this?

We build this kind of software, and we staff the teams that do.

Get in touch