Remember that feeling of opening a new LEGO set as a kid? The excitement, the clear instructions, the satisfaction of pieces clicking together perfectly. Now remember your last code review of a "flexible" enterprise component. Not quite the same feeling, is it?
After years of watching developers (including myself) struggle with over-engineered solutions, I've learned that the best React architectures have more in common with LEGO than with the complex machinery we sometimes try to build.
The LEGO Principle: Simple Pieces, Infinite Possibilities
What My 5-Year-Old Daughter Taught Me About API Design
Last weekend, I watched my daughter play with her LEGO set. "Today we're building a dog park!" she announced excitedly. Without any documentation or "senior LEGO architect" guidance, she proceeded to create slides, sandboxes, a water area, feeding stations, and play zones for dogs. The next day? "Let's make cars!" And just like that, the entire dog park transformed into a fleet of vehicles.
This hit me hard. Here was my 5-year-old intuitively understanding something we often overcomplicate in software development: with the right building blocks, you can create anything, transform everything, and rebuild without fear. Each LEGO piece had one clear purpose, connected in obvious ways, and worked reliably every time.
Meanwhile, back at work, we had a "flexible" component that looked like this:
// The "enterprise-ready, flexible" approach
const EnterpriseDataComponent = ({
data,
configurationMatrix,
transformationPipeline,
errorBoundaryStrategy,
optimizationHeuristics,
// ... 20 more intimidating props
}) => {
useEffect(() => {
// 100 lines of setup logic
}, [/* dependency array longer than my coffee order */]);
return (
// JSX that would make a senior dev cry
);
};
Something was very wrong with our approach.
The LEGO Master Builder's Guide to React
1. Start with Perfect Bricks
// A basic LEGO brick - it does one thing perfectly
const Button = ({ onClick, children }) => (
<button
onClick={onClick}
className={styles.button}
>
{children}
</button>
);
// A slightly more specialized brick
const ConfirmButton = (props) => (
<Button
{...props}
className={styles.confirm}
/>
);
2. Build Bigger Things from Simple Pieces
// Combining bricks into something useful
const ConfirmationDialog = () => {
const { confirm, cancel } = useDialog();
return (
<Dialog>
<DialogTitle>Are you sure?</DialogTitle>
<DialogActions>
<ConfirmButton onClick={confirm}>Yes</ConfirmButton>
<Button onClick={cancel}>No</Button>
</DialogActions>
</Dialog>
);
};
3. Hide the Complex Machinery
// The complex machinery is there, but hidden
const useDialog = (options = {}) => {
// Level 1: The Happy Path (90% of developers only need this)
const simplePath = {
confirm: () => handleConfirm(),
cancel: () => handleCancel()
};
// Level 2: Extended Features (9% of cases)
if (options.advanced) {
return {
...simplePath,
onBeforeConfirm: handlePreConfirm,
onAfterCancel: handlePostCancel
};
}
// Level 3: Escape Hatch (1% of power users)
if (options._superPowers) {
return {
...simplePath,
_internal: internalAPIs,
_context: dialogContext
};
}
return simplePath;
};
The Design System: Your Master Builder Kit
Think of your design system not as a collection of components, but as a LEGO Master Builder Kit. Each piece should be:
- Instantly Recognizable
// Anyone can understand this
const Card = ({ title, children }) => (
<div className={styles.card}>
{title && <h2>{title}</h2>}
{children}
</div>
);
- Predictably Connectable
// Pieces that work together naturally
const ProductCard = ({ product }) => (
<Card>
<CardImage src={product.image} />
<CardContent>
<ProductDetails product={product} />
</CardContent>
<CardActions>
<AddToCartButton product={product} />
</CardActions>
</Card>
);
- Safely Extensible
// Senior devs can add features without breaking simplicity
const withAnalytics = (WrappedComponent) => {
return function EnhancedComponent(props) {
useAnalytics(props.analyticsEvent);
return <WrappedComponent {...props} />;
};
};
// Still simple to use
const TrackableButton = withAnalytics(Button);
The Security Advantage: Fewer Entry Points, Better Control
When you build with well-defined "LEGO bricks", security becomes more manageable:
// One secure implementation, used everywhere
const SecureButton = ({ onClick, children }) => {
const { validatePermissions } = useAuth();
const handleClick = () => {
if (validatePermissions()) {
onClick();
}
};
return <Button onClick={handleClick}>{children}</Button>;
};
// Developers can't accidentally bypass security
const DeleteButton = () => (
<SecureButton
permission="delete:items"
onClick={handleDelete}
>
Delete
</SecureButton>
);
The Unexpected Benefits
After implementing these principles, we discovered some surprising benefits:
-
Junior developers became productive faster
- "It just makes sense" was a common feedback
- Less time reading docs, more time building
-
Senior developers found it easier to optimize
- Clear boundaries made performance improvements isolated
- Easier to implement advanced features without affecting basic usage
-
Code reviews became discussions about business logic
- Instead of "Why is this so complex?"
- We got "This is exactly what we needed"
-
Documentation practically wrote itself
- When your APIs are intuitive, you need less documentation
- What documentation you do write is focused on advanced use cases
The Master Builder's Wisdom
Remember:
- If your components need a PhD to understand, you're doing it wrong
- Complex features should be opt-in, not opt-out
- The best code is the code you don't have to explain
- Build for the many, extend for the few
Looking Forward
The future of React development isn't about who can build the most complex system. It's about who can make complex systems feel simple. Just like LEGO has been doing for generations.
Next time you're designing a component or system, ask yourself: "Could a 5-year-old understand how these pieces fit together?" (Okay, maybe not the code itself, but the mental model should be that clear.)
How do you keep your React components simple yet powerful? Share your LEGO-wisdom in the comments below!
Top comments (0)