The Hidden Architecture of Good Systems: Why Code and Data Both Reward Strong Boundaries

Kai Nguyen

Hatched by Kai Nguyen

May 30, 2026

9 min read

82%

0

The real problem is not complexity, it is boundary failure

Most people think software gets hard because there is too much of it. In practice, it gets hard for a different reason: everything starts to know too much about everything else. A class reaches into another class’s internals. A query assumes a table shape that no one dares to change. A small update in one place sends ripples through the rest of the system. The result is not just messy code or awkward SQL. It is a system that resists change because its parts have no disciplined borders.

That is why object-oriented design principles and SQL are more connected than they first appear. One is a guide for organizing behavior inside code. The other is a language for asking structured questions of data. But both are really about the same deep issue: how to create useful relationships without creating dependency chaos.

The temptation in software is always to optimize for immediate convenience. Put the logic here, the data there, the query wherever it is easiest. But convenience compounds into fragility when no one defines what belongs where. The deeper question is not, “How do we build systems that do everything?” It is, “How do we build systems whose parts can evolve without constant collateral damage?”

Good systems are not the ones with the fewest parts. They are the ones whose parts can change without surprising each other.


SOLID and SQL both teach the same discipline: ask each layer to do one job

The most powerful idea behind SOLID is not memorizing five acronyms. It is learning to respect the shape of responsibility. A class should have one reason to change. Abstractions should depend on stable contracts, not fragile details. Interfaces should be small enough that callers are not forced to care about irrelevant features.

SQL, at its best, follows a similar discipline. It lets you retrieve, combine, aggregate, and update data through a clear declarative interface. You tell the database what you want, not how to grind through rows one by one. That separation matters because it keeps the act of asking distinct from the act of storing. A query is not supposed to become a tangled miniature program that also knows business rules, presentation logic, and workflow sequencing.

Think of a restaurant. The kitchen prepares food, the server communicates orders, and the dining room shapes the experience. If the server starts cooking or the kitchen starts designing the menu on the fly for every table, the operation becomes brittle. Likewise, if a class both manages business policy and formats database rows, or if a query is forced to encode the whole application’s decision making, the boundary is broken.

The insight is simple but profound: structure is not bureaucracy, it is insulation. When responsibilities are cleanly separated, local change stays local. When they are not, every change becomes a negotiation with the entire system.

SQL makes this visible in a concrete way. A well shaped query can join multiple tables, group records, or use subqueries to derive answers without mutating the schema of the world around it. The query is powerful precisely because it is constrained. It can combine many things, but it does so through rules that preserve the integrity of the underlying model.

That is very close to the spirit of SOLID. A class should expose the minimum necessary surface area. A table relationship should reflect the minimum necessary assumption. Both are forms of designed restraint.


The mistake most developers make: they confuse flexibility with boundarylessness

There is a seductive myth in software design: if we keep everything accessible, we will remain flexible. In reality, unlimited access destroys flexibility because it makes every component aware of too much. Once a class depends on implementation details, replacing that class becomes hazardous. Once a query depends on an exact table layout, changing the schema becomes risky. The system becomes “flexible” only in the narrow sense that it can be hacked quickly today, while becoming harder to evolve tomorrow.

This is where the connection between design principles and SQL becomes especially useful. SQL teaches you that even powerful operations should happen through a controlled interface. You can join many tables, but you do not directly poke into memory structures. You can aggregate records, but you do not rewrite the storage engine in the process. The language gives you leverage through abstraction.

A good class design works the same way. The class should not expose all of its gears simply because someone may someday want to adjust them. Instead, it should offer stable operations that remain meaningful even as the internals evolve. That is what makes software maintainable. Not total openness, but selective permeability.

Here is a practical analogy. Imagine a spreadsheet where every formula references raw cell positions all over the file. Move one row, and half the workbook breaks. Now imagine named ranges and clear sections. The sheet can still be intricate, but the complexity is organized around boundaries. SQL tables and SOLID classes are both better when they behave like the second spreadsheet, not the first.

This also explains why many systems degrade over time. They are not overengineered in the abstract. They are underbounded. Responsibilities leak across layers until no one can tell whether a rule belongs in the database, the query, the model object, or the service layer. At that point, complexity is no longer a property of the problem. It is a property of the architecture.

