Design & UX

Stop Building Search Features When You Should Be Building Resolution Engines

A

Admin User

Author

Jul 7, 2026
4 min read
4 views
Stop Building Search Features When You Should Be Building Resolution Engines

Last year, I spent three weeks debugging what seemed like a simple autocomplete issue in a logistics application. A user would type a shipment tracking code, and the system would sometimes return five results, sometimes fifty, sometimes none. The business logic kept failing downstream because the "correct" result wasn't always the same depending on the warehouse, the customer tier, or even the date. I kept thinking I had a UI problem. Turns out, I had an architectural problem I didn't have language for.

That's when I realized something fundamental was missing from how I approached these common business scenarios. We call them "dropdowns" or "search features" and treat them like UI concerns. But they're not. They're actually gateways to translating human language into machine language, and I was vastly underestimating their complexity.

The Difference Between Search and Resolution

Here's the thing that changed my perspective: I've been confusing two entirely different operations. A search returns results. Resolution answers a specific question: which entity does the user actually mean?

When a user types "PROD-001" in a sales order, they're not just searching for products. They're providing a business reference within a specific context. That context matters enormously. The same product code might have different pricing for different customers, different availability depending on warehouse location, or different applicability based on document date. The system needs to know all of this to resolve the reference correctly.

In my logistics example, that tracking code wasn't unique in isolation. It only became unambiguous once the system understood the warehouse, the shipment type, and the time period we were querying. Without that context, the reference was too broad to resolve properly.

Building the Right Mental Model

What I appreciate most about framing this as the "Locator Pattern" is that it separates the concept from its implementation. The resolution process isn't a ComboBox. It's not a search box. It's not UI at all—it's a process.

This process can live anywhere. A desktop application needs it. A web application needs it. An API endpoint needs it. A background import job needs it. The interface changes, but the core logic shouldn't. When I started thinking about it this way, I realized I'd been duplicating this logic in multiple places across my applications.

The Critical Distinction: Ambiguity vs. Failure

There's a concept here I'd never explicitly considered before: the difference between business ambiguity and resolution failure.

If a product code returns five possible matches, that's business ambiguity. The user can disambiguate by providing more information. But if it returns five thousand matches? That's not a UI problem to be solved with a better dropdown. That's a business reference that's too broad. The system shouldn't ask the user to choose from five thousand items. It should ask for a better reference.

This distinction has actually changed how I handle validation in my applications. Instead of just showing users a list, I now validate whether the reference itself is specific enough within the context.

Where I'd Push Back (Slightly)

I agree with the core argument, but I think the article undersells one practical concern: performance at scale. Resolving a business reference correctly might require querying multiple related entities, checking business rules, evaluating date-based policies. This gets expensive quickly.

I've started implementing caching and background pre-computation for common resolution patterns. If a sales order is querying product pricing based on customer tier and date, I cache that resolution result. This keeps the synchronous resolution fast while maintaining correctness.

A Quick Pattern I'm Using

Here's how I've started structuring this in recent projects:

interface ResolutionContext {
  businessReference: string;
  context: {
    customerId?: string;
    warehouseId?: string;
    documentDate?: Date;
    customerTier?: string;
  };
}

interface ResolutionResult<T> {
  status: 'resolved' | 'ambiguous' | 'not_found' | 'reference_too_broad';
  canonicalId?: string;
  candidates?: T[];
  projection: T | null;
}

// Usage in a service
const resolveProduct = async (
  ref: ResolutionContext
): Promise<ResolutionResult<Product>> => {
  // 1. Find candidates matching the reference
  // 2. Apply business context filters
  // 3. Check if result is usable or too broad
  // 4. Return appropriate status and projection
};

This structure forces me to think about resolution as a distinct concern and makes the possible outcomes explicit.

The Question This Raises for Me

If we're treating resolution as an architectural pattern rather than a UI detail, shouldn't we have better tooling and frameworks for declaratively defining these patterns? The article hints at this in the closing, and I genuinely wonder what the answer looks like.

What patterns are you using for this in your applications? Are you also accidentally treating resolution as a search problem?

Source: This post was inspired by "Fundamental Concepts of Business Applications II: The Locator Pattern" by Dev.to. Read the original article

Share this article

Written by Adil Sher

Full stack developer building high-traffic platforms, AI services, and custom web applications. Explore my portfolio, learn about my background, or get in touch.

Related Articles

Voice-First Interfaces Aren't The Future—They're Already The Necessity
Design & UX Jul 4

Voice-First Interfaces Aren't The Future—They're Already The Necessity

Last month, I was sitting in a small convenience store in F-10 Islamabad, waiting for my order. The shopkeeper was manually writing entries in a ledger while managing three phone calls and a queue of customers. I watched him fumble with a pos system on an old tablet—it was clearl...