Skip to content
academia.sh

Lesson 25 / 25

Regional Requirements

Counting the assumptions baked into name, address, and identity fields, a flexible field setup that accepts every record, requirements read from a country table, and storing identity fields as text.

Contents

Direction and formatting decisions adapted the interface’s container to the language. What is left is the data that goes inside the container. A library membership form asks for three things: a name, an address, and an identity number. Each of these three fields carries an assumption — that a name has two parts, that an address is completed by a postal code, that an identity number has a fixed length.

The assumptions stay invisible in most records, because most records fit them. A record that does not fit cannot get through the form: the user cannot squeeze their name into one field, cannot leave a required postal code blank, and their identity number is rejected. This lesson counts the assumptions and turns them into rules.

Measuring the Assumption

The computation below runs a strict form — a two-part name field, a required postal code and region, a fixed-length identity number — against sample records and counts how many fail.

// region.mjs — turning name, address, and identity field assumptions into rules

// 1. Name field: a strict form assumes two fields (given name + family name, both required).
const STRICT_NAME = { fields: ["given", "family"], required: ["given", "family"], exact: 2 };
// Records: real-world name structures encountered in practice (real examples, chosen for structural variety).
const NAMES = [
  { record: "A1", parts: ["Elif", "Yılmaz"], note: "two parts" },
  { record: "A2", parts: ["Ravi"], note: "single-part name" },
  { record: "A3", parts: ["María", "del", "Carmen", "Ruiz", "García"], note: "two surnames, multiple given names" },
  { record: "A4", parts: ["Nguyễn", "Thị", "Hoa"], note: "family name first" },
  { record: "A5", parts: ["Björn", "Þórsson"], note: "surname derives from the father's name" },
  { record: "A6", parts: ["Jean", "-", "Pierre", "Le", "Roux"], note: "hyphenated name, multi-word surname" },
];
console.log("record  parts  fits strict form  loss");
let overflow = 0;
for (const n of NAMES) {
  const realParts = n.parts.filter((p) => p !== "-").length;
  const fits = realParts === STRICT_NAME.exact;
  if (!fits) overflow++;
  const loss = fits ? "-" : realParts < 2 ? "required field cannot be left blank" : "extra parts get crammed into one field";
  console.log(`${n.record.padEnd(6)} ${String(realParts).padStart(5)}  ${(fits ? "yes" : "NO").padStart(16)}  ${loss}`);
}
console.log(`does not fit the strict form: ${overflow} / ${NAMES.length}`);

// Flexible rule: one free field + an optional display name.
console.log("\nflexible rule: 'full name' one field (required) + 'display name' (optional)");
for (const n of NAMES) {
  const full = n.parts.join(" ").replace(" - ", "-");
  console.log(`  ${n.record}  full name: ${JSON.stringify(full).padEnd(34)} (${n.note})`);
}

// 2. Address field: a strict form assumes postal code and region/state are required.
const ADDRESSES = [
  { record: "B1", lines: 2, postalCode: "34710", region: "İstanbul", country: "TR" },
  { record: "B2", lines: 3, postalCode: null,    region: "Dublin",   country: "IE" },
  { record: "B3", lines: 1, postalCode: "1010",  region: null,       country: "AT" },
  { record: "B4", lines: 4, postalCode: "100-0001", region: "Tokyo", country: "JP" },
  { record: "B5", lines: 2, postalCode: "SW1A 1AA", region: null,    country: "GB" },
];
const STRICT_ADDRESS = { postalCodeRequired: true, regionRequired: true, lineLimit: 2 };
console.log("\nrecord  lines  postal code  region    rule dropped by the strict form");
let addressDropped = 0;
for (const a of ADDRESSES) {
  const dropped = [];
  if (STRICT_ADDRESS.postalCodeRequired && !a.postalCode) dropped.push("postal code required");
  if (STRICT_ADDRESS.regionRequired && !a.region) dropped.push("region required");
  if (a.lines > STRICT_ADDRESS.lineLimit) dropped.push(`line count ${a.lines} > ${STRICT_ADDRESS.lineLimit}`);
  if (dropped.length) addressDropped++;
  console.log(
    `${a.record.padEnd(6)} ${String(a.lines).padStart(5)}  ${String(a.postalCode ?? "-").padEnd(11)} ${String(a.region ?? "-").padEnd(9)} ${dropped.join("; ") || "-"}`
  );
}
console.log(`records dropped by the strict address form: ${addressDropped} / ${ADDRESSES.length}`);

