Back to writing
product-thinkingsystem-designsoftware-engineering

From UI Components to Product Thinking

How shifting from interface-first to user-first thinking changed the way I approach software engineering.

12 min read

Introduction

When I first started building applications, I began with the interface. Before writing an API or designing a database table, I wanted to know what the application would look like: which screens it needed, how they connected, and what users would click.

At the time, I saw the backend mostly as a service for the frontend—a place to fetch and store data after the visible part of the work was done.

Working on larger projects, especially Hypertube, changed that assumption. A search bar was not just an input with a results page behind it. It raised questions about what users could search for, how results should be grouped and ranked, and how filters and pagination should behave together. “Continue Watching” was not just a row of movie cards. It depended on playback progress, stored state, watch history, and a homepage that could reflect the user’s most recent activity.

Even language support reached beyond translated labels. It affected user preferences, movie metadata, subtitle choices, API responses, and the UI that connected them.

I started to see that the interface and backend were not separate layers handed off to one another. They were different expressions of the same product decision. The experience a user sees is only possible when the systems beneath it are reliable, flexible, and coherent.

Today, I do not think of UI as making an application look polished. I think of it as designing an experience—and then designing the system that makes that experience feel natural.

UI Is Not the Product

is easy, especially early on, to treat the interface as the product. We spend hours refining layouts, choosing colors, and polishing interactions because those are the parts we can immediately see.

But users do not open a streaming platform because they want to admire its card layout. They open it because they want to find something to watch, return to something they started, or understand what to play next.

That changes what “good” means.

A polished movie card matters, but it cannot compensate for a search experience that makes the right title hard to find. A beautiful homepage loses its value if it does not reflect where a user left off. A language switch feels incomplete if the interface changes but the available metadata or subtitles do not support the user’s choice.

The interface is the medium through which people interact with the system. The product is the whole experience: the speed of a response, the consistency of data, the clarity of a flow, and the confidence that the application will remember what matters.

On Hypertube, that meant treating the visible UI as a promise. If the homepage showed “Continue Watching,” the system had to make that promise true. If search suggested that content was easy to find, the API and result design had to support that expectation.

💡 Engineering Insight

UI creates expectations. Engineering determines whether the product can keep them.

Every Screen Starts With a User Goal

As I worked on more complex applications, I stopped thinking about pages first and started thinking about intentions. Every screen, component, and interaction should earn its place by helping someone move toward a goal.

Before implementing a feature, I began asking different questions:

  • Who is this for?
  • What are they trying to do right now?
  • What is the shortest clear path to that outcome?
  • Is this information helping, or is it only adding complexity?
  • What happens if we remove it?

Those questions often lead to better decisions than asking which feature should come next. Sometimes the right answer is not to build more. It is to remove a step, avoid another state to manage, or make an existing action easier to discover.

Hypertube made this practical. The homepage was not there to fill space with movie cards. Its job was to help a returning user resume a movie or help a new user choose something worth watching. That is why a “Continue Watching” section has a different role from a general movie collection: one helps users recover context; the other supports discovery.

Search had a similarly specific goal. It was not about showing every possible result. It was about reducing the effort required to find the right movie or profile. Once I looked at it that way, questions about filters, result types, ordering, and pagination were no longer isolated implementation details. They became part of the same question: does this help the user get where they are trying to go?

Lesson learned

A feature becomes easier to design when its user goal is more precise than its UI label.

Designing Flows Instead of Pages

One of the biggest changes in my thinking was realizing that users do not experience applications one page at a time. They experience a sequence of decisions.

A user does not open a streaming platform because they want to visit the homepage. They open it because they want to watch something.

That simple observation changes the role of every part of the product. The homepage should help them resume something familiar or discover something new. Search should reduce the time it takes to find a specific title. The movie page should provide enough context to make a decision without becoming a wall of information. The player should fade into the background so the content—not the controls—remains the focus.

On Hypertube, these were not independent screens. They formed a loop. A user could discover a movie, open it, start watching, leave, and return expecting the homepage to remember that context. The last step changes the first one: playback is not finished when the player closes, because its progress becomes input for the next visit.


## User Flow

1. **Open Hypertube**
   
   ↓

2. **Resume or discover a movie**
   
   ↓

3. **Open movie details**
   
   ↓

4. **Play movie**
   
   ↓

5. **Save playback progress**
   
   ↓

6. **Refresh Continue Watching on the next visit**

Thinking in flows made engineering decisions more concrete. It clarified which state needed to survive navigation, which data belonged in APIs, and where consistency mattered most. Instead of optimizing individual pages in isolation, I could evaluate whether the entire journey still felt coherent.

Trade-off

A page can look complete on its own while the overall flow still fails. The unit of ?>quality is the journey, not the screen.

Every Product Decision Becomes an Engineering Decision

The lesson that changed the way I build software most is that product decisions and engineering decisions are never independent.

Take Continue Watching in Hypertube. For a user, it is simply a row that lets them resume a movie. That simplicity creates a system-wide contract: when the product says “continue,” it needs to know what the user watched, where they stopped, and which progress should be shown when they return.

That touches more than a component. Playback has to produce progress updates. The application has to store them reliably. Watch history and homepage data need to reflect the same source of truth. The homepage also needs to load that information efficiently enough that the feature still feels immediate.

## Playback Progress Flow

1. **User plays a movie**

   ↓

2. **Playback progress changes**

   ↓

3. **Progress is persisted**

   ↓

4. **Watch history and homepage data reflect it**

   ↓

5. **Continue Watching can resume the right movie**

Search introduced a different kind of product decision. Allowing users to search movies and profiles makes the product more useful, but it also creates questions: should different result types appear together or separately? What is the useful ordering? How do filters, sorting, and pagination work without making the results difficult to understand? The answer cannot live only in the UI or only in the backend. The API has to expose data in a shape the interface can explain clearly. Localization made the same point from another direction. Changing a language is not just translated interface text. It influences stored preferences, which metadata is useful, what subtitles are available, and how those choices are represented across the system.

## Language Preference Flow

1. **Language preference**

   ↓

2. **API response and movie metadata**

   ↓

3. **Available subtitles**

   ↓

4. **Playback and interface choices**

These experiences taught me that there are very few purely “frontend” or “backend” features. Most useful features are cross-system agreements. The interface expresses the agreement, while APIs, data models, application state, and background work make it dependable.

Engineering insight

When a feature looks small in the UI, map the systems it touches before estimating the work.

Simplicity Is Often the Hardest Thing to Build

As users, we rarely notice the engineering behind a good experience. We remember how effortless it felt, not how much work it took to make it feel that way.

One of the biggest lessons I learned is that simplicity is not the absence of complexity. It is the result of putting complexity in the right place.

A “Continue Watching” button can hide authentication, stored progress, API communication, state updates, and the logic required to show the right item at the right time. Search can feel immediate only when the application handles filtering, loading, and result presentation without forcing the user to understand any of it. A language choice can appear small while connecting preferences, metadata, subtitles, and UI state.

The goal is not to pretend the complexity does not exist. It is to prevent users from carrying it themselves.

That changed how I measure quality. I no longer judge an interface by how many options it exposes or how visually impressive it looks. I ask how much thinking it asks of the user. Can someone find a movie, understand what happens next, and recover their place without having to learn the system first?

The best engineering often goes unnoticed because it makes the product feel unsurprising. Everything appears where the user expects it, and the system behaves consistently enough that they can focus on what they came to do.

Lesson learned

Internal complexity is sometimes necessary. User confusion is not.

What Changed in the Way I Build Software

Looking back, the biggest change was not learning a new framework or adopting a different technology. It was changing what I ask before writing the first line of code.

I used to begin with components and tables: what pages do I need, and what data do they require? Now I begin with a simpler question: what problem am I trying to solve for the user?

From there, the technical work has a clearer direction. The user journey shapes the interface.

The interface reveals the data it needs. That data informs the API contract and the data model.

The architecture then evolves around the experience instead of being designed as a separate exercise.

## Product Design Flow

1. **User goal**

   ↓

2. **User flow**

   ↓

3. **Interface and states**

   ↓

4. **API contract**

   ↓

5. **Data model and system boundaries**

This has also changed how I evaluate new features. “Can we build this?” is usually only the first question. “Should we build this?” is often more important. Every new capability adds states, maintenance work, edge cases, and future decisions. Sometimes simplifying an existing experience is more valuable than adding another option.

It also means thinking about performance, accessibility, localization, maintainability, and future change earlier. They are not final polish after the feature is complete. They are constraints that help define what a good feature should be in the first place.

I am still learning, and each project exposes a new set of trade-offs. But Hypertube made one principle stick: good software is not built by connecting technologies together. It is built by understanding people first, then designing systems that quietly help them achieve what they came to do.

A Different Way of Thinking

When I first started programming, I thought of software as a collection of pages connected by APIs. My goal was to implement features, make them work, and move on to the next task. Today, I see the work differently.

Building pages taught me how to make an interface usable. Building user experiences taught me to think about what happens before and after each interaction. Hypertube pushed that one step further: it taught me to think in systems.

A search field, a subtitle selector, a homepage row, and a playback control can look like separate pieces of UI. In practice, each one is connected to decisions about data, state, reliability, and the user’s next step. Every engineering choice either reduces or adds friction between a person and what they are trying to do.

Frameworks, databases, and programming languages will change. The tools will keep evolving. But the principles behind good product engineering are more durable: understand the user’s goal, make the path clear, manage complexity where users do not have to see it, and design each part of the system to support the others.

Hypertube taught me that the work is not finished when a feature renders. It is finished when the whole experience holds together.

That is the mindset I want to keep developing: not just building pages, and not only shipping features, but designing systems that make technology feel useful, reliable, and human.