Let's talk
product

Why a 57-screen rebuild split seven ways would not fit

Every contract bug in the project had been between contributors, not inside one. So the mobile rebuild began by turning those disagreements into build failures.

· · updated

Two steel beams bolted together at a joint on a construction frame.

You have a mobile app to rebuild against a completely different backend: fifty-seven screens, a different data model, a different authentication scheme. The obvious way to hit the date is to split it across seven parallel workstreams. It is also how you produce seven halves of an app that do not fit, and you find out when they are put together, in the week you meant to ship.

The evidence 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 with a narrower question than how to divide the work: which disagreements are possible, and which of them can be made into build failures?

What was actually going on

Dividing work by screen puts the risk at the seams. A screen calls an endpoint, a link points at a screen somebody else owns, two people add the same thing to the same file. None of those is a mistake in anyone’s own code, and none shows up until the pieces meet.

What we changed

Three foundations were built before anyone else started.

The interface was generated, not agreed. The whole API layer, request functions and types, was produced from the server’s own live schema: ninety-six operations and a hundred and fifty-four types. Nobody writes a call by hand, so nobody can call an endpoint that does not exist or misspell a field. Whether a button points 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. The router uses typed routes, so a link to a screen that does not exist yet fails to compile, and a half-built router would have meant turning that check off for the whole rebuild. Contributors filled files rather than creating them, so no two could disagree about where a screen lives or what it is called.

The parts that cannot be shared went first, to one person. One migration, the device authentication module, and the single function that awards points so that no call site writes to the ledger directly. Routers were pre-registered in the application’s entry point so nobody else had to touch that file.

The old implementation was removed at the same time: sixteen thousand lines across a hundred and sixty-five files, deleted rather than kept as reference, because leftover code is the most reliable source of a contributor copying a pattern that no longer applies.

What it did not fix

The foundation did not catch everything, and the misses have a pattern.

The test runner had no mapping for the project’s import alias. Every workstream’s tests passed on their own, and five suites broke the moment aliased imports crossed a feature boundary, which is the moment the work was combined. I had thought of the foundation as production code, and test configuration belonged in it.

One workstream built a pairing QR code to emit a deep-link URL, as the design document specified. The scanner, already shipped by another workstream, treats whatever it reads as the literal code, with no URL parsing. Every real scan would have failed. Someone reading the other side’s landed code caught it, not the plan. When two pieces of work meet, the contract is whichever one is already in the repository.

Two workstreams hit the same lint rule in the same round and solved it identically and independently. That belongs in the foundation. And some of my own foundation was wrong: I laid down the child-side shell as a plain stack because I believed none of those screens had a navigation bar. Five of them do.

A screenshot harness photographed the same screen twenty-eight times, because the routing groups screens in a way that does not appear in the URL. Twenty-eight correctly named files looked like coverage. It now hashes every capture and fails on duplicates, which also caught twenty-nine empty files when a second device was connected.

What to ask your own team or supplier

  • If our rebuild is divided among several people, which disagreements between them become build failures, and which wait for a human to notice?
  • Is the interface between front end and server generated from the server, or written by hand on both sides?
  • What is shared infrastructure here, including test configuration and the evidence tooling, not just production code?
  • When two workstreams meet, is the contract taken from the plan or from the code already merged?
  • Can the tool that produces evidence, such as screenshots, fail, and how?

Where this ends up

The same question decides how a team is set up, not just how one rebuild is split: which disagreements are possible, and which of them can be turned into a build failure. How an ODC works here describes how one is scoped and ramped, which is that question at a different scale.

Working on something like this?

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

Get in touch