What Does 'Resilient' Mean? — Defining Drift and Invariants
Source: Dev.to
Drift in CSS Design
In Part 1, I argued that CSS architecture should shift from “rules to memorize and follow” to a “feedback system.” But what exactly does resilient (drift‑resistant) design mean? This part defines the phenomenon of design degradation as drift and introduces the concept of invariants to prevent it.
CSS design doesn’t collapse all at once. Small decision inconsistencies accumulate, and by the time you notice, coherence is lost. I call this drift.
Breaking Down
In this series, “breaking down” refers specifically to three things:
- Component boundary ambiguity – where one component ends and another begins differs from person to person.
- Layout responsibility confusion – whether margin belongs to the parent or child varies file by file.
- Naming and structural inconsistency – naming conventions and file organization vary across the project.
Example: Common drift in a BEM project
| Situation | Drift |
|---|---|
One team member writes margin on the child component itself; another specifies it from the parent. | “Is this element an independent component or part of its parent?” – answers differ by person. |
| Modifier granularity varies from file to file. | – |
None of these are “rule violations.” The interpretive latitude in guidelines allows decision drift, and that latitude widens as teams grow.
AI Drift
Introducing AI coding agents doesn’t change the structure. Even with guidelines packed into the context window, output varies where judgment is required. Human drift simply becomes AI drift.
Weakness of Convention‑Based Designs
Convention‑based designs share a structural weakness:
- Memorization burden – the longer the guidelines, the harder it is for everyone to accurately remember and apply them.
- Subjective decisions – questions like “where does one component end?” have no objective answer.
- Verification difficulty – whether something violates a convention can’t be determined mechanically; you can only rely on reviews.
When all three are present, drift is inevitable. Reviews maintain quality only while the reviewer’s judgment stays consistent, and reviewers are human – their judgment drifts too.
Invariants
Programming has the concept of invariants – conditions that must hold at every point in a program (e.g., an array index staying within bounds, an account balance never going negative). These conditions are mechanically enforced through types and assertions.
The same idea applies to CSS architecture: eliminate rules whose answers change based on interpretation, and adopt only conditions that can be mechanically evaluated as true or false.
Concrete Examples
| Convention‑based (requires interpretation) | Invariant (mechanically verifiable) |
|---|---|
| “Decompose components into appropriate granularity.” | “A Block’s direct children can only be Blocks or Elements.” (terms defined in Part 4) |
| “Parents manage layout.” | margin-top can only be specified from the parent’s > .child selector. |
| “Keep naming consistent.” | Blocks use 2‑word kebab‑case; Elements use a single word. |
| “Distinguish between state and variation.” | Variants use data-variant; States use data-state. |
The left column requires human interpretation to judge correctness. The right column can be judged through string‑pattern and selector‑structure matching, making automated lint verification possible. The right‑hand examples are actual invariants used in SpiraCSS, which I’ve developed and use in production. Part 4 covers them in detail.
Properties of a Viable Invariant
Not every rule can become an invariant. To function as one, a rule needs these properties:
- Binary evaluation – violation or compliance is determined unambiguously (no gray zones).
- Syntax‑verifiable – can be determined through source‑code syntax analysis alone (no runtime needed).
- Locally verifiable – can be determined by looking at the target file alone (no project‑wide scanning needed).
If the design is composed entirely of rules meeting these criteria, a lint tool can serve as the “gatekeeper.” Humans don’t need to make judgment calls — just follow the tool’s verdict. The same goes for AI agents.
Addressing Objections
“Isn’t this just freezing preferences rather than defining ‘correctness’?”
That’s a fair objection. “Write margin from the parent” isn’t the only correct approach, but there’s value in fixing design preferences to make all authors converge on the same output — especially when the pool of authors includes both humans and AI. Having an unwavering standard itself supports team productivity.
The Feedback Loop
Defining invariants alone won’t preserve the design. Without detecting violations and communicating what’s wrong and how to fix it, corrections don’t happen. The sequence:
- Define invariants.
- Detect violations.
- Present fix instructions.
forms a feedback loop. The next part dives deeper into designing this loop. When lint returns not just “what’s wrong” but also “how to fix it,” error messages must be thoughtfully crafted.
Next Steps
→ Part 3 — The Feedback Loop — Designing Lint That Tells You What to Fix and How (later this week)
Resources
- SpiraCSS – design specs, tools, and source code are open source.
- Website:
- GitHub: