A product develops a language through its words, visual system, behavior, and code. When that language stays consistent, people can understand a new part of the product without learning everything again.
The same word should travel
In Building interfaces that scale, I wrote about interfaces absorbing complexity so customers don't have to. Shared language is part of that. If customers know something as an experiment, that word should remain recognizable in the interface, code, contracts, documentation, and team conversations.
My work on LinkedIn lift test reporting made that especially clear. I designed the frontend architecture for lift reporting and incremental lift tests, implemented it with two other frontend engineers, and partnered with backend engineers on the schema and GraphQL setup.
On the frontend, a shared TypeScript architecture normalized Lift entities into one typed model. The model handled formatting and differences in the underlying data so reusable components could consume a predictable shape.
That foundation brought two reporting flows together and enabled a third revenue-based experiment type. Shared components could frame the results for each product while the entity model kept meaning and data transformation in one place.
Framing matters because advertisers use these results to make decisions. Experiment, control, treatment, lift, and measurement should not quietly change meaning between products or between the UI and the system underneath it.
Small actions carry language too. Save, Cancel, and Launch imply different outcomes. An error should say what happened and what someone can do next. The wording is part of the behavior.
The visual system should travel too
Visual language needs the same consistency as product terminology. Shared components stop buttons, fields, and status messages from inventing new behavior every time they appear. They also let an accessibility fix or interaction improvement reach every product using them. LinkedIn has written about how a shared design language helps different products and teams still feel connected.
I prefer tokens that ask for an intent instead of a hard-coded appearance. A warning state should ask for warn, not a specific hex code of yellow. This allows the theme to shift globally while the semantic meaning stays.
/* Primitives: The hard values */
:root {
--color-yellow-500: #f6c85f;
--color-yellow-700: #b7791f;
}
/* Semantics: The intent (Light Theme) */
:root {
--intent-warn-bg: var(--color-yellow-500);
--intent-warn-text: var(--color-yellow-700);
}
/* Semantics: The intent (Dark Theme) */
[data-theme="dark"] {
--intent-warn-bg: var(--color-yellow-700);
--intent-warn-text: var(--color-yellow-500);
}The same idea applies to spacing, typography, motion, and interaction states. Components can preserve the rule while leaving enough room for each product to have its own voice.
Consistency creates room to play
When I design an app, I want familiar rules to handle the basics without flattening its personality. Hierarchy, spacing, focus, and state changes should feel consistent, but the product should still have its own point of view.
This portfolio is one example. The writing carries most of its personality, while typography, thin borders, visible focus states, spacing, and theme keep it familiar. The games loosen the tone without feeling disconnected. CHILL, CASUAL, and CRACKED fit them better than the usual difficulty labels. They share visual rules, but Stack, Snake, Meteor, Dive, and Ricochet keep their own finesse.
When I added Game of the Day to the homepage, its panel competed too strongly with my bio and Notes. Making it compact and muting it until someone interacts kept the playful idea without letting it take over the page.
Most people will never notice the design decisions behind a product, and that is often the point. Across the apps and features I've built, I aim for hierarchy that feels natural without calling attention to itself: familiar enough to make sense, with enough room for the product to feel distinct.