MAKE IT.
BREAK IT ON PURPOSE.
Three modest projects with real code and deliberately missing rules. The errors are pedagogical, not claims that a particular AI model wrote them.
Number Desk: zero is not blank.
Scenario: a visitor needs to add two numbers from a phone. The initial app accepts two number fields and announces the result.
The invisible problem
JavaScript has the unintuitive rule Number('') === 0. If your code converts a blank input directly, a missing number becomes a real quantity. The interface reports success even though the user has not completed the task.
// Before: the empty string is silently coerced.
const total = Number(first.value) + Number(second.value);
// After: blank and zero receive different treatment.
if (first.value.trim() === '' || second.value.trim() === '') {
status.textContent = 'Enter both numbers.';
return;
}
const total = Number(first.value) + Number(second.value);Three necessary checks
- Enter 2 and 3: expect 5.
- Leave one input empty: expect an error, not a plausible answer.
- Operate the form using only a keyboard and confirm the result is announced.
Transfer lesson: never let a coercion rule silently define the business meaning of missing data.
PRACTISE IN THE WORKSHOP ↗Show & Tell: absence needs a label.
Scenario: three local portfolio items are filterable by text. The first version removes unmatched cards but has no recovery message. A visitor searches for “banana”; the empty panel looks broken.
What changed
The repaired version uses an explicitly labelled search and a visible, live-announced message explaining that no projects matched. The message recommends editing or clearing the query. A “zero results” interface can still be a complete interaction.
// After filtering: list.replaceChildren(...matchingCards); emptyMessage.hidden = matchingCards.length !== 0; // HTML: <p id="emptyMessage" role="status" hidden> // No matches. Clear the filter and try again. // </p>
Three necessary checks
- Search “design”: see the design project.
- Search an impossible term: see a helpful empty state.
- Clear the search: the full collection returns and focus stays where expected.
Transfer lesson: every empty state is a piece of product writing and an accessibility decision, not just an absence of content.
Kirana Counter: invalid lines still add up to trouble.
Scenario: a tiny neighbourhood shop records item, quantity and unit price. The first version accepts zero units; a line appears in the record although it represents no sale.
The rule belongs in the model
The repaired version requires a nonempty item name, a positive whole-number quantity and a finite nonnegative unit price. This is a worked example of domain logic: code can be syntactically valid while violating the world's actual rules.
// A few examples of an explicit domain rule:
const validQty = Number.isInteger(qty) && qty > 0;
const validPrice = Number.isFinite(unit) && unit >= 0;
if (!item.trim() || !validQty || !validPrice) {
message.textContent = 'Check item, quantity and price.';
return;
}Three necessary checks
- Add 2 units priced at ₹15: total rises by ₹30.
- Try quantity zero: receive an error and no new line.
- Reload the page: confirm the demo has no persistent customer or sales data.
Transfer lesson: input types and HTML hints do not replace the application rules. Real shop systems need additional safeguards, persistence decisions and data backup.
YOUR TURN TO SHIP A SMALL THING.
Every case has a real, inspectable and exportable starter. Learn what was changed before trusting the result.