A system becomes fragile when the cost of understanding one part includes understanding everything else.


A useful mental model: every layer should have a “translation budget”

One way to synthesize these ideas is to think in terms of a translation budget. Every time information crosses a boundary, it must be translated: rows become objects, objects become queries, queries become results, results become decisions. Healthy systems keep these translations purposeful and limited. Unhealthy systems let translation become interpretation, and interpretation become policy.

A SQL query is a translator. It turns relational structure into an answer set. A well designed class is also a translator. It turns domain intent into operations without leaking storage details or irrelevant mechanics. The trouble starts when a layer spends too much of its budget. If a query contains business rules, formatting logic, and optimization hacks all at once, it is doing too much translation. If a class also acts as a table mapper, a validator, and a workflow coordinator, the same problem appears.

Consider a simple example: an online store needs a report of customers whose lifetime purchases exceed a threshold. One unhealthy approach is to scatter the logic across code, manually iterate through rows, compute totals in application memory, and then decide who qualifies. Another approach is to let SQL handle the aggregation with grouping, then pass the result into a small, focused component that applies the final policy. The second approach is not just faster. It is cleaner because each layer performs the kind of work it is best suited for.

This translation budget idea reveals a deeper compatibility between SQL and SOLID. Both are about keeping responsibility proportional to capability. SQL is excellent at set based retrieval and aggregation. Classes are excellent at encapsulating behavior and preserving invariants. When each layer does what it naturally does best, the system gains both clarity and adaptability.

You can use this as a diagnostic question: Is this code translating, or is it deciding? If a layer is both moving data around and making core decisions, it is probably spending too much of the budget. That is often where complexity hides.


The deepest connection: boundaries are how systems remember what they are

The most interesting thing about SOLID and SQL is that neither is primarily about restriction. Both are about identity. A class with a single responsibility knows what it is for. A query that aggregates data knows what kind of answer it is producing. A table with clear relationships knows what facts it stores and what facts it does not.

That matters because systems fail when they forget their own shape. A class starts acting like a database, a database becomes a policy engine, and the application layer becomes a dumping ground for exceptions. At that point the architecture no longer mirrors the domain. It mirrors the improvisations of the last six months.

SQL’s declarative style is a powerful reminder that some of the best leverage in software comes from not specifying every step. Instead, you define the goal and trust the system beneath you to optimize execution. SOLID encourages the same humility in object design. Do not make a class responsible for everything simply because you can. Design the public surface so that callers can rely on outcomes without knowing the internals.

This gives us a broader principle: healthy software is organized by promises, not by convenience. A class promises a stable behavior. A query promises a stable shape of result. A table relationship promises a stable meaning of data. The more faithfully those promises are kept, the less the system depends on tribal knowledge.

That is why maintainability is not just about fewer bugs. It is about preserving meaning over time. When boundaries are clear, future developers can ask, “Where does this rule belong?” and actually get an answer. When boundaries are blurred, every change becomes archaeology.


Key Takeaways

  1. Treat boundaries as a design feature, not overhead. Clear boundaries between classes, queries, and data models reduce the spread of change.

  2. Let each layer do its native work. Use SQL for set based retrieval, grouping, and aggregation. Use classes for encapsulating behavior and protecting invariants.

  3. Watch for layers that both translate and decide. When a query or class starts mixing data movement with business policy, complexity is likely leaking across boundaries.

  4. Prefer stable contracts over exposed internals. Whether in object design or database access, depend on what is guaranteed, not on accidental structure.

  5. Use boundary questions during design reviews. Ask: What is the single responsibility here? What should this layer know? What should it never need to know?


Conclusion: the best systems are made of well defended truths

Software is often described as a matter of performance, features, or cleverness. But the longer you build, the more you realize that the real challenge is epistemic. A system must preserve the truth of what each part is for. That is what object design principles defend, and what SQL’s disciplined structure quietly reinforces.

If you want code that lasts, do not ask only how to make it work. Ask how to make it stay itself as it changes. The answer is almost always some version of the same lesson: define the borders carefully, keep the responsibilities narrow, and let each layer speak in its own language.

In that sense, good architecture is not about isolation. It is about responsible connection. The parts of a system should touch, but never blur into each other. That is where flexibility truly comes from, and why the healthiest software feels less like a pile of instructions and more like a well ordered conversation.

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 🐣