Atomic Query Construction (AQC) Query Optimization Backend Development Software Architecture Clean Code

Atomic Query Construction Design Pattern: Eliminating Repeated Query Snippets for Good

Muhammad Raheel

Muhammad Raheel

March 23rd, 2026 · 9 min read

Atomic Query Construction Design Pattern: Eliminating Repeated Query Snippets for Good

There’s a quiet lie sitting inside most codebases.

It doesn’t throw errors. It doesn’t break builds. It just sits there, multiplying. Lets understand how.

Product::where('status', 'active')->get();

You’ve written it. Everyone has.

Then somewhere

Product::where('status', 'active')->where('category_id', 2)->get();

And again:

Product::latest()->paginate();

Looks harmless. Feels normal.

It’s not.

It’s a violation of the Don’t Repeat Yourself (DRY) principle. And not a subtle one.

The Misunderstood DRY

Most developers think DRY means:

  • Don’t repeat functions
  • Don’t copy-paste logic
  • Extract reusable methods

That’s surface-level DRY.

The deeper rule is this:

Don’t repeat intent.

And that’s exactly what happens when Product::where(...) or Product::latest(...) is scattered across your application.

Because those lines are not just syntax. They encode meaning:

  • How a product query starts
  • What defaults are applied
  • What assumptions exist

Every time you rewrite them, you risk redefining that meaning.

The Real Problem: Repeated Entry Points

The issue is not the where clause itself.

The issue is the entry point:

Product::latest(...)

That’s where the query begins. That’s where logic starts taking shape.

If this entry point exists in multiple places, then:

  • You have multiple definitions of the same concept
  • You have no control over consistency
  • You’ve made future changes harder than they need to be

You didn’t just repeat code.

You repeated the starting point of logic.

The AQC Rule

Atomic Query Construction (AQC) introduces a strict rule:

Every model must have exactly one query entry point.

In practical terms:

If you search Product::latest (or any query start) across the codebase, you should find exactly one occurrence.

And it must live inside a dedicated execution class.

Not in controllers, services, jobs or helpers etc.

One place. No exceptions.

What This Actually Looks Like

Instead of scattering queries:

// Controller
Product::latest()->where('category_id', 1)->get();

// Service
Product::latest()->where('brand_id', 2)->get();

// Somewhere else
Product::latest()->paginate();

You define a single owner of that query:

class GetProducts
{
    public function handle($params = [])
    {
        $productObj = Product::latest('id');
		
        // apply filters
        if (isset($params['category_id']) && $params['category_id'] > 0) {
            $productObj->where('category_id', $params['category_id']);
        }

        if (isset($params['brand_id']) && $params['brand_id'] > 0) {
            $productObj->where('brand_id', $params['brand_id']);
        }

        // add more filters as needed

        // select columns
        if (isset($params['columns']) && ($params['columns']) > 0) {
            $productObj->select($params['columns']);
        } else {
            $productObj->select('*');
        }

        // sorting
        if (isset($params['sortBy']) && isset($params['type'])) {
            $productObj->orderBy($params['sortBy'], $params['type']);
        }

        return isset($params['paginate'])
            ? $productObj->paginate(Product::PAGINATE)
            : $productObj->get();
    }
}

And everywhere else:

(new GetProducts())->handle($params);

That’s the entire system.

What Changed?

You didn’t extract a reusable base.

You removed duplication at the root.

Before:

  • Query entry point repeated everywhere
  • Slight variations across files
  • Logic scattered and inconsistent

After:

  • One entry point
  • One owner
  • One place to evolve logic

This is not about organizing queries.

This is about eliminating multiple definitions of the same intent.

Why This Is Actual DRY

Let’s be precise:

If Product::latest('id') appears in multiple places, you are repeating yourself.

Even if everything after it is different.

Because that line defines:

  • Default ordering
  • Query starting behavior
  • System-wide assumptions

Repeating it = duplicating intent.

AQC ensures that never happens.

But This Feels Strict

Good. Because without that strictness, this falls apart instantly.

The moment you allow:

“Just this one query in a controller…”

you’re back to:

  • scattered logic
  • inconsistent behavior
  • silent bugs

AQC works because it removes that freedom.

Composition Still Exists (Just Not Where You Think)

You’re not losing flexibility.

You’re just relocating it.

Instead of composing queries across files, you compose inside the execution class using parameters.

  • Filters → params
  • Sorting → params
  • Columns → params
  • Pagination → params

One entry point. Infinite controlled variations.

The One-Entry Principle

If there’s one rule that defines AQC, it’s this:

A model should have one and only one place where its query begins.

If you search your codebase and find multiple starting points:

You are not DRY.

You are just organized duplication.

Final Thought

If Product::latest() appears in ten places in your codebase, you don’t have ten queries.

You have ten slightly different interpretations of how a product query should behave.

That’s not flexibility. That’s drift.

Atomic Query Construction doesn’t manage that drift. It eliminates it.

Comments


Comment created and will be displayed once approved.