Say you're building a component that shows up in lots of places, like a header.
Look at designs and sure enough, same header on every page. Logo, few buttons, username. You create a reusable component. DRY all the way.
const Header = () => {
return (
<Box>
<Logo />
<MenuItem />
<MenuItem />
<UserMessages />
<UserProfile />
</Box>
)
}
Fantastic! You have a header that works everywhere.
A new page appears
"Hey, header looks weird on homepage. Where's the signup button?"
Your designer's not happy. Header that's the same everywhere can't be same on the homepage. That's for marketing, they need signups.
obviously 🙄
You add a prop.
const Header = (props: { showSignup: boolean }) => {
return (
<Box>
<Logo />
<MenuItem />
<MenuItem />
{!props.showSignup && <UserMessages />}
{!props.showSignup && <UserProfile />}
{props.showSignup && <SignupButton />}
</Box>
)
}
Cool, you've kept it DRY. Same header, same styling, signup yes or no.
A funnel shows up
"Hey, users are getting distracted out of this purchase funnel. Header too busy"
Your universal header is costing you money. When users are on the path to paying, you want nothing to stand in their way.
Another boolean!
"Oh and let's pretend this is a fullscreen modal, add a close button. Keep the logo"
Two booleans!
const Header = (props: {
showSignup: boolean
hideMenu: boolean
showClose: boolean
}) => {
return (
<Box>
<Logo />
{!props.hideMenu && <MenuItem />}
{!props.hideMenu && <MenuItem />}
{!props.showSignup && <UserMessages />}
{!props.showSignup && <UserProfile />}
{props.showSignup && <SignupButton />}
{props.showClose && <CloseButton />}
</Box>
)
}
Well that's not confusing at all. With 3 booleans, your header has 8 possible incantations.
Add one more ask from design and you're up to 16.
😅
You've created a mess
Your beautiful universal header component is hard to use. Complexity is exploding, the code is getting hairy, and you're the only person on your team who knows how to hold it.
For everyone else it's frustrating as heck. Get it right for this screen, breaks on that screen.
Debugging feels like whack-a-mole.
And I'm showing you a simple example. In production code these booleans start interacting. If hideMenu and showSignup
then do X, otherwise if not showClose
do Y.
Nobody wants to touch your component ever again. It's too tricky.
Variants to the rescue
How many of those 8 incantations are valid?
I count 3.
Then why allow the other 5? If 5 out of 8 ways to use your component are bugs, something's wrong.
Here's what you do 👉 turn those flags into a variant prop. Use TypeScript and you even get autocomplete 😍
const Header = (props: { variant: "homepage" | "funnel" }) => {
let hideMenu, showClose, showSignup
switch (variant) {
case "homepage":
showSignup = true
case "funnel":
hideMenu = true
showClose = true
}
return (
<Box>
<Logo />
{!hideMenu && <MenuItem />}
{!hideMenu && <MenuItem />}
{!showSignup && <UserMessages />}
{!showSignup && <UserProfile />}
{showSignup && <SignupButton />}
{showClose && <CloseButton />}
</Box>
)
}
Now the rest of your team can use your header with ease: <Header variant="..." />
. And thanks to TypeScript their IDE tells them what's available.
AND we found a bug in my pseudocode. You don't want user menus showing up in funnel headers 😅
Cheers,
~Swizec
PS: quick tip for shorter emails 👉 break your wrist
And then I broke my wrist a little 😅 pic.twitter.com/cQDBEqsTSQ
— Swizec Teller (@Swizec) February 27, 2021
Continue reading about Variants – a quick tip for better React components
Semantically similar articles hand-picked by GPT-4
- DRY – the common source of bad abstractions
- Why null checks are bad
- DRY is a footgun, remember to YAGNI
- Build a new design system in a couple afternoons
- Why CSS-in-JS is winning, an example
Learned something new?
Read more Software Engineering Lessons from Production
I write articles with real insight into the career and skills of a modern software engineer. "Raw and honest from the heart!" as one reader described them. Fueled by lessons learned over 20 years of building production code for side-projects, small businesses, and hyper growth startups. Both successful and not.
Subscribe below 👇
Software Engineering Lessons from Production
Join Swizec's Newsletter and get insightful emails 💌 on mindsets, tactics, and technical skills for your career. Real lessons from building production software. No bullshit.
"Man, love your simple writing! Yours is the only newsletter I open and only blog that I give a fuck to read & scroll till the end. And wow always take away lessons with me. Inspiring! And very relatable. 👌"
Have a burning question that you think I can answer? Hit me up on twitter and I'll do my best.
Who am I and who do I help? I'm Swizec Teller and I turn coders into engineers with "Raw and honest from the heart!" writing. No bullshit. Real insights into the career and skills of a modern software engineer.
Want to become a true senior engineer? Take ownership, have autonomy, and be a force multiplier on your team. The Senior Engineer Mindset ebook can help 👉 swizec.com/senior-mindset. These are the shifts in mindset that unlocked my career.
Curious about Serverless and the modern backend? Check out Serverless Handbook, for frontend engineers 👉 ServerlessHandbook.dev
Want to Stop copy pasting D3 examples and create data visualizations of your own? Learn how to build scalable dataviz React components your whole team can understand with React for Data Visualization
Want to get my best emails on JavaScript, React, Serverless, Fullstack Web, or Indie Hacking? Check out swizec.com/collections
Did someone amazing share this letter with you? Wonderful! You can sign up for my weekly letters for software engineers on their path to greatness, here: swizec.com/blog
Want to brush up on your modern JavaScript syntax? Check out my interactive cheatsheet: es6cheatsheet.com
By the way, just in case no one has told you it yet today: I love and appreciate you for who you are ❤️