Readable Code Starts Where the Database Can Still Think

Kai Nguyen

Hatched by Kai Nguyen

Jun 14, 2026

10 min read

87%

0

The hidden similarity between clean classes and fast queries

Most engineers learn object design and SQL optimization as if they belong to different planets. One is about elegant classes, interfaces, and maintainable software. The other is about indexes, execution plans, and shaving milliseconds off a query. But the deeper question connecting them is strangely human: how do you make intent legible to a system that cannot infer what you meant?

That question matters because both Python objects and SQL queries fail for the same reason. They become expensive when they force the engine to guess. A class hierarchy becomes brittle when one class tries to do too much, when responsibilities blur, or when dependencies spread everywhere. A SQL query becomes slow when the database cannot use the structure you gave it, because you wrapped an indexed column in a function, hid it behind a negation, or asked for sorting before filtering. In both cases, the system is not “dumb.” It is literal.

That is the bridge: good design is not decoration, it is a form of machine-readable clarity. Whether you are shaping objects or shaping queries, the goal is the same. Make the important path obvious. Reduce ambiguity. Let the engine, whether it is a compiler, a runtime, or an optimizer, do its best work without heroic interpretation.


Why complexity is expensive only when it blocks the obvious path

Complexity is often misunderstood. People think complexity means “many lines of code” or “many clauses in a query.” But the more dangerous kind is structural opacity. A query with ten clauses can be perfectly efficient if it preserves a clean path to the index. A tiny query can be disastrous if it turns a searchable column into an expression the database can no longer optimize.

The same is true in object-oriented design. A class is not unhealthy because it has methods. It is unhealthy when those methods pull in unrelated responsibilities, making it hard to change one thing without touching everything else. The cost is not size, but coupling. Once responsibilities merge, each change has to navigate a larger mental and technical surface area.

Think of a city. A well-designed city can be large and dense, yet still easy to traverse because roads, neighborhoods, and transit lines have clear roles. A badly designed city can be much smaller and still frustrating, because every route forces detours. SQL optimization works the same way. If your WHERE clause is structured so that the database can go straight to the relevant rows, it moves like a metro system. If your conditions force it to inspect rows one by one, it behaves like a car stuck in traffic.

This is why practices like SARGability matter so much. A searchable predicate is not just a performance trick. It is a statement of respect for the optimizer. It says: here is the path, use it. Avoid the temptation to make the database solve a puzzle that could have been stated plainly.

The fastest system is usually not the one that works hardest. It is the one that can recognize your intent with the least translation.


SOLID and SARGable are both about preserving useful boundaries

The famous design principles behind clean object-oriented code all point toward one idea: keep boundaries meaningful. A class should have one job. It should be open to extension, closed to reckless modification. It should depend on abstractions rather than concrete entanglement. Those principles are not just about elegance. They are about preserving the ability to change one thing without dragging the rest of the system through the mud.

SQL optimization has an equivalent philosophy. A query should expose the structure the database needs in order to use indexes and reduce work. It should filter early, avoid unnecessary sorting, avoid calculations that defeat indexing, and limit the result set when possible. In other words, the query should keep its boundary with the underlying data as clean as possible.

Here is the surprising connection: both domains reward designs where the expensive work stays local. In object design, localizing responsibility means a feature change touches one class, not five. In SQL, localizing work means the database can narrow candidates early instead of scanning the world. Good boundaries shrink blast radius.

A practical example helps. Imagine a user search feature. One version of the code keeps all search logic in one large service object, with rules for filtering, formatting, permission checks, and pagination all tangled together. Another version separates concerns: one component determines access rules, another builds the query, another handles presentation. If the query component also expresses its conditions in a way that preserves index usage, the whole system becomes easier to evolve and faster to run.

That is the real lesson: clarity compounds across layers. A cleaner class design can make query construction clearer. A better query structure can influence how you model the data access layer. When the boundaries are clean, each layer communicates intent to the next one instead of smuggling complexity downward.


The optimizer is your collaborator, not your janitor

There is a subtle but important mistake many developers make. They treat the database optimizer as a magical cleanup crew. They write whatever feels convenient, then assume the database will figure it out. Sometimes it does. Often it cannot, at least not without paying a significant price.

This mindset has a parallel in object-oriented code. A developer can create a giant class with many behaviors and assume the language runtime will keep everything manageable. But the runtime cannot rescue poor boundaries forever. Eventually, the design becomes harder to test, harder to reason about, and harder to extend. The machine can execute your code, but it cannot restore the architecture you failed to design.

A better mental model is this: the optimizer is a collaborator that works best when you speak clearly. If you want it to use an index, express a predicate that can be searched directly. If you want maintainable code, express responsibilities directly. If you want a system to scale, do not bury intent inside layers of unnecessary transformation.

Consider the classic anti-pattern of applying a function to an indexed column in a WHERE clause. Something like LOWER(name) may feel convenient because it simplifies matching logic, but it can prevent the database from using the index on name. The optimizer is then forced to inspect more rows than needed. In object terms, this is like putting transformation logic inside a core entity where it does not belong, making the object responsible for both its meaning and every possible presentation of itself.

