The Two Languages Every Good System Must Speak

Kai Nguyen

Hatched by Kai Nguyen

Jul 12, 2026

8 min read

84%

0

The hidden problem behind every query and every object

What do Python objects and SQL queries have in common? At first glance, almost nothing. One lives in application code, the other in databases. One concerns how an object introduces itself, the other how data is grouped, ranked, and transformed. Yet both are solving the same deeper problem: how to present reality at the right level of abstraction for the right audience.

That is the tension that quietly shapes good software. A system can be technically correct and still be hard to understand. It can expose too much detail, or too little. It can answer the question literally, while failing to answer the question that the reader or user actually has in mind. The best tools in programming do not just compute, they translate.

Python’s __repr__() and __str__() make this visible in miniature. SQL, especially with CTEs and window functions, makes the same idea visible at scale. Both are about giving an entity more than one voice, because no single representation serves every purpose.

Good systems are not built on one truth. They are built on multiple truthful views, each optimized for a different kind of thinking.

Why one representation is never enough

A common beginner mistake is to assume that an object or dataset has one “real” form. In practice, that belief creates confusion. An object may be perfectly understandable to the programmer in one format, but noisy or useless to the user in another. A table may contain all the right rows, but unless the rows are grouped, ranked, or partitioned appropriately, the pattern remains invisible.

This is why Python separates __repr__() from __str__(). The first is the official account, aimed at someone who needs precision, debugging, or reconstruction. The second is the human-facing description, aimed at readability and quick comprehension. If you print a timestamp, a raw coordinate pair, or a custom domain object, you usually do not want the same string in both contexts. A developer wants detail and unambiguity. A user wants meaning.

SQL reaches the same conclusion through structure. A plain query returns rows, but rows alone are often not enough. A CTE gives an intermediate name to an intermediate thought. A window function lets you compute across a group without destroying the row-level context. A PARTITION BY clause says, in effect, “These rows belong together for this calculation, but they still remain distinct.”

The surprising connection is this: both languages know that clarity emerges through controlled duplication. You do not eliminate complexity by flattening everything into one view. You manage complexity by creating the right number of views.

CTEs and __repr__(): the discipline of explicit thought

A CTE is often taught as a syntactic convenience, but that undersells its real value. It is not just a way to make SQL shorter. It is a way to name a subproblem. That naming matters because humans do not reason well about anonymous complexity. We reason by chunking. We convert a long chain of operations into a sequence of steps we can inspect.

That is exactly what a good __repr__() does for an object. It does not merely show data. It shows structure. If implemented well, it reveals the fields and state that matter for debugging and reconstruction. It says, “Here is what I am, in terms precise enough that another developer can reason from me.”

Consider a simple e commerce example. Suppose you have an Order object with dozens of fields: customer, line items, taxes, shipping method, timestamps, internal flags. A useful __str__() might say, Order #1842 for Maya, total $86.40. A useful __repr__() might say, Order(id=1842, customer_id=77, status='paid', total_cents=8640). Those are not competing truths. They are different resolutions of the same thing.

CTEs do the same for data. Imagine a query that calculates monthly revenue, filters out refunds, ranks products by sales, and joins to a category table. Written all at once, it can become a nest of conditions that is technically valid but cognitively expensive. Broken into CTEs, each step becomes legible:

  1. Clean the transactions.
  2. Aggregate by product.
  3. Rank within category.
  4. Select the top performers.

That is not just style. It is a way of respecting how human understanding works. People need intermediate objects and named stages to keep their mental stack from overflowing.

The deepest value of a CTE, like the deepest value of __repr__(), is not output. It is inspectability.

Window functions and __str__(): meaning without losing context

If CTEs and __repr__() are about precise structure, window functions and __str__() are about usable meaning.

A window function computes across a defined set of related rows while preserving each row. That is a subtle but profound idea. An aggregate function collapses the group into one summary. A window function says, “I can give you the summary, but I will not erase the original record.” If you rank sales within each region, each product still appears as itself, but now it carries contextual meaning: first, second, third. If you compute a running total, each row becomes part of a story, not just a point on a ledger.

__str__() does the same for objects. It preserves enough of the object’s identity to make it immediately useful. You do not need the full internal state when sending a message to a user, logging a friendly label, or printing a dashboard. You need the part that answers the question, “What should this look like in context?”

