Topics / Engineering practice

A language migration changes more than syntax.

Preserve the behaviors customers depend on by checking boundary semantics, error behavior and durable effects across both implementations.

Inventory the semantic differences that can matter.

Numbers, string handling, ordering, concurrency and error propagation can differ across implementations. Select the relevant boundaries for your system instead of assuming a successful translation preserves the contract.

Illustrative example

The same integer takes a different path.

A migration changes how an oversized value is parsed. The old service rejects it; the replacement wraps or rounds it. Happy-path examples match. An explicit input-range requirement and boundary corpus reveal the difference before deployment.

Compare behavior at stable boundaries.

BoundaryCompare
APIResponses, error codes and documented ordering
PersistenceStored values, identity and transaction effects
ConcurrencyAllowed interleavings and duplicate handling
Failure recoveryRestart, timeout and partial-result behavior

Run the same declared inputs against identified versions. Keep a record of normalizations and intended differences. If no owner can decide which result is right, the migration has an intent question to resolve.

Retain a migration agreement.

Proof’s requirements and mirror records can organize parity obligations, implementation links and open gaps. Tests and other verification still need to produce evidence for each material claim.

Move one bounded component first. Define rollout observations and rollback conditions with the operating team. Passing a comparison corpus supports that scope; it does not establish that every production behavior is equivalent.

Try it on your software

Choose one boundary for a migration pilot.

Bring both implementations and the behaviors that would be costly to lose.