# Schemas
Every product manager has been there.
You've emerged from weeks in the research trenches. User interviews completed. Personas crafted. Experience maps drawn. Sharpie covers your hands, and post-its carpet your desk.
But the slog was worth it. You've unearthed something precious—a feature idea that feels genuinely breakthrough. The user need is clear, the market opportunity substantial, the competitive advantage obvious. For a brief moment, you allow yourself to savor the satisfaction of discovery.
Time for the big reveal with engineering.
A few sentences into your pitch, their expressions shift. The energy drains from the room like air from a punctured tire.
"Our data model won't support that."
"What does that even mean?!"
## The invisible architecture
"Data model" and "schema" are engineering euphemisms for "how an application organizes information." It sounds straightforward—almost trivial. Keep the data tidy. Build logical relationships. How hard could it be?
As it turns out, extraordinarily hard.
Even brilliant decisions compound into architectural dead ends. The choices that seemed obviously correct in year one become the constraints that strangle growth in year three. This isn't a failure of engineering competence—it's an inevitable consequence of building software in an uncertain world.
Consider how these constraints emerge through a simple example.
## The Familyizer™ paradox
Imagine you're building the world's premier family tree software: Familyizer™. Your mission is simple—help people visualize their nuclear family connections through elegant technology.
You start with this family as your prototype:
Our test family (yes, that's Santa—go with it)
The obvious data structure emerges naturally:
1{
2 "user": "Michael Williams",
3 "dog": "Obi",
4 "mother": "Eva",
5 "father": "Robert",
6 "sister": "Susan"
7}
Familyizer Data Model — v0.1
Great, that looks clean an intuitive. But the moment you expand beyond this single case, the limitations appear.
What if users have brothers instead of sisters? Multiple siblings? Stepparents? The rigid structure crumbles under the weight of real-world complexity.
We switch to arrays instead of hard coded relationships and relabel the groups to be more flexible:
1{
2 "name": "Michael Williams",
3 "pets": ["Obi"],
4 "parents": ["Eva", "Robert"],
5 "siblings": ["Susan"]
6}
Familyizer Data Model — v0.2
Better, but now you've lost critical information. Which parent is which? What species is that pet? Nested objects restore the missing context:
1{
2 "name": "Michael Williams",
3 "pets": [
4 {
5 "name": "Obi",
6 "species": "dog"
7 }
8 ],
9 "family": [
10 {
11 "name": "Eva",
12 "relationship": "mother"
13 },
14 {
15 "name": "Robert",
16 "relationship": "father"
17 },
18 {
19 "name": "Susan",
20 "relationship": "sister"
21 }
22 ]
23}
Familyizer Data Model — v1.0
Looking good! Your schema handles nuclear families, extended families, complex relationships, and even family pets. After six months of hockey-stick growth, you're ready for the next big feature: connecting individual family trees into a global network.
The vision is compelling. Users link their maps to create humanity's family tree. Network effects. Viral growth. The works.
You present the idea to engineering with confidence.
Their response: "The schema won't support it."
Again??
## The trap
Your carefully crafted data model optimized for a single viewpoint—the individual user. From that perspective, it works beautifully. Anyone can quickly see how they relate to family members.
But the schema has no understanding of how family members relate to each other. How would the system know whether your sister married your brother-in-law? What if you have two sisters and he married the other one? The data model can't answer these questions because it was never designed to.
This isn't a criticism of your engineering team. It's a textbook example of how early, reasonable decisions become future roadblocks. The constraint wasn't visible until you needed capabilities the original design never contemplated.
## The calculus of constraints
There's no such thing as software without constraints. Every architectural decision opens certain possibilities while closing others. The art lies not in avoiding constraints—that's impossible—but in choosing them wisely.
The solution isn't to predict the future perfectly. It's to minimize the cost of being wrong.
## The antidote to schema paralysis
Three practices can prevent data models from sabotaging your product development:
Include engineers in discovery. The more your engineering team understands about user needs and business objectives, the better their architectural decisions become. Schema choices made in isolation from product context are almost certainly suboptimal.
Share ideas early and often. The "it's not ready to share yet" mindset destroys your team's ability to think ahead. Engineering insight is most valuable during the messy, half-formed ideation phase—not after you've fallen in love with a specific solution.
Discuss constraint implications explicitly. Every schema decision creates trade-offs. Surface these trade-offs rather than hiding them. When your team understands the architectural debt being incurred, they can make more informed decisions about when to accept it and when to refactor.
## The strategic choice
Your products will always have constraints—the question is whether you choose them deliberately or inherit them accidentally. The teams that thrive are those that approach data architecture with the same strategic thinking they apply to product roadmaps.
As Charlie Munger noted, "Invert, always invert." Instead of asking "What schema do we need today?", ask "How could these decisions limit us tomorrow?" The difference between good and great product teams often comes down to which questions they choose to answer.
The best schema isn't the one that solves today's problems perfectly. It's the one that gives you the most options for solving tomorrow's problems too.