// 3. Identity field: a length and format assumption.
const IDENTITIES = [
  { record: "C1", value: "12345678901", kind: "11 digits" },
  { record: "C2", value: "AB-9931",     kind: "letter + digit" },
  { record: "C3", value: "0012",        kind: "leading zero" },
  { record: "C4", value: "9987654321234", kind: "13 digits" },
];
const STRICT_IDENTITY = { length: 11, digitsOnly: true };
console.log("\nrecord  value           matches strict rule  reason");
for (const c of IDENTITIES) {
  const lengthOk = c.value.length === STRICT_IDENTITY.length;
  const digitsOk = /^\d+$/.test(c.value);
  const matches = lengthOk && digitsOk;
  const reason = matches ? "-" : [!lengthOk && `length ${c.value.length}`, !digitsOk && "non-digit character"].filter(Boolean).join(", ");
  console.log(`${c.record.padEnd(6)} ${c.value.padEnd(15)} ${(matches ? "yes" : "NO").padStart(20)}  ${reason}`);
}
console.log("if the identity field is stored as a number, leading zeros are lost; the field is text.");

// 4. Result: comparing two form designs.
const recordTotal = NAMES.length + ADDRESSES.length;
const droppedTotal = overflow + addressDropped;
console.log(`\nstrict form: ${droppedTotal} / ${recordTotal} records cannot be entered directly (${Math.round((100 * droppedTotal) / recordTotal)}%)`);
console.log("flexible form: full name one field, address a multi-line free-text field + country,");
console.log("               postal code and region requirements toggle on and off by country.");

// 5. Country-dependent field rule: gathered into a single table.
const COUNTRY_RULE = {
  TR: { postalCode: "required", region: "required", postalCodeFormat: "5 digits" },
  IE: { postalCode: "optional", region: "required", postalCodeFormat: "free-form" },
  AT: { postalCode: "required", region: "optional", postalCodeFormat: "4 digits" },
  JP: { postalCode: "required", region: "required", postalCodeFormat: "3-4 digits" },
  GB: { postalCode: "required", region: "optional", postalCodeFormat: "free-form" },
};
console.log("\ncountry  postal code    region         format");
for (const [c, r] of Object.entries(COUNTRY_RULE)) {
  console.log(`  ${c}  ${r.postalCode.padEnd(14)} ${r.region.padEnd(14)} ${r.postalCodeFormat}`);
}
console.log("the rule table is data; it is not baked into the form, it is read by country selection.");
record  parts  fits strict form  loss
A1         2               yes  -
A2         1                NO  required field cannot be left blank
A3         5                NO  extra parts get crammed into one field
A4         3                NO  extra parts get crammed into one field
A5         2               yes  -
A6         4                NO  extra parts get crammed into one field
does not fit the strict form: 4 / 6

flexible rule: 'full name' one field (required) + 'display name' (optional)
  A1  full name: "Elif Yılmaz"                      (two parts)
  A2  full name: "Ravi"                             (single-part name)
  A3  full name: "María del Carmen Ruiz García"     (two surnames, multiple given names)
  A4  full name: "Nguyễn Thị Hoa"                   (family name first)
  A5  full name: "Björn Þórsson"                    (surname derives from the father's name)
  A6  full name: "Jean-Pierre Le Roux"              (hyphenated name, multi-word surname)

record  lines  postal code  region    rule dropped by the strict form
B1         2  34710       İstanbul  -
B2         3  -           Dublin    postal code required; line count 3 > 2
B3         1  1010        -         region required
B4         4  100-0001    Tokyo     line count 4 > 2
B5         2  SW1A 1AA    -         region required
records dropped by the strict address form: 4 / 5

record  value           matches strict rule  reason
C1     12345678901                      yes  -
C2     AB-9931                           NO  length 7, non-digit character
C3     0012                              NO  length 4
C4     9987654321234                     NO  length 13
if the identity field is stored as a number, leading zeros are lost; the field is text.

strict form: 8 / 11 records cannot be entered directly (73%)
flexible form: full name one field, address a multi-line free-text field + country,
               postal code and region requirements toggle on and off by country.

country  postal code    region         format
  TR  required       required       5 digits
  IE  optional       required       free-form
  AT  required       optional       4 digits
  JP  required       required       3-4 digits
  GB  required       optional       free-form
the rule table is data; it is not baked into the form, it is read by country selection.

A Name Is Not Two Parts

The first section’s output shows that four of six name records do not fit the strict form. The loss takes two shapes: a single-part name cannot fill the required second field, and a name with more parts gets crammed into one field. Cramming does not look like loss, but it corrupts the data: which part is the family name is gone.

The second section shows the flexible rule: a single required full name field, plus an optional display name. This setup takes all six records as they are. The display name is asked separately, because the name the interface uses in “Hello, X” cannot be derived from the full name — deriving it always requires an assumption about order.

The name field’s second rule is sorting: which part a list view sorts by is an interface decision and cannot be baked into the data. Sorting uses locale-aware comparison — the same rule as the Tables lesson.

An Address’s Required Fields Depend on the Country

The third section shows that four of five address records drop out of the strict form. The reasons differ from record to record: some places have no postal code, some places do not use a region or state field, and some addresses do not fit two lines.

The last table gives the fix: the requirement rule is not baked into the form; it comes from a table read by country. Once the user picks a country, that table determines which fields are required, what format the postal code takes, and what the field labels say. The table is data; adding a new country adds a row, and the code does not change.

The address field’s third rule is line count: a multi-line free-text field loses less information than structured fields. Structure is asked for only when it is genuinely needed — a shipping account, a tax record — and even then it varies by country.

The Identity Field Is Text

The fourth section shows that the identity number fails the strict rule in three distinct ways: a different length, a non-digit character, and a leading zero. The last is the most deceptive: when the field is stored as a number, leading zeros are lost and the value is silently corrupted.

The rule is: an identity field is not a number but text. No arithmetic is performed on it, its format varies by country, and validation is a pattern check. That validation pattern is also read from the country table, the same as the address rules; a single regular expression baked into the form breaks on the first foreign record.

What the Measurement Means

The fifth section gives the total: eight of eleven records fail the strict form. This number is tied to the sample set and is not a statistic; its job is to show that each assumption leaves out a class of record.

The flexible form takes all the same records and asks for two things in return: fields have to stay free-form, and requirements have to be read from data. It has a cost too — automatic parsing over free-text fields gets harder. The decision comes down to which loss is acceptable: for a library membership, leaving a user out is a heavier loss than failing to structure an address.

Measurable Constraints

  • The name field is a single required free-text field; splitting it into parts happens only when genuinely necessary, and even then as optional.
  • Address requirements are read from a country table; the table is not baked into code.
  • Identity and postal code fields are stored as text; the leading zero is preserved.
  • Field labels and validation messages also vary by country; the error-message rule follows the structure from the Error Message Writing lesson.
  • The required-field marker and error notice are tied to the field the same way as in the Accessible Error Presentation lesson.

Common Mistakes

The most common mistake is splitting the name field into two required parts. The second is making the postal code required for every country. The third is storing identity and postal code fields as numbers. The fourth is writing these rules as conditional code instead of a country table: every new country then requires a code change, and the rule set eventually becomes unreadable.

Summary

  • Name, address, and identity fields each carry an assumption; in the model, eight of eleven records fail the strict form.
  • A single required full-name field takes every name structure; a display name is asked separately and optionally, because it cannot be derived from the full name.
  • Address requirements and postal code format come from a table read by country; the table is data, not baked into the form.
  • Identity and postal code are text: stored as numbers, the leading zero is lost.
  • The flexible form’s cost is that automatic parsing gets harder; the decision is made by which loss is acceptable.

Course Wrap-Up

This course treated components not by their appearance but by their specification. The Basic Components topic built the button, the text input, the selection control, and the dropdown list on the native-element-first rule, writing down each one’s role, name, state, and keyboard contract. The Container and Navigation Components topic specified the card, the tab, the accordion, the menu, the location indicator, the table, and the auto-rotating banner with the same discipline, and counted the cost of focus and tab order in each. The Layer and Feedback Components topic treated components that sit above the flow — the modal, the tooltip, the notification, the loading indicator, the skeleton, the empty and error states, the badge — through focus transfer and announcement policy. The Text and Localization topic then made interface text part of the component: guide rules, an error message’s structure, formatting derived from the locale, direction-sensitive layout, and this lesson’s field assumptions.

Three measures held constant through the course. ARIA is never written where a native element exists. Every state is announced through at least two channels, not one. And every decision ties to a measurable constraint — target size, contrast ratio, a time limit, or a tab-stop count.

The M15 curriculum closes here. Fundamentals of Interface Design tied visual decisions to perceptual principles and measurable thresholds. User Experience and Behavior Design established how those decisions are derived from the user and where the ethical boundary sits. Design Systems turned decisions into tokens, a catalog, and governance, making them scale. Accessible Component Patterns then wrote every part of the system’s keyboard, focus, and screen reader behavior at the specification level.

This curriculum was built to be read alongside the implementation layer in the M14 Frontend Development curriculum: there, how a component works; here, how it should behave. Where the two curricula meet is where an interface both works correctly and behaves correctly.

To keep your progress and take notes, Log in

My notes

Log in to take notes.

Start typing to search.

↑↓ Esc navigate · open · close