How do you decide whether converting a long-lived service's mutable core to immutable values is worth its cost to the teams that own it?
answer
- name the defect you are buying out
- check where those defects concentrate
- price the review tax, not just the code
- a region closeable in one cycle
- cheaper partial moves, then a stop rule
basics
~20 sName a defect class you can count, check it concentrates in that core, price the boundary plus the review tax, scope to a region closeable in one planning cycle, weigh cheaper partial moves, and set a stop rule.
solid answer
~50 sTreat it as an investment with a named return, not a quality crusade. First name the **defect class** you expect to remove - incidents traced to shared editable state, bugs that could not be reproduced from inputs, changes that broke a distant caller - and check it actually concentrates in the region you want to convert. Then price the cost honestly: the boundary and its mapping, the conversions, two shapes during the transition, and the review and onboarding tax while both styles are live. Scope the work to a **region you can close inside one planning cycle**, because benefit arrives per closed region, not per converted file. Compare it against cheaper moves - freezing data at the boundary only, adding invariant checks, confining mutation to one owner - which sometimes capture most of the return. Finally, agree the stop rule and the revert plan before anyone starts.
go deeper
Recall that rewriting working code has a cost paid by everyone who reads it afterwards, so a style change needs a reason you can point at, not just a preference for the new shape.
Explain that the benefit arrives when a region closes, which is why scope is chosen as a boundary you can finish rather than as a percentage of files, and name one cheaper alternative to a full conversion.
Demonstrate the measurement: which defects you counted, where they concentrated, what the transition cost in review time, and what evidence would have told you to stop.
Own the whole bet - the return you are buying, who funds it against who absorbs the tax, the region you can close this cycle, the cheaper alternatives you rejected and why, and the condition under which you revert rather than leave an island.
## Why this is a judgement call and not a best practice There is no general answer to whether a long-lived service should move its core to immutable values, because the cost falls on people and the benefit falls on a specific class of defect. A lead owns the decision because it spends other teams' quarters, changes what every reviewer must know, and can leave the codebase in a worse state than either endpoint if it stalls. The answer an interviewer wants is a decision procedure with a stop rule in it - not an opinion about immutability. ## Name the return before anything else The return has to be something you can count before and after: - **Incidents traced to shared editable state** - two paths holding the same data, one editing it under the other. - **Bugs that could not be reproduced from inputs**, because the answer depended on when something was edited. - **Changes that broke a distant caller** through data reachable from both. - **Time spent in review arguing about whether something can change underneath a call.** Then check *where* those concentrate. If the incidents cluster in the request-handling shell rather than in the computational core, converting the core buys very little, and the honest answer is no. ## Price the cost in the same units | Cost | Falls on | Ends when | |---|---|---| | Boundary and mapping code | The owning team, once per region | The region closes | | Two shapes for one concept | Everyone changing the model | Never, while both persist | | Conversion at each crossing | The runtime and the reader | The crossings are consolidated | | Two conventions in review | Every reviewer | The last region closes | | Learning the new model | Every newcomer | Never, but it shrinks once the map is written | The row that is usually underestimated is the fourth, because it is paid in small amounts by many people and never appears on a plan. ## Scope it so the benefit can actually arrive 1. **Pick a region with a nameable boundary** - a subgraph you could draw a line around and say what crosses it. 2. **Check it can be closed within one planning cycle.** A region that needs three cycles will sit open across two of them, paying both bills with no guarantee. 3. **Start with the region where the counted defects live**, not the easiest one. Easy-first migrations front-load the cost and leave the aliasing-heavy parts unconverted forever. 4. **Define done as a closed boundary**, with no editable shape crossing inward and no defensive re-checking inside. ## Consider the cheaper alternatives honestly Several partial moves capture a large share of the return for a fraction of the cost, and a strong answer names them: - **Freeze at the boundary only**: copy inbound data once, leave the interior as it is. Removes cross-path editing without rewriting the core. - **Single owner for mutation**: keep the editable shape but allow exactly one component to write it, so the question 'who changed this' has one answer. - **Invariant checks at the boundary** so violations are caught where they enter rather than diagnosed later. - **Convert the leaf computations only** - the pricing functions - and leave the orchestration stateful. Often most of the reproducibility win with one thin boundary. If one of these captures most of the counted defects, the full migration is a poor trade and saying so is the senior answer. ## Decide, then bound the decision - **Set a stop rule in advance**: if the first region is not closed by a stated date, the work stops and the region is reverted rather than left as an island. - **Agree who pays** - one team funding it while three teams absorb the review tax is a decision, and it should be made explicitly rather than discovered. - **Write the region map down** on day one, because the mixed state is survivable when the map is written and corrosive when it lives in three people's heads. - **Re-measure the defect class** after the first region closes. If it did not move, the model was wrong and the remaining regions do not deserve the funding the first one got. ## What a weak answer sounds like A weak answer argues from the merits of immutability in the abstract, assumes the migration finishes, and never mentions who absorbs the transition. A strong one names the defect class, points at where it concentrates, prices the transition including the review tax, picks a region it can close, offers the cheaper alternative it considered, and states the condition under which it would stop and revert.
- The counted defects concentrate in the effectful shell rather than the computational core - what does that change?It reverses the plan. Converting the core spends the budget where the incidents are not, so the honest move is to work on the shell: give mutation a single owner, freeze data as it enters, and check invariants at the entry point. The core migration becomes a nice-to-have that has to compete for a later cycle.
- How do you decide who funds the work when the tax falls on other teams?Make the split explicit before starting: the owning team funds the boundary and the conversions, and the other teams absorb review and onboarding while both styles are live. If those teams will not accept that tax for the stated duration, the scope is too large and should be cut to a region whose transition they will tolerate.
- The first region closed and the defect class did not move - what now?Stop and re-examine the model rather than continuing on momentum. Either the defects were not caused by shared editing, or they live elsewhere. Closed regions can stay, since a closed region is a coherent endpoint, but the remaining ones should re-compete for funding against whatever the measurement now suggests.
saying these in an interview costs you the question
- Argues from the merits of immutability without naming a defect class
- Assumes the migration finishes and prices only the finished state
- Ignores the review and onboarding tax paid by other teams
- Starts with the easiest region rather than where the defects concentrate
- Has no stop rule and no plan to revert an unclosable region
- Never considers the cheaper partial moves that capture most of the return