Exercise 3: Splitting User.name — Possible Solution ===================================================== Release plan 1. Expand firstName String? lastName String? SQL: ALTER TABLE "User" ADD COLUMN "firstName" TEXT, ADD COLUMN "lastName" TEXT; 2. Dual write One function builds all three fields, used by every write: function nameFields(first: string, last: string) { return { firstName: first, lastName: last, name: [first, last].filter(Boolean).join(" ") }; } 3. Backfill (re-runnable) UPDATE "User" SET "firstName" = split_part(trim("name"), ' ', 1), "lastName" = NULLIF(trim(substr(trim("name"), length(split_part(trim("name"), ' ', 1)) + 1)), '') WHERE "firstName" IS NULL AND "name" IS NOT NULL; (Everything before the first space becomes firstName; the rest, if any, becomes lastName.) 4. Switch reads — display code uses firstName/lastName. Both stay OPTIONAL: name was optional, and not everyone has two names. 5. Stop writing name. 6. Contract — drop "name". Where this is harder than the status change - The mapping isn't exact. published -> status was a perfect rule; splitting names is a guess. "Mary Ann Smith", "Ludwig van Beethoven", single names ("Cher"), names written family-name-first, and names without spaces all split wrongly or ambiguously. The backfill produces a best effort, not the truth. - It loses information you can't recover. Once name is dropped, the original spelling and order are gone. Keep a backup (or a copy column) until users have checked their details. - Users should confirm the result. A good plan adds a "please check your name" prompt in the app rather than trusting the split. - It's worth questioning the change itself. Many systems keep one full-name field (plus perhaps a "preferred name") precisely because first/last splits don't fit every culture. WHY THIS WORKS AS AN ANSWER ------------------------------ The same six releases keep old and new code working at every step, with the dual-write rule in one function and a re-runnable backfill. The answer then goes further than the mechanics: a data migration is only as good as its mapping, and when the mapping is lossy, the safe choices are to keep the original data longer, involve the people the data describes, and reconsider whether the change is needed.