← Back to work
Case 01 · Enterprise systems

Turning a formula language into something you can see.

District administrators were writing nested formula syntax by hand to derive every username, email, and directory attribute for thousands of students and staff. A wrong character wasn't caught until the accounts already existed.

Work shown with enterprise-identifying details removed. Product name and interface are my own; original assets are not shown.

Role
UX/UI Designer
Users
District IT administrators
Tools
Claude prototyping, React
Status
Shipped to production
The context

Every district names people differently.

When a district syncs its people into a directory, something has to decide what each person's username, email address, and display name will actually be. One district wants first initial plus last name. Another wants the employee ID. Another wants first name, a dot, last name, all lowercase, with a fallback when a field is missing.

That decision is expressed as a mapping: for each destination attribute, a rule that derives it from source data. The rules have to handle real names, and real names are messy.

The problem

A programming language, handed to people who don't program.

Administrators wrote these rules as raw formula strings. Source fields wrapped in one delimiter, destination fields in another, function calls in backticks, nested several levels deep, with positional arguments and no autocomplete.

Two problems compound each other. Getting the syntax right is hard, and there is no way to see what a formula produces until it has already run. By then the accounts exist. Someone's login is wrong, and fixing it means correcting the rule and reconciling every record it already touched.

What made this specifically dangerous
  • The output is an identity, so a mistake doesn't degrade an experience, it locks someone out
  • Errors are silent. A malformed rule often produces a plausible-looking wrong value rather than a failure
  • It runs at scale. One bad rule applies to every person in the district at once
  • Discovery is delayed, usually until someone tries to log in and can't
The prior formula-entry experience is described from memory rather than shown. The original interface is not reproduced here.
The real design problem

The syntax was visible. The result was not.

It would be easy to read this as a syntax problem and solve it with better validation or an autocomplete. That helps, but it addresses the smaller half.

The rule an administrator types is not the thing they care about. They care about what comes out the other side for actual people. The old interface showed them the input and hid the output, which is exactly backwards for a task where the input is unfamiliar and the output is what matters.

A formula that parses correctly and produces the wrong username is still a failure, and validation cannot catch it.
The design

Blocks to build it, records to check it.

One
Typed blocks instead of syntax
Source fields, destination fields, functions, and literal text become draggable blocks, color-coded by kind. Functions carry labeled slots for their arguments. You cannot produce a malformed rule, because there is no syntax to get wrong. Nesting is expressed by dropping a block into a slot rather than by counting parentheses.
Source fieldDestination fieldFunctionLiteral text
Two
A palette organized by what you're trying to do
Functions are grouped by intent rather than listed alphabetically, and the palette is searchable. An administrator who wants to handle a missing value looks under conditional rather than scanning thirty function names for the one that sounds right.
TextConditionalDate and timeHash and encodeLookup
Three
A live results preview
Every change to the rule immediately re-evaluates against sample records and shows the actual resulting value for each person. The output stops being something you discover after the sync and becomes something you are looking at while you build.
Four
Raw formula mode, retained
The text view stays available and round-trips: a formula parses into blocks, blocks serialize back to a formula. Administrators with existing rules and existing habits are not stranded, and anyone who wants to paste something can.
The problem
  • Rules are written as raw formula strings, by hand
  • Nested function calls with positional arguments and delimiters to get exactly right
  • A text field shows the rule, never the value it will produce
  • A malformed rule often yields a plausible-looking wrong value rather than an error
The design
  • Typed blocks dropped into labelled slots
  • Nesting expressed by placement rather than by counting parentheses
  • Functions grouped by intent and searchable
  • Every change re-evaluated live against sample records, before saving
Design principle at work
When the input is unfamiliar and the output is what actually matters, show the output continuously. Validation confirms a rule is well-formed. Only the result confirms it is correct.
Blocks composing a username rule, with the results preview showing broken output for two of four sample records

Blocks on the canvas, sample records evaluating live beneath them.

The part I'd defend hardest

The sample records are edge cases on purpose.

A preview is only as useful as the records it previews against. The obvious choice is a few clean, ordinary names, which would confirm that a rule works and teach an administrator nothing.

So the preview set is deliberately awkward. Someone with an apostrophe in their surname. Someone with accented characters and a hyphenated name. Someone with no middle name. Someone with an empty email field.

What the preview is actually for
  • Not confirming the rule works on an easy name
  • Showing where it breaks, before it breaks on someone real
  • Making the fix obvious in the same screen where the problem appeared

Build a simple first-initial-plus-surname rule and the preview immediately produces an apostrophe and an accented character inside what is supposed to be a login. Nobody has to explain that this will fail. The administrator sees it, reaches for the function that strips diacritics, and watches the value correct itself.

Design principle at work
Sample data is a design decision, not filler. Choosing the records that expose failure turns a preview from reassurance into a test.
Try it

The builder, rebuilt and interactive.

I rebuilt this as a standalone prototype with fictional records, embedded below. Snap together a first-initial-plus-surname rule and watch the preview. Two of the four sample records produce a username that would not survive contact with a directory.

Sample data is fictional. Interface rebuilt from scratch in my own design system. Open full screen ↗
The decision

Keep the raw formula, or force everyone into blocks?

Removing the text view entirely would have made the product simpler and the design cleaner. It would also have stranded every administrator with formulas they had already written and habits they had already built, and taken away the fastest path for the few who genuinely prefer typing.

Impact

Shipped, and in daily use.

The block builder is in production. Administrators define attribute mappings without writing formula syntax, and see the resulting values for real records before anything is saved. The class of error where a rule looks right and produces the wrong identity is now visible at the moment it is created rather than after it has propagated.

What I learned

Preventing bad input is half the job.

Lesson 01
Structure beats validation.
Blocks with typed slots make malformed rules impossible to express. That is stronger than catching them afterward, and it needs no error messages at all.
Lesson 02
Show the output, not just the input.
A correct-looking rule that produces a wrong value is the failure mode that matters. Only the result reveals it, so the result has to be on screen.
Lesson 03
Choose sample data that breaks things.
Previewing against easy names is reassurance. Previewing against the names that expose flaws is a test the user runs without knowing they're running one.
Lesson 04
Don't strand the people already using it.
Keeping the raw view cost some elegance and bought migration. A new interface that abandons existing work gets adopted slowly, or not at all.

The blocks made the rule easy to write. The preview made it possible to know whether it was right.

Thanks for reading.