In the morning the study of Mosaic’s shape gave the apps rooms of their own, told in “separate rooms”. By the evening the rooms had walls.

an error, not a habit

The idea stays the one Selim gave it: one house, separate rooms. One repo and one deploy, because more of them would cost more, but each app in a place of its own, so an agent working on one app reads and touches only that app.

Until today the rooms were a convention. A test could catch an app reaching into another, after the fact. Now each of the backend’s fourteen apps is a module of its own, and each compiles against a shared platform only. Reaching into another app is no longer something a reviewer has to notice: the compiler says no.

The backend after step 6: the platform underneath, an app per module, a boot module on top, and nothing at the root but shared setup.

The backend after step 6: the platform underneath, an app per module, a boot module on top, and nothing at the root but shared setup.

the first room could not move alone

The plan was to move one quiet app first. It could not move: every app leaned on the shared layer that talks to the databases, so the platform had to become a module before any app could. Then the apps went, one pull request at a time for the first four, each through the dev site and then the real one. After four apps at ten minutes of deploys each, the thread changed pace and sent the other nine together, one commit per app, so each can still be taken back on its own. Last, the boot itself moved out of the root. The root is now just the hallway.

green tests, red prod

On the way, a break nobody’s tests had seen. After the platform’s move every check was green, yet the real site answered errors on every address that carries an id, for about forty-five minutes. The build plugin keeps the names of parameters only for the project it is applied to, and the new modules had quietly lost them; the framework needs those names to read an id out of an address. The language app’s tests were the first to fail on it locally, which sent the thread to the server’s logs, where the error had been showing since the deploy. The fix was one line in the build, plus a test that keeps it.

The lesson shaped the next thread, which finished the move: before shipping, start the real jar and call an address with an id in it. Three threads carried the backend’s step in one afternoon, each handing the next its task written down as a prompt.

checks that build only what changed

The backend had no automatic check on GitHub at all. Now a pull request builds and tests only the modules its files touch, plus the modules that depend on them; a change to the platform builds everything; a change to docs builds nothing. Build minutes are limited, and the split only pays off if a change to Todarch stops building the language app.

Two tests every thread had been stepping around as known failures were fixed first: a snapshot that went stale each time the company hired a role, and a test with yesterday’s date written into it. A check that is red on its first day teaches everyone to ignore it. Selim’s whole go-ahead was “Yes, it works, continue.”

the front end follows

The front end did the same in the same order. Cube design’s own screens moved first into a library inside the same workspace, still one build and one deploy, seen by the shell only by its name. A lint rule stops any app from importing another. One surprise: with two projects in the workspace, a bare test command quietly ran the library instead of the app, so every command now names its app.

Then a script moved the rest, two apps at a time and then in batches, until all thirteen were libraries. Langle, the language app, hid one more knot: the sign-in checked the key through the language app’s own service, so the shell depended on an app. It was turned around, the shell owning its own call. Last came the shell’s own pieces, which leaned on each other in three places; those edges were cut, and lint keeps them cut. The app folder now holds only the shell’s front door.