Reading Breaking Change Guides
5 exercises — read a realistic v2-to-v3 migration guide with before/after code examples, manual steps, a codemod, and a silent breaking change. Understand what must change, why it changed, and how to verify the migration.
Reading migration guides: a structured approach
- Before / After → identify exactly what code must change at each call site
- Manual step required → automation cannot do this; it needs human judgment
- Silent ignore / no warning → the most dangerous pattern — test the behaviour, not just the code
- Codemod → an automated script that transforms matching code patterns
- Verify after migration → run the compatibility checker before deploying
0 / 5 completed
1 / 5
Migration Guide — @acme/forms v2 to v3
# Migration Guide: @acme/forms v2 to v3
Minimum required version: Node.js 18, TypeScript 5.0
This guide covers breaking changes introduced in @acme/forms v3.0.0.
Complete all steps before upgrading in production.
---
## 1. Form.submit() now requires explicit validation
BEFORE (v2.x):
form.submit(); // validation ran silently and errors were logged to console
AFTER (v3.x):
const result = await form.validate();
if (!result.valid) {
showErrors(result.errors);
return;
}
await form.submit();
Why: Silent validation failures caused data integrity issues in production.
Explicit validation gives callers control over error presentation.
---
## 2. Field names are now case-sensitive
BEFORE (v2.x):
form.getField('Email') // matched 'email', 'EMAIL', 'Email' — case-insensitive
AFTER (v3.x):
form.getField('email') // must match exactly; 'Email' throws FieldNotFoundError
Manual step required: Audit all getField() calls and ensure field names match
the case used when the field was registered. Run: npx @acme/forms-codemod v3
---
## 3. The "submit" event payload changed
BEFORE (v2.x):
form.on('submit', (data) => { console.log(data.values); });
AFTER (v3.x):
form.on('submit', ({ values, metadata }) => {
console.log(values);
console.log(metadata.submittedAt); // new: ISO timestamp
});
Why: The flattened payload made it impossible to add metadata without a
breaking change. The new structure is extensible.
---
## 4. Config option renamed
v2: new Form({ validateOnBlur: true })
v3: new Form({ validation: { trigger: 'blur' } })
The old option is silently ignored in v3 — no runtime error, no warning.
---
## Verification
After migration, run the official compatibility checker:
npx @acme/forms-check --version=3 According to section 1, what is wrong with the v2 approach to form submission, and how does v3 fix it?
Silent validation → explicit validation with caller-controlled error handling:
The migration guide states: "validation ran silently and errors were logged to console" in v2, which "caused data integrity issues in production." In v3, validation is a separate, explicit step that must be called first.
Why silent failures are dangerous in production:
If a form could be submitted despite validation errors (because the error was only logged to the console, not surfaced to the user), real invalid data could reach the database or downstream services. Developers would not notice during development — console logs are visible — but end users would not see any error message and the form would submit garbage data.
The v3 pattern teaches explicit error handling:
The migration guide states: "validation ran silently and errors were logged to console" in v2, which "caused data integrity issues in production." In v3, validation is a separate, explicit step that must be called first.
Why silent failures are dangerous in production:
If a form could be submitted despite validation errors (because the error was only logged to the console, not surfaced to the user), real invalid data could reach the database or downstream services. Developers would not notice during development — console logs are visible — but end users would not see any error message and the form would submit garbage data.
The v3 pattern teaches explicit error handling:
const result = await form.validate()→ runs validation, returns result objectresult.valid→ boolean: did all validations pass?result.errors→ array of validation errors if invalidshowErrors(result.errors)→ the caller decides how to display errors (toast, inline, modal)await form.submit()→ only called after confirmed valid