Think about a date object. The programmer may need an exact representation like datetime.date(2026, 7, 12). The user may need July 12, 2026. Both are true. The difference is not truth versus fiction. It is truth under different constraints.

Window functions embody the same principle in analytical work. Suppose you are building a sales dashboard and want to show each salesperson’s revenue alongside the team average and their rank within the team. A plain aggregate would hide the individual salesperson. A raw row would hide the comparison. A window function gives you both: the row and the lens.

This is why window functions feel like a superpower once they click. They allow you to answer a question about a row without leaving the row behind. That is exactly what __str__() does for an object when it chooses readability without sacrificing identity.

The real design principle: every entity needs an internal self and a social self

Once you see the parallel, a broader framework emerges. Nearly every important software artifact has at least two identities:

  • An internal self, optimized for exactness, debugging, computation, and reconstruction.
  • A social self, optimized for communication, interpretation, and decision making.

An object’s internal self is its __repr__(). Its social self is its __str__(). A query’s internal self is the chain of transformations that makes the result trustworthy. Its social self is the final shaped insight, the ranked list, the grouped summary, the reportable number.

The mistake is to force one identity to do both jobs. When that happens, one of two failures usually appears. Either the output becomes too technical for humans, or too vague for machines and maintainers. In product design, this is the difference between an interface that is powerful and one that is merely exposed. In analytics, it is the difference between a trustworthy pipeline and a pretty dashboard that nobody can audit.

A useful mental model is to ask of every artifact:

  • What is the precise form? This is what a developer, debugger, or downstream process needs.
  • What is the readable form? This is what a user, stakeholder, or report consumer needs.
  • What transformation bridges them? This is where naming, grouping, partitioning, ranking, and formatting do their work.

In this sense, good programming is not only about correctness. It is about calibrated visibility. Show enough to make the thing usable. Hide enough to make it comprehensible.

A practical rule for writing code that thinks clearly

If you are building software, this insight can change how you write both Python and SQL.

When designing a class, do not ask only, “What should printing this object show?” Ask two questions instead:

  1. What is the debugging truth of this object?
  2. What is the human truth of this object?

When designing a query, do not ask only, “Can I get the answer in one statement?” Ask instead:

  1. What intermediate ideas deserve names?
  2. What context should survive the transformation?

That leads to a simple but powerful workflow.

Start with named steps. In SQL, use CTEs to isolate each conceptual stage. In Python, structure your classes so that internal state is coherent and easy to inspect. Then add the presentation layer. In SQL, that may be a final selection with windowed annotations. In Python, that may be __str__() returning a compact, user-oriented description.

The point is not verbosity. The point is cognitive ergonomics. Each representation should reduce the cost of understanding for its intended audience.

A strong implementation often looks like this:

  • First, make it correct.
  • Then, make it inspectable.
  • Then, make it readable.

That sequence matters because readability without inspectability is fragile, and inspectability without readability is hostile.

Key Takeaways

  • Design for multiple audiences. The same object or dataset may need a developer-facing form and a user-facing form.
  • Use named intermediates to think clearly. CTEs are not just SQL convenience, they are conceptual scaffolding.
  • Preserve context when summarizing. Window functions show how to add meaning without collapsing the original row-level detail.
  • Separate precision from presentation. __repr__() is for exactness, __str__() is for communication.
  • Ask what should be visible, and to whom. Good abstractions are not about hiding everything. They are about revealing the right thing at the right moment.

The deeper lesson: clarity is relational, not absolute

The most interesting thing about __repr__() and __str__() is that neither is universally superior. The same is true of aggregates and window functions. One is not better than the other in the abstract. Their value depends on the question being asked.

That is the deeper lesson connecting Python and SQL: clarity is relational. A representation is clear only relative to a purpose, an audience, and a level of abstraction. Whenever we pretend there is one best form, we end up either overwhelming people with raw structure or starving them with oversimplification.

So the next time you write a class or a query, do not ask, “What is the one true output?” Ask something smarter: What does this need to be true for? For the debugger, for the user, for the analyst, for the future maintainer. Once you start answering that question well, your code stops merely storing truth and starts communicating it.

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 🐣