This is why the simplest-looking query is often the most advanced one. It does not merely request data. It preserves the conditions under which the database can think efficiently. The same is true of the simplest-looking class. It does not merely contain methods. It preserves the conditions under which the system can change safely.


A unifying framework: reduce semantic distance

If there is one concept that unites these ideas, it is semantic distance. Semantic distance is the gap between your intention and the form in which the system can use it.

When semantic distance is low, the machine sees your meaning almost directly. A class does one thing. A query filters with a predicate that aligns with an index. A dependency points to an abstraction. A result set is limited before unnecessary work is done. The system spends time on the actual task rather than on interpreting your structure.

When semantic distance is high, intent gets wrapped in extra layers. A class becomes a catch-all. A query hides searchable conditions inside expressions or functions. Sorting happens before filtering. The database must infer more, and the codebase becomes harder to maintain.

This framework helps explain why seemingly unrelated best practices belong together:

  1. Single responsibility reduces the number of reasons a component changes.
  2. Searchable predicates reduce the number of rows a database must examine.
  3. Abstraction boundaries reduce the number of places where implementation details leak.
  4. Early filtering reduces unnecessary work before expensive operations.
  5. Avoiding needless transformations keeps the path from intent to execution short.

Seen this way, design is not about making things “pretty.” It is about minimizing translation cost. Every translation step introduces risk: more bugs, more ambiguity, more missed optimization opportunities.

The best architecture is not the one that looks smartest. It is the one that stays closest to the shape of the problem.


How to apply this thinking in real systems

Let us make this concrete with a common scenario: a product dashboard that shows a list of orders. The dashboard needs to support filtering by date, status, customer name, and sort order. The naive approach is to keep adding logic wherever it seems convenient. A service object checks permissions, assembles SQL, applies date math to columns, formats results, and returns everything in one go.

That feels efficient at first because there is less code to write. But it quietly destroys the optimizer’s options and the codebase’s future flexibility. If the query wraps the order date in a function, indexes may be ignored. If the same class also handles formatting and business rules, changes to the UI can ripple into data access. If pagination is added late, sorting may become expensive for the wrong reasons.

A better design separates the concerns by what they ask the system to do:

  • Business rules decide what the user is allowed to see.
  • Query construction expresses filters in index-friendly form.
  • Pagination limits result size before costly operations where possible.
  • Presentation formats the data after retrieval.

The result is not just cleaner code. It is code that lets the database answer the question efficiently. You are designing for two readers at once: the human maintainer and the query optimizer. The best solution serves both.

This is also why performance work should happen earlier than most teams think. If you only optimize after the system is slow, you are often forced into desperate, local fixes. But if you design with semantic distance in mind, many performance wins arrive for free. A query that can use an index is not a micro-optimization. It is a consequence of writing the query in the shape the engine understands.

Similarly, a class with one responsibility is not an aesthetic preference. It is an operational advantage. It becomes easier to test, easier to swap, easier to understand, and easier to extend without accidental regressions.


Key Takeaways

  • Write for the next reader of your intent, whether human or machine. If a class or query makes the desired path obvious, it is easier to maintain and faster to execute.
  • Protect boundaries. In code, that means clear responsibilities and abstractions. In SQL, that means predicates and query shapes that preserve index usage.
  • Filter early and transform late. Reduce the amount of work before sorting, grouping, formatting, or other expensive operations.
  • Avoid hiding searchable logic inside functions or expressions. If the database cannot see the column plainly, it may not be able to use the index efficiently.
  • Treat optimization as a design outcome, not a cleanup task. The fastest systems are usually the ones that were structured to be understood from the beginning.

The deeper lesson: clarity scales better than cleverness

There is a temptation in software to admire cleverness, especially when it seems to compress many concerns into one elegant construct. But cleverness often shifts cost somewhere less visible. It may save a few lines of code while imposing a tax on every future change. It may make a query look neat while hiding the very structure the database needs to run it efficiently.

Clarity scales differently. It may feel less dramatic in the moment, but it compounds over time. A clear class boundary survives refactoring. A clear predicate stays indexable. A clear separation of concerns keeps both code and data accessible to the systems that must operate on them.

So the next time you write a class or a query, ask a more powerful question than “Does this work?” Ask: Can the system see what I mean without guessing? If the answer is yes, you are not just writing better code. You are designing a conversation between intent and execution that is cheap to understand and cheap to run.

And that, more than any isolated principle, is what makes software durable: not brilliance in isolation, but structures that remain legible when the system, and the requirements, get bigger.

Sources

← Back to Library

Hatch New Ideas with Glasp AI 🐣

Glasp AI allows you to hatch new ideas based on your curated content. Let's curate and create with Glasp AI :)

Start Hatching 🐣
Readable Code Starts Where the Database Can Still Think | Glasp