The architecture diagram kept saying “data” — this component sends data, that one reads data. The D step finally asks: what is that data? We describe the system from the data's point of view — its core entities and where each one lives.
The map
Where we are in RADIO
The architecture told us pieces exchange data. Now we model it. Tap D:
D · Core Entities
Identify the core entities the UI is built around, what each one owns, and how they relate.
The D in RADIO
What core entities are
A data entity is a block of data you can name with a single word — a Post, a Comment, a User. The D step identifies the core entities in your system, the fields each one holds, and which component or module owns them. That's what lets you say precisely “the store holds the posts; the header reads the author.”
Where data comes from
Two kinds of data
Almost every system mixes two sources of data, and telling them apart decides where each piece should live:
Server-originated
lives in the database
Your profile (name, avatar)
Feed posts & comments
Anything fetched from an API
Persists across devices & sessions.
Client-originated
starts life in the UI
Draft text in an input
isLoading / isError
isExpanded / isOpen
Often transient component state.
They can convert
The two aren't walls. Draft text in a comment box is client-originated — but the moment you hit Enter and it's saved, it becomes server-originated for everyone else. The question is simply where the data starts.
How to write it
Describe data with types
Don't just say “username.” Say its type. TypeScript-style notation is the clearest way to pin a field down so whoever reads the design knows exactly what shape arrives:
a field is a name + a type
username:stringage:numbercomments:Comment[]// an array of Comment entities
That last line matters: when a component expects Comment[], everyone knows it renders a list, not a single item.
Worked example
The Facebook-feed entities
Before the abstract boxes, here's the thing we're actually modeling — one feed post. Every region on screen maps to an entity (tagged in the corners):
User
Guilty-Looking Dogs
Portia Smith · 2h · 🌐 Public Group
Post
Is your dog looking guilty? Share your best “I-didn't-eat-it” face below! 🐶
Media
🐶
👍❤️😆 233K432 comments
👍Like
💬Comment
↪Share
Comment
Max's Human
He absolutely did it 😂
Turn that screen into data. Four entities cover the feed; notice how relations (the green types) stitch them together — a Post owns Comment[] and a User author:
Post
idstring
datestring
contentstring
mediaMedia[]
commentsComment[]
authorUser
Comment
idstring
datestring
contentstring
mediaMedia[]
authorIdstring
Media
type"image" | "video"
urlstring
User
idstring
usernamestring
avatarstring
Those cards are only half the story — the relations are what make it a model. Tap an entity to trace what it owns:
A Post owns comments, media, and an author. Tap an entity.
Try it
Classify the data
For each piece of data in the feed, decide where it originates — which tells you whether it belongs in the store/DB or as transient component state:
0/6 sorted
The logged-in user's profile (name, avatar)
Text being typed into the comment box
The page of feed posts just fetched
isLoading while the feed request is in flight
Whether a post's comments are expanded
A post's text before you hit “Post”
Keep state sane
State best-practices
Three habits keep your data model from turning into a bug farm:
1 · Keep component state isolated
Each component's state should be a black box. If you render two posts, one post's isLoading must never affect the other's. Isolated state is what lets you safely repeat a component on the page.
2 · Minimize the number of states
Fewer states are easier to reason about and cheaper to manage. Keep only the state that genuinely represents something you need.
3 · Don't store derived state
If a value can be computed from existing state, compute it — don't store it. isEmpty isn't state; it's items.length === 0. Storing it just gives you a second copy to keep in sync.
derive, don't duplicate
// avoid: a second source of truthconst[isEmpty,setIsEmpty]=useState(true)// prefer: derive it on the flyconstisEmpty=items.length===0
Practice
Check your understanding
Q1Sort each scenario
Server-originated or client-originated?
A user's saved order history
Whether a modal is currently open
Search results returned from an API
The current value of a search input
Q2Multiple choice
You need to know if a cart is empty. The best approach?
Q3Multiple choice
Why keep each component's state isolated?
Try it yourself
Design challenge
Model the data for a simple chat window:
Write the Message and Conversation entities with typed fields.
List which data is server-originated vs client-originated.
Find one value you were tempted to store but could derive instead.
Key takeaways
→A core entity is a nameable block of data (Post, Comment, User) with typed fields, owned by some part of the system.
→Data is either server-originated (persists in the DB) or client-originated (UI state) — and can convert from one to the other.
→Describe every field with its type (TS-style) so the shape is unambiguous.
→Keep component state isolated, minimize the number of states, and never store derived state.