An enterprise software vendor of SAP's shape must replace a logging call used at 2,400 sites across 1,100 files owned by 40 teams. The codemod itself takes an afternoon to write. Sequence the change so it lands once and stays landed.
Show the full answer Hide the answer
The sequence
- Ship the new form and a lint rule in warning mode first. Nothing else in this plan is safe until the old form is machine-detectable, because every later step depends on being able to count what is left.
- Measure branch inventory before scheduling the landing. A 1,100-file commit conflicts with every open branch touching those packages, and conflict probability per branch rises with both files touched and branch age. Land it at the weekly minimum, usually just after a release train closes, and announce a window measured in hours.
- Land the codemod as one commit containing only mechanical edits, with the script committed beside it and a CI job that re-runs the script and asserts an empty diff. That reproducibility check is what makes the change reviewable: nobody reads 1,100 files, and pretending otherwise is the step teams skip.
- Flip the lint from warning to error the same day. Miss this and the old form returns from branches merged after yours, and you run the codemod again every month until someone notices the pattern.
- Add a shim only for paths a rewriter cannot reach, with a dated removal recorded against a named owner.
- Delete the old API after the lint has been at error level for a full release cycle with no new suppressions.
Where it diverges
The 2% that turns an afternoon into three weeks is always the same list: reflection, call sites built from strings, generated code, vendored copies, and files in a language the rewriter does not parse. Enumerate them before step 3, by searching for dynamic construction rather than for the call itself, and hand them out as named work. A codemod that silently skips a file leaves a correctness problem the lint will also miss if the lint shares the parser.
Suppressions are your divergence signal. A rising count of lint suppressions after step 4 means the migration is being worked around rather than finished, and the count is cheap to alert on.
The point of no return
Everything up to step 6 is reversible: the codemod can be reverted, the lint downgraded, the shim kept. Deleting the old API is the irreversible step, and it should be a separate commit on a separate day from anything else.
When not to codemod
If the old form is merely inconsistent rather than wrong, a ratchet beats a campaign: require the new form in new code, convert on touch, and block regression in CI. It costs no conflict storm and no coordination, and it finishes in a year instead of a week.
Codemod when uniformity is load-bearing: the old form is a correctness or security defect, or a type, a lint or a build step depends on there being exactly one form.
What a strong answer adds
Say who pays. A central team that lands the codemod and leaves 40 teams to fix their own conflicts has moved its cost onto them and will be refused next time. The team proposing the change owns the conflict resolution, which is also the argument for keeping the diff purely mechanical, because then the owner can regenerate it rather than merge it.