Invisible Until Declared: The Hidden Design Rule Behind Types, Routes, and Meaningful Software
Hatched by
Apr 26, 2026
10 min read
3 views
87%
The strangest thing about good software: it often does not exist until you declare it
What do a TypeScript enum and a Next.js route have in common? At first glance, almost nothing. One is about values in a type system, the other about folders in a web framework. But both hide the same unsettling design truth: software often remains invisible, inert, or inaccessible until it is explicitly declared in the right way.
That may sound obvious, but it is a deeper principle than most developers notice. We tend to think of code as something that exists if it is written. In reality, modern tools are full of layered boundaries: compile time versus runtime, file system versus public route, private structure versus public interface. The result is a subtle but powerful lesson: what matters is not only what you create, but when and where the system recognizes it.
This is why a value check against an enum can fail in one form and succeed in another, and why a folder can sit in your app for months without ever becoming a route. In both cases, the system is not asking, “Did you write it?” It is asking, “Did you make it legible in the layer I understand?”
The core tension: existence is not the same as accessibility
Most developers learn this lesson the hard way. You write code, you see it in your editor, and you assume the system will use it. But software platforms are not simple mirrors of your source files. They are selective interpreters. They only care about certain forms of existence.
Take an enum in TypeScript. If you are checking whether a value exists in an enum, the basic idea feels straightforward: inspect the enum at runtime and compare values. But that assumption breaks down with const enums, because they are designed to disappear during compilation. They are optimized for zero runtime presence. So the thing you expected to inspect is no longer there in the compiled output.
That tiny detail reveals something profound: a declaration can be real to the developer and nonexistent to the machine at runtime.
Next.js has a parallel idea. A folder in the app directory is not automatically a route. It becomes publicly accessible only when a page.js or route.js file is added to that segment. Likewise, a folder prefixed with an underscore can be used to make it private. That means the file system is not the same thing as the public application surface. A directory can exist, hold structure, and even organize your code beautifully, yet remain invisible to users until it is explicitly surfaced.
In modern software, visibility is a design decision, not a default.
This is the deeper connection between the two systems. Both encourage you to distinguish between internal structure and external interface. Both punish the assumption that all written code is equally available everywhere. And both reward developers who understand that declaration is not just syntax, it is a contract with a particular layer of the system.
A useful mental model: software has different kinds of reality
To make this concrete, imagine your application as a city with three layers.
- Blueprint reality: what exists in your design documents or source files.
- Operational reality: what exists after compilation and build steps.
- Public reality: what users can actually reach.
A const enum may exist in blueprint reality but vanish from operational reality because the compiler replaces it with literals. A Next.js folder may exist in blueprint reality and operational reality, but remain absent from public reality until a route file is present.
This three layer model is useful because it explains a common category of bugs: developers confuse one reality for another. They inspect source code and expect runtime behavior. They see a folder and expect a URL. They define a type and expect a value. They organize internal structure and assume public exposure.
The mistake is not incompetence. It is category confusion.
That is why these systems feel surprising at first. They are not merely tools for writing code. They are tools for drawing boundaries. A good framework does not just help you add features. It helps you decide what should exist where, and for whom.
Why this matters: the best abstractions make things disappear on purpose
There is a temptation to treat disappearing code as a problem. But often it is the opposite. The disappearance of a const enum at runtime is a feature, not a flaw. The privacy of a folder in Next.js is also a feature. Both are forms of intentional absence.
This may feel counterintuitive because developers are trained to value presence. More code feels like more control. More runtime objects feel easier to inspect. More exposed files feel simpler to reason about. Yet mature systems often work by removing unnecessary presence.
Consider a library closet in a building. You do not want every shelf visible from the lobby. You want some things stored for internal use, some things labeled for public access, and some things translated into a simpler interface for the outside world. The same logic applies to code.
A const enum says: do not carry this object into runtime if a simpler representation will do. A private folder says: do not turn this organizational detail into a public route just because it exists in the app tree. In both cases, the framework is enforcing a principle of selective exposure.
This principle matters because software complexity is often a consequence of overexposure. If every internal detail is public, every change becomes breaking. If every type must survive to runtime, you lose optimization and clarity. If every folder becomes a URL, your internal architecture leaks into your user experience.
The real craft is not to maximize visibility. It is to expose the minimum surface necessary for the system to work well.
The hidden cost of ignoring the boundary
When developers ignore the difference between definition and declaration, they create fragile systems.
For example, imagine writing code that checks whether a string value is present in an enum by iterating the enum object. That works for regular enums because the object exists at runtime. But if the enum is const, the object has been erased during compilation. The check fails not because the value is invalid, but because the mechanism you used assumes a runtime artifact that no longer exists.
The lesson is not simply “be careful with const enums.” The lesson is broader: your validation strategy must match the layer where the truth lives. If the truth exists only at compile time, do not ask runtime to prove it. If the truth is expressed in routing conventions, do not assume the file system automatically publishes it.
The same applies to app structure. A private folder is not just a naming trick. It is a statement that some parts of your architecture are for organization, not exposure. If you ignore that boundary, you may accidentally design around implementation details instead of stable public contracts.
This is a subtle but important shift in thinking. Strong systems are not defined by having fewer boundaries. They are defined by having clearer boundaries.
A boundary is not a restriction alone. It is also a source of confidence. When you know exactly where a value exists, you know where to validate it. When you know exactly what makes a folder public, you know how to reason about routing. When you know what disappears at compile time, you know what not to depend on at runtime.
Synthesis: programming is the art of making the right things real in the right layer
Here is the thesis that emerges from both ideas: good software does not merely contain information, it places information in the correct layer of reality.
That may sound abstract, but it has practical force. A type declaration should help the compiler. A runtime object should help execution. A route file should help routing. A private folder should help organization. Problems begin when one layer is asked to do the job of another.
Think of it like a theater production. The script, the stage set, the backstage area, and the performance all matter, but they matter differently. The audience only sees the performance. The crew depends on backstage structure. The script shapes the play, but it is not the play itself. Similarly, a TypeScript enum, especially a const enum, may be more like script than stage prop. A Next.js private folder may be more like backstage than audience seating.
The art is not in making everything visible. It is in making the right thing visible to the right consumer.
This is where many codebases become elegant or chaotic. Elegant systems respect the grain of the platform. They understand that compile time, build time, and runtime have different responsibilities. They know that the folder structure can organize work without becoming part of the user surface. They do not fight the tool, they collaborate with its boundaries.
The best abstractions are not those that show everything. They are those that make the correct thing appear at the correct moment.
Once you see this, you start noticing it everywhere. CSS modules scope class names to prevent leakage. Environment variables hide secrets from the client. Server components keep server only code off the browser bundle. Database migrations change persistence without changing every call site. Modern software is full of intentional invisibility. Not because developers want mystery, but because systems become more reliable when they separate internal truth from public interface.
A practical framework: ask three questions before you depend on anything
Whenever you are about to rely on a value, a file, or a convention, ask three questions.
1. Does it exist at the layer I am using?
If you are validating at runtime, make sure the thing exists at runtime. If you are routing from the file system, make sure the framework treats that file as a route. Do not assume a compile time construct will survive into execution.
2. Is it meant to be public or private?
If something is intended as internal structure, do not treat it as an external contract. A private folder is a good example: it helps you organize code without making that structure part of the URL space.
3. Am I depending on representation or behavior?
An enum may represent a closed set of values, but that does not mean the object itself will always be present. A folder may represent a route hierarchy, but that does not mean it automatically generates a route. Focus on the behavior the system guarantees, not the shape you happen to see in your editor.
This framework helps prevent a large class of bugs that are really boundary misunderstandings in disguise. It also nudges you toward better architecture. Once you start asking where truth lives, you naturally write cleaner validation, more deliberate routing, and less leaky abstractions.
Key Takeaways
- Do not confuse definition with availability. A value can be defined in source code and still be absent at runtime.
- Match your checks to the correct layer. Runtime validation needs runtime objects, not compile time illusions.
- Treat public exposure as explicit, not automatic. A folder or file should not be assumed public unless the framework says so.
- Use boundaries as design tools. Private structure is not a limitation, it is how you keep internal complexity from leaking outward.
- Ask where truth lives before depending on it. The best way to avoid brittle code is to know whether a fact belongs to compile time, runtime, or public interface.
Conclusion: the real skill is learning what not to make visible
The surprising connection between a TypeScript enum and a Next.js route is not technical trivia. It is a philosophy of software design. The healthiest systems are not those that expose everything they contain. They are those that are deliberate about what becomes real, where it becomes real, and who gets to see it.
That is a much more demanding standard than simply writing code that works. It asks you to think like an architect of layers, not just an assembler of features. It asks you to respect the difference between a thing that is written, a thing that is compiled, and a thing that is reachable.
Once you internalize that distinction, you stop asking only, “Did I create it?” You start asking the better question: “In which reality does this thing actually exist?”
That question is one of the most valuable habits in modern development, because the boundary between existence and accessibility is where many of the best abstractions, and many of the most expensive bugs, are born.
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 🐣