Readable Code Is a Form of Version Control for the Human Mind
Hatched by Dhruv
Aug 20, 2026
10 min read
0 views
92%
What if indentation and Git commits are not separate programming habits, but two versions of the same idea?
One makes structure visible while you are looking at code. The other makes change understandable after the code has moved through time. Together, they suggest a deeper principle: good software practice is the art of making intention recoverable.
That principle matters far beyond neat files or tidy repositories. Software is rarely read only once, by one person, in the moment it was written. It is revisited after a bug appears, inherited by a teammate, compared with an earlier version, or modified months later by someone who no longer remembers the original problem. The real audience for code is not just the present programmer. It is the future reader, including a future version of yourself.
The question, then, is not merely whether code works. It is whether its meaning remains visible as context changes.
Structure in Space, Structure in Time
Consider a small piece of HTML. The elements inside one another form a hierarchy. A paragraph may sit inside a section, which sits inside a page body. Indentation does not change what the browser renders, but it changes what a human can perceive. Without indentation, nesting becomes a puzzle. With it, the shape of the document becomes immediately legible.
The same is true of emphasis. An element that makes text italic is not necessarily doing the same conceptual work as an element that marks text as emphasized. A visually bold phrase may simply be styled to stand out. A phrase marked as important communicates something about its role and meaning, not only its appearance.
These distinctions reveal two layers of a program:
- Presentation, which concerns how something appears.
- Semantics, which concerns what something means.
Readable indentation belongs to a third layer: orientation. It helps a person navigate the relationship among parts. A document can be technically valid without being easy to orient within, just as a sentence can be grammatically correct while being difficult to understand.
Git introduces an analogous distinction, but across time rather than within a document. A repository is not only a folder containing the latest files. It is also a record of deliberate states. A commit says, in effect, “these related changes belong together, and this is the point at which they became a coherent unit.”
An atomic commit is valuable because it preserves the shape of an intention. If one commit changes a button’s appearance, fixes a form submission problem, and reorganizes unrelated files, its snapshot may be accurate, but its meaning is blurred. If the changes are separated according to task, each snapshot becomes easier to inspect, explain, and undo.
Indentation makes relationships visible in space. Atomic commits make relationships visible in time.
Readable code shows how parts belong together. Readable history shows why changes belong together.
This is the surprising connection. Both practices reduce the cost of reconstructing structure. One protects the reader from getting lost inside the present state. The other protects the reader from getting lost among past states.
The Hidden Cost of Ambiguity
Ambiguity in software creates a form of technical debt that is easy to underestimate. People often think of technical debt as messy architecture, duplicated code, or an outdated dependency. Yet confusion itself is a liability. Every unclear relationship forces someone to spend mental energy inferring what the system means.
Imagine opening a file with inconsistent indentation. You can still read it, but you must repeatedly ask: does this element belong inside that one, or beside it? Is this block intentionally grouped, or did the grouping happen accidentally? The browser may answer some of these questions through its behavior, but the human reader cannot rely on behavior alone. Understanding requires reconstruction.
Now imagine examining a repository whose history contains a single enormous commit called “updates.” The current files may work perfectly. But when a regression appears, the history offers little help. Which change introduced the problem? What was the intended purpose of the modified section? Which parts can be safely reverted?
In both cases, the system has preserved execution while losing explanation.
This distinction is crucial because computers and humans consume different kinds of information. A browser needs valid markup and instructions. A developer needs hierarchy, emphasis, boundaries, and reasons. Git can store a complete snapshot of every file, but a snapshot alone does not tell us which edits were conceptually connected. Machines preserve states. Humans need narratives.
A useful mental model is to treat every programming decision as producing two outputs:
- A machine result, which allows the software to run.
- A human signal, which allows someone to understand, modify, or recover the software.
Neglecting the second output does not eliminate its cost. It transfers the cost into future debugging, onboarding, review, and maintenance.
This is why visual styling and semantic meaning should not be confused. Making text look bold can satisfy the eye while communicating nothing about importance. Similarly, making a commit large can capture many changes while communicating nothing about their relationship. In both situations, surface appearance creates the illusion of clarity.
The deeper discipline is not tidiness for its own sake. It is semantic alignment: the visible form should accurately reflect the conceptual structure.
If two pieces of code serve different purposes, they should not be presented as one undifferentiated block. If two changes can be understood, tested, or reverted independently, they should not be forced into one historical unit. The goal is not maximum fragmentation. The goal is to make boundaries correspond to meaning.
Reversibility Is a Design Requirement
A common misunderstanding is that careful structure mainly helps when everything is going well. In reality, its greatest value appears during failure.
Suppose a developer adds a new feature and also cleans up a confusing section of CSS. Later, a layout breaks. If those changes were committed together, the developer must investigate both at once. Perhaps the feature caused the problem. Perhaps the cleanup changed an assumption. Perhaps the two interacted. The act of recovery becomes an archaeological project.
With an atomic commit, the same situation is easier to reason about. The feature can be inspected as one unit. The cleanup can be evaluated separately. If necessary, one change can be reverted without discarding the other. The commit is not merely a checkpoint. It is a reversible hypothesis about the system.
This way of thinking changes how we work. A commit is a claim: “this set of changes solves this particular problem.” A good commit message identifies the claim. A small scope makes the claim testable. A clean snapshot makes the claim easier to challenge.
The same logic applies inside a file. When semantic emphasis is represented by an element that communicates importance, future tools and readers can interpret it correctly. Accessibility software, search systems, and other consumers may use that meaning even when visual styling changes. The markup becomes more resilient because it records purpose rather than merely appearance.
In both cases, the practice improves future optionality. Semantic markup leaves more options open for different presentations and technologies. Atomic history leaves more options open for selective rollback, comparison, and collaboration.
A well structured system does not merely work now. It preserves choices for later.
This gives us a practical test for code quality: ask not only, “Does this produce the desired result?” Ask also, “If the result is wrong, how easily can I locate the assumption, explain the change, and remove only what needs removing?”
That question exposes why status checks matter. A command that shows which files have changed is not administrative overhead. It is a moment of boundary detection. Before creating a snapshot, you inspect the gap between the last known state and the current one. You decide what belongs in the next conceptual unit and what should remain outside it.
The staging area makes this decision explicit. Instead of treating every change in a directory as one event, you select the changes that form a coherent idea. This is the historical equivalent of using meaningful nesting in a document. You are telling the system, and your collaborators, where one unit ends and another begins.
The Two Clocks of Software Work
Every codebase operates on two clocks.
The first is the spatial clock of the current file. It asks: where does this part belong, what does it contain, and what is its role relative to neighboring parts? Indentation, semantic elements, and clear separation answer these questions.
The second is the temporal clock of the repository. It asks: what changed, in what order, for what reason, and which earlier state can we safely return to? Status checks, focused staging, meaningful messages, and pushes answer these questions.
Many programming mistakes happen because developers manage one clock while ignoring the other. A file may be beautifully organized, but its history may be an opaque sequence of giant changes. Or a repository may have excellent commits while the current code is deeply confusing. Local readability and historical readability are related, but neither substitutes for the other.
A stronger workflow coordinates both clocks:
- First, express the structure of the current document clearly.
- Next, distinguish meaning from appearance so that the code says what it intends.
- Then, inspect the changes before recording them.
- Finally, create a snapshot whose scope matches one understandable task.
This is more than a checklist. It is a method for reducing uncertainty at each stage. The reader can understand the file. The reviewer can understand the change. The debugger can isolate the failure. The future maintainer can recover the reasoning.
Even a simple command sequence embodies this philosophy. Check the status of the working directory. Select the relevant file or files. Record a focused commit with a message that describes the change. Inspect the resulting relationship between the local branch and the remote repository. Push when the snapshot is ready to be shared.
The sequence matters because each step answers a different question. What is different? What belongs together? What did we decide? Has that decision been transmitted to others? Skipping these questions may save seconds while increasing uncertainty for everyone who follows.
A Practical Framework: Meaning, Boundary, Recovery
The connection between semantic markup and version control can be turned into a simple framework for daily work. Before changing code, examine three dimensions.
1. Meaning
What is this piece of code trying to communicate beyond its appearance? Is a phrase merely styled, or is it genuinely important? Is a group of edits merely adjacent, or do they serve one purpose?
Name the intent in plain language. If you cannot describe the purpose without listing implementation details, the conceptual boundary may still be unclear.
2. Boundary
Where does this meaning begin and end? In a document, boundaries are expressed through nesting and elements. In a repository, they are expressed through files selected for staging and commits limited to one task.
A useful rule is: make the smallest boundary that still tells a complete story. A single character change may be too small if it has no independent meaning. A whole feature plus unrelated cleanup is usually too large.
3. Recovery
If this decision proves wrong, how precisely can it be revisited? Can a reader identify what the code means? Can a reviewer isolate the relevant change? Can a developer revert the decision without destroying unrelated work?
Recovery is where good structure proves its value. The purpose of organization is not to make the present look polished. It is to make the future less expensive.
Key Takeaways
- Treat readability as recoverability. Write code so another person can reconstruct its structure and purpose without relying on guesswork.
- Separate appearance from meaning. Use semantic constructs when the concept matters, and reserve purely visual treatment for presentation concerns.
- Use boundaries that match intent. Indent related structures clearly, and create commits around one coherent task rather than one burst of activity.
- Inspect before recording. Check the current changes, stage deliberately, and verify that the proposed snapshot tells a complete story.
- Optimize for selective reversal. Ask whether a future bug fix could isolate or undo this change without sacrificing unrelated work.
The best programmers are not simply faster typists or more knowledgeable command users. They are skilled at leaving behind evidence of intention. Their files show how ideas fit together. Their histories show why the system changed. Their choices reduce the amount of invisible reconstruction demanded from everyone else.
That may be the most useful way to rethink clean code. Clean code is not code that looks immaculate at one moment. It is code that remains intelligible when the original context has disappeared.
Indentation is therefore not cosmetic. A semantic element is not merely a formatting preference. A focused commit is not just a convenient save point. Each is a small promise to the future: the structure will remain visible, the meaning will remain distinguishable, and the path back from a mistake will remain open.
The mature question is not, “How do I make this code work?” It is: “How do I make its intent survive me?”
Sources
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 🐣