DEV Community

Cover image for Why Learn Binary Search When You're Paid to Build Buttons?
Anton Trishin
Anton Trishin

Posted on

Why Learn Binary Search When You're Paid to Build Buttons?

Hi!

There's been an ongoing debate among developers for years: do algorithms really matter in everyday software development, or are they just dry theory for passing coding interviews? I decided to join the discussion.

When I started my career as a frontend developer, I constantly asked myself questions like: "Why do interviewers ask me to traverse graphs if all I do at work is adjust CSS margins?" or "Why should I know Big O notation if my layout still breaks in Safari?" With the rise of artificial intelligence (AI), these questions have become even more common: "Why should I think at all if an AI agent can write this loop for me?"

However, as I improved my algorithmic skills, I began to notice their practical applications in real-world development—especially when the task involved something more complex than vertically centering a div. I learned to design cleaner implementations of business features, identify performance bottlenecks more quickly, and, most importantly, gained confidence in my own decisions.

There's an important nuance here: yes, you can write a good prompt and get optimized code from an AI in seconds. End of story, right?

Not quite.

The responsibility for a feature still lies with the developer, and when a bug appears, you're the one who has to fix it. But how can you fix a bug if you don't understand how the function works? You can keep feeding prompts to an LLM and hope for the best, but sooner or later that turns into an endless cycle of trial and error.

LLMs are excellent at generating code, but they usually don't know the constraints of your particular project. They don't know how many users your system serves simultaneously, what your memory limitations are, or where the actual bottlenecks lie. The better a developer understands the algorithms behind a feature, the more accurately they can instruct the model—and the faster they can distinguish an efficient solution from one that merely looks elegant.

If you clearly understand the algorithm behind a feature, you'll have no trouble extending or improving the solution yourself, or guiding the same LLM in the right direction much more effectively.

Based on my own experience, I've come to the conclusion that algorithms are neither an end in themselves nor just abstract LeetCode exercises. They're a foundation that gives frontend developers three key advantages:

Faster development by relying on well-known, time-tested algorithmic patterns.
Higher code quality and more mature engineering decisions when designing component architecture.
A direct impact on the business through better performance, interface stability, and user experience (UX).

Below are several examples of how classic algorithmic ideas appear in everyday frontend development. For each example, I've included a link to a similar LeetCode problem to make it easier to connect the learning exercise with its practical application.

Two Sum: Fast Data Lookup

Imagine an online store where a customer adds an item to their shopping cart. The system needs to determine whether that item is already in the cart so it can either increase the quantity or create a new entry.

A naive approach would iterate through every item in the cart each time a product is added. While this works for small carts, performance degrades as the number of items grows.

In real-world systems, this logic is typically implemented using a key-value data structure, where productId serves as the key. This makes it possible to quickly check whether an item exists and update its quantity without traversing the entire collection:

if (cart.has(productId)) {
  cart.get(productId).count++;
} else {
  cart.set(productId, { count: 1 });
}
Enter fullscreen mode Exit fullscreen mode

At first glance, this looks like a simple in-memory collection operation. In practice, however, the same idea is often hidden behind databases, indexes, or caching layers, where existence checks and updates are performed through fast key-based lookups. The same principle also applies on the client side—for example, when organizing data in a state management solution.

This is exactly the principle demonstrated in LeetCode #1 (Two Sum). Instead of performing a linear scan of the collection, the solution uses a hash-based data structure to instantly access previously seen elements. In one case, we're looking for two numbers whose sum matches a target value; in the other, we're managing the state of a shopping cart. The context is different, but the underlying algorithmic pattern is the same: replacing a full scan with a key-based lookup.

LRU Cache: Data Caching

Imagine a typical web application. Every time a user opens a page, the application requests configuration data—feature flags, UI settings, available languages and currencies, and other reference information.

While the user navigates through the application, this configuration rarely changes. Without caching, however, the frontend continues sending the same requests over and over again. As a result, the API receives unnecessary load, the number of network requests increases, server-side rendering (SSR) slows down, and Web Vitals suffer.

The solution is to use a cache that evicts the least recently used entries:

const key = "/api/config?locale=ru&currency=RUB";

let config = cache.get(key);

if (config === -1) {
  config = await api.get(key);
  cache.put(key, config);
}

return config;
Enter fullscreen mode Exit fullscreen mode

From the outside, this looks like ordinary caching. Internally, however, cache.get() and cache.put() implement the same logic as the LRU Cache problem in LeetCode #146. Every time an entry is accessed, it is marked as "recently used." When the cache reaches its capacity, the least recently used entry is automatically removed.

Algorithms like this are used every day in real-world systems and have a direct impact on application performance and stability.

Merge Intervals: Working with Time Ranges

Now let's consider a meeting room booking system. The frontend receives a list of occupied time intervals and needs to display them as a timeline in a calendar.

In many cases, the data contains overlapping or adjacent intervals—for example, after synchronizing schedules from multiple sources. To display a clean and continuous schedule instead of a collection of fragmented blocks, the data must first be normalized.

Before processing:

09:00–10:00
09:30–11:00
11:00–12:00
13:00–14:00
13:30–15:00
16:00–17:00
Enter fullscreen mode Exit fullscreen mode

After processing:

09:00–12:00
13:00–15:00
16:00–17:00
Enter fullscreen mode Exit fullscreen mode

This task is usually handled on the backend or at the database level. However, in some situations—such as applying local changes or merging data from multiple sources—it may also be performed on the client.

This is exactly the problem solved by LeetCode #56 (Merge Intervals), which merges overlapping intervals into the smallest possible set of non-overlapping ranges.

This algorithm is commonly used when building calendars, timelines, scheduling interfaces, and any application that works with time intervals.

Promise Time Limit: Controlling API Timeouts

Imagine a web application that fetches data from multiple external services during page load. Under normal conditions, the APIs respond within 100–200 ms. However, due to network issues or heavy load, a request may occasionally hang for tens of seconds.

If you simply wait for the Promise to resolve, users may end up staring at a loading indicator indefinitely, while server-side rendering (SSR) becomes significantly slower. That's why production applications almost always enforce request timeouts:

const data = await timeLimit(
  () => api.get("/api/profile"),
  3000
);
Enter fullscreen mode Exit fullscreen mode

If the API doesn't respond within three seconds, the request is canceled, and the application either displays an error message or falls back to an alternative solution.

LeetCode #2637 (Promise Time Limit) formalizes this scenario by implementing an asynchronous operation with a strict time limit.

Strictly speaking, Promise Time Limit is not a classical algorithm like binary search. It's better described as an engineering pattern for managing asynchronous operations. Nevertheless, problems like this develop an essential skill: limiting execution time, handling failures gracefully, and designing resilient systems.

Top K Frequent: Finding the Most Popular Items

Most online stores have sections such as "Popular Products," "Frequently Bought," or "Recommended for You." In large-scale systems, this functionality is usually implemented at the database or analytics layer using aggregations, indexes, or specialized analytics platforms.

However, if you need to implement this logic yourself, the core problem is frequency counting: given a large stream of events, find the K most frequently occurring items. This is exactly the pattern formalized by LeetCode #347 (Top K Frequent Elements).

Of course, this is far from a complete list. Frontend development offers many other examples where algorithmic ideas appear in practice. For instance, binary search is used internally by list virtualization libraries such as react-virtualized and TanStack Virtual to efficiently determine which items should be rendered as the user scrolls.

Understanding algorithmic principles allows developers not only to use existing tools effectively but also to design solutions tailored to the specific requirements and constraints of their own products.

Conclusion

In my opinion, algorithms aren't something you learn just to argue on the internet or climb the LeetCode rankings. Their real value lies elsewhere—in understanding what solution patterns exist and how they behave in real-world systems.

This has a direct impact on the product. It helps you find scalable solutions more quickly instead of relying on simple but costly workarounds, and gives you a deeper understanding of what's happening under the hood of the tools you use every day—from databases and caching systems to modern frameworks.

The better a developer recognizes these patterns, the more likely they are to build not just code that works, but architecture that remains reliable as traffic, data volume, and overall system complexity continue to grow.

Top comments (0)