RADIO Framework
The RADIO framework is a checklist for structuring frontend system design discussions. It moves from understanding the problem to proposing a design and then examining the parts where deeper trade-offs matter.
R -> Requirements
A -> Architecture
D -> Data Model
I -> Interface Definition
O -> Optimizations and Deep Dive
One-line idea: RADIO keeps a design grounded in requirements before moving through architecture, data, contracts and evidence-driven optimization.
Core Concepts
What RADIO Is - and Is Not
RADIO is a practical interview and design heuristic, not a formal web standard or a rigid development process. Its purpose is to make open-ended reasoning complete and easy to follow.
Understand the product
↓
Draw the major boundaries
↓
Define the information
↓
Specify communication
↓
Stress-test important decisions
The stages influence one another. Discovering an API limitation may change the data model; a performance target may change the architecture. Use the letters as checkpoints and revisit earlier decisions when needed.
R - Requirements
Requirements establish what must be designed, for whom and under which constraints. Do this before choosing frameworks, state libraries or rendering strategies.
Functional Requirements
Functional requirements describe user-visible behavior.
For a news feed, important questions might include:
- Can users only read posts, or also create and edit them?
- Is the feed chronological, ranked or both?
- Are reactions, comments and sharing in scope?
- Must new posts appear in real time?
- Does the feed support search, filtering or offline reading?
Identify the critical user journeys and separate them from optional features.
Must have: View feed, load more, open a post
Useful: React, comment, refresh in real time
Later: Offline mode, advanced filters
Non-Functional Requirements
Non-functional requirements describe the quality and operating constraints of the experience:
- performance and responsiveness
- accessibility
- availability and reliability
- scale and traffic patterns
- security and privacy
- internationalization
- browser and device support
- SEO and shareability
- offline or low-connectivity behavior
Make important goals measurable where possible:
Vague: The feed should be fast.
Specific: The first page should remain usable on a mid-range mobile device
and scrolling should not require rendering thousands of DOM nodes.
Scope and Assumptions
State what the design will and will not cover:
In scope: Web client, feed rendering, pagination and optimistic reactions
Out of scope: Post recommendation algorithm and media transcoding
Assumption: Backend APIs and authentication service already exist
This prevents time from being spent on a different problem than the one being evaluated.
Requirements Output
At the end of this stage, aim to have:
- primary users
- critical use cases
- important constraints
- scale assumptions
- explicit exclusions
- a few success signals
A - Architecture
Architecture shows the major components, boundaries and data flow that satisfy the requirements.
Browser
├── Routes and page shell
├── Feature components
├── Client and server state
└── Data-access layer
↓
API gateway or backend services
↓
Databases, caches and external systems
Keep the first diagram high-level. Explain why each major block exists before discussing implementation details.
Frontend Questions
Consider:
- How are routes and feature boundaries organized?
- Which pages use CSR, SSR, SSG or a hybrid?
- Which state is local, shared, server-owned or URL-based?
- How does data flow through the interface?
- What should happen during loading, empty and failure states?
- Which features load initially and which can be deferred?
- Where are authentication and authorization enforced?
Component Boundaries
Prefer components with clear responsibilities:
FeedPage
├── FeedFilters
├── FeedList
│ └── FeedItem
└── PaginationSentinel
Avoid turning a component tree into the entire architecture. Also show data ownership, network boundaries, caching and important browser capabilities.
Data Flow
Trace at least one important user action from input to visible result:
User reacts to a post
↓
UI applies optimistic state
↓
Mutation is sent with post and reaction IDs
↓
Server accepts or rejects the request
↓
UI confirms or rolls back the optimistic update
This exposes missing loading states, race conditions and ownership decisions earlier than a box diagram alone.
Architecture Output
Produce:
- a high-level component and service diagram
- rendering and routing choices
- state ownership boundaries
- one or two key data flows
- failure and recovery behavior
- reasons for major decisions
D - Data Model
The data model defines the information the frontend reads, derives, caches and changes.
Identify Entities
Start with product concepts rather than UI components:
type User = {
id: string;
displayName: string;
avatarUrl: string;
};
type Post = {
id: string;
authorId: string;
body: string;
createdAt: string;
reactionCount: number;
};
Discuss identifiers, relationships, optional fields and update frequency. Clarify which values come from the server and which are derived by the client.
Classify State
| State type | Example | Typical owner |
|---|---|---|
| Local UI state | Open menu, draft input | Component or feature |
| URL state | Search query, filter, selected tab | Router or URL |
| Server state | Feed items, user profile | Query cache backed by server |
| Shared client state | Theme, session summary | Application-level store or context |
| Persistent client state | Offline drafts, preferences | Browser storage with a lifecycle policy |
Do not put every value in global state. Keep state close to its owner while providing a deliberate synchronization path when multiple consumers need it.
Normalize When It Solves a Problem
Repeated entities may be stored once and referenced by ID:
const state = {
usersById: {
u1: { id: "u1", displayName: "Aman" },
},
postsById: {
p1: { id: "p1", authorId: "u1", body: "Hello" },
},
feedIds: ["p1"],
};
Normalization can reduce duplication and simplify consistent updates. It also adds lookup and reconstruction work, so use it where entities are shared or frequently updated rather than automatically.
Model UI States Explicitly
Include more than successful data:
type RequestState<T> =
| { status: "idle" }
| { status: "loading" }
| { status: "success"; data: T }
| { status: "error"; message: string };
Loading, empty, stale, partial and error states are part of the product design.
Data Model Output
Produce:
- core entities and relationships
- state categories and owners
- update and invalidation rules
- derived values
- loading and failure states
- persistence and retention decisions
I - Interface Definition
Interfaces are contracts between components, modules, clients, services and third parties.
Network API Contracts
Define the information a client needs rather than only naming an endpoint:
GET /api/feed?cursor=abc123&limit=20
{
"items": [
{
"id": "p1",
"authorId": "u1",
"body": "Hello",
"createdAt": "2026-09-04T10:00:00Z"
}
],
"nextCursor": "def456"
}
Discuss:
- request and response shapes
- pagination and filtering
- authentication
- validation and error formats
- retries, cancellation and timeouts
- versioning and backward compatibility
- real-time events when required
Component Interfaces
Frontend interfaces also include props, callbacks and events:
type FeedItemProps = {
post: Post;
currentUserReaction?: string;
onReact: (postId: string, reaction: string) => void;
};
A useful component contract exposes product behavior without leaking internal markup or state-management details.
Event Contracts
For real-time systems, describe event identity and ordering:
{
"type": "post.updated",
"eventId": "evt_42",
"postId": "p1",
"version": 7,
"changes": {
"reactionCount": 13
}
}
Version or sequence information can help the client reject stale updates and recover after reconnecting.
Interface Output
Produce:
- main network requests and events
- representative payloads
- component or module contracts
- error and cancellation behavior
- compatibility and evolution strategy
O - Optimizations and Deep Dive
Start optimization only after a complete baseline design exists. Choose the areas most connected to the stated requirements and likely bottlenecks.
Performance
Possible topics include:
- route and feature code splitting
- image and font delivery
- list virtualization
- memoization after measuring renders
- caching and request deduplication
- pagination or incremental loading
- prefetching likely next actions
- Web Workers for CPU-heavy processing
Explain the cost as well as the benefit. Prefetching may improve navigation but consume bandwidth; aggressive caching may serve stale data.
Reliability and Network Behavior
Consider:
- retry rules with backoff
- offline and reconnect behavior
- optimistic update rollback
- duplicate or out-of-order events
- stale cache revalidation
- graceful degradation
- feature rollback or kill switches
Accessibility and Internationalization
Check:
- semantic structure and accessible names
- keyboard and focus behavior
- announcements for dynamic updates
- contrast and reduced motion
- translated text expansion
- locale-aware dates and numbers
- left-to-right and right-to-left layouts
These are requirements and design constraints, not polish to add after performance work.
Security and Privacy
Cover the risks relevant to the feature:
- authentication and authorization boundaries
- output encoding and input validation
- CSRF and XSS protection
- safe token and sensitive-data handling
- content security policy
- permission minimization
- logging without exposing private data
Frontend checks improve user experience but do not replace server-side authorization.
Observability
Define signals that show whether the design works in production:
- user-centric performance metrics
- request latency and failure rate
- JavaScript errors
- feature-specific success and abandonment rates
- structured logs and trace correlation
- alerts tied to user impact
Optimization should be connected to measurements and an explicit success criterion.
Worked Example: Autocomplete Search
Requirements
- Show suggestions after the user types a short query.
- Support keyboard and screen-reader interaction.
- Keep results responsive on unreliable networks.
- Do not send a request for every keystroke.
Architecture
SearchInput
↓ debounced query
SuggestionController
↓ cached request
Search API
↓
AccessibleSuggestionList
Data Model
type AutocompleteState = {
query: string;
suggestions: Suggestion[];
activeIndex: number;
status: "idle" | "loading" | "success" | "error";
};
Interface
GET /api/suggestions?q=rea&limit=8
The response includes stable suggestion IDs, display labels and optional destination URLs.
Optimization and Deep Dive
- Debounce input while keeping typing immediate.
- Cancel or ignore stale requests.
- Cache recent queries for a short period.
- Limit and rank the response on the server.
- Use combobox semantics and predictable keyboard navigation.
- Measure response latency, selection rate and abandoned searches.
The example shows how each step narrows the next. The optimizations follow from the latency, accessibility and request-volume requirements.
Using RADIO Effectively
Treat It as a Checklist
RADIO does not require equal time for every letter. Begin with requirements, sketch the whole design, then spend depth where the problem is difficult or the interviewer shows interest.
Broad pass: R -> A -> D -> I -> O
Deep dive: A <-> D <-> I <-> O
Explain Trade-Offs
Avoid listing technologies without reasoning:
Weak: Use WebSockets.
Better: Use WebSockets because updates are bidirectional and frequent;
for server-only notifications, SSE would be simpler.
State the selected option, the requirement it satisfies, its cost and when an alternative would be better.
Common Mistakes
| Mistake | Better approach |
|---|---|
| Choosing a framework before clarifying the product | Start with users, flows, constraints and scope |
| Treating RADIO as a rigid script | Revisit stages as new information changes the design |
| Drawing only a component tree | Include state, data flow, server boundaries and failures |
| Modeling only successful data | Include loading, empty, stale, partial and error states |
| Defining endpoints without contracts | Show representative fields, errors, pagination and evolution |
| Putting all state in one global store | Classify state and keep ownership deliberate |
| Listing every possible optimization | Prioritize bottlenecks tied to requirements |
| Ignoring accessibility or security until the end | Treat them as constraints throughout the design |
| Claiming one architecture is always best | Compare alternatives and explain the chosen trade-off |
| Spending the interview on implementation code | Focus on design decisions unless code is requested |
References and Further Reading
- GreatFrontEnd: The RADIO Framework
- MDN: Web Performance
- MDN: Accessibility
- OWASP: Web Security Testing Guide
Summary
RADIO structures frontend system design by connecting requirements to architecture, data ownership, communication contracts and prioritized optimization.
Clarify the user problem and constraints
↓
Design the simplest architecture that satisfies them
↓
Make data ownership and state transitions explicit
↓
Define stable contracts between boundaries
↓
Deep-dive into the highest-impact risks and trade-offs
↓
Validate every major choice against a requirement