When Conventions Become Interfaces: What Monorepos and Enum Routing Reveal About Good Systems

Ryusei Nakamura

Hatched by Ryusei Nakamura

Jul 02, 2026

10 min read

72%

0

The hidden question behind both choices

What makes a system feel safe to use without making it feel hard to change?

That is the deeper thread connecting two apparently ordinary engineering decisions: managing a monorepo with pnpm, and using implicit enum binding in routing. One is about package management. The other is about web requests. But both are really about the same thing: turning a messy, open ended world into a smaller set of valid moves.

That may sound like a restriction. In practice, it is freedom. When your tools can tell you, early and clearly, what belongs and what does not, you spend less time debugging ambiguity and more time building meaning. Good systems do not remove choice. They make the right choices easier to express and the wrong choices harder to smuggle in.

The interesting part is that this principle appears at two very different layers of software. In a repository, it shows up as workspace structure and dependency management. In a router, it shows up as type backed validation of URL segments. One helps a team coordinate code. The other helps an application coordinate meaning. Together, they point to a design philosophy that is easy to appreciate in hindsight but difficult to apply consistently: let structure do the filtering.


From chaos to a bounded space

Most software problems begin as unbounded ones. A repository grows. Packages multiply. Routes accumulate. Strings that once stood for obvious things begin to stand for many things. The cost is not always visible at first, because ambiguity is gentle in small doses. But once a system reaches a certain scale, ambiguity becomes a tax.

A monorepo without disciplined workspace management can become a maze of local hacks, duplicated dependencies, and fragile assumptions about where code lives. pnpm changes the geometry of that maze. Its workspace model encourages a shared dependency graph instead of a pile of isolated copies. That means the repository behaves less like a random collection of folders and more like a designed system with explicit relationships.

Enum binding in routing performs the same kind of transformation, but for incoming requests. A route parameter like /posts/draft or /users/admin may look harmless, yet it is actually a question asked by the outside world: which values are admissible here? By binding that segment to a string backed enum, the application refuses to treat every string as equally meaningful. Only valid enum values are allowed to reach the route action. The router becomes a gatekeeper of semantic legitimacy.

These are not just implementation conveniences. They are examples of a broader move in software design: replace informal agreement with machine checked boundaries.

The best systems do not trust every string, every path, or every dependency. They ask the system itself to prove that something belongs.

That is why these two ideas fit together so well. Both convert a sprawling space of possible inputs into a smaller space of intentional ones. Both reduce the number of places where humans must remember tribal knowledge. And both make the codebase more legible to future maintainers, not by adding commentary, but by encoding expectations in the structure itself.


The real benefit is not correctness, it is navigability

When people talk about validation or workspace tools, they often frame the benefit as fewer bugs. That is true, but incomplete. The deeper gain is navigability.

Think about a city. A city with no street signs may still be functional if everyone has lived there long enough. But it becomes exhausting for newcomers. Every errand requires negotiation. Every trip depends on local memory. A well designed city does not eliminate complexity, it makes complexity traversable.

pnpm does this inside a repository. Instead of letting every package improvise its own dependency story, it establishes a consistent map. You know what is shared, what is local, and how packages relate. That cuts down on “mystery behavior,” the kind where something works on one machine and fails on another because the dependency landscape is accidental rather than intentional.

Enum route binding does the same thing for request handling. Instead of forcing every controller or middleware layer to ask, “Is this value one of the allowed states?”, the route layer itself answers that question before the request goes deeper. Invalid inputs are rejected at the boundary. Valid inputs are not merely accepted, they are named as belonging to a known domain.

This changes the emotional experience of maintenance. You stop feeling like you are patching leaks and start feeling like you are moving through a well marked system. That matters because software is not only about execution. It is about orientation.

A useful mental model here is to distinguish between two kinds of complexity:

  1. Essential complexity: the real domain problem, the thing the software must do.
  2. Accidental complexity: the confusion introduced by weak structure, unclear boundaries, and implicit assumptions.

pnpm and enum binding both reduce accidental complexity by moving constraints earlier and making them explicit. They do not make the domain simpler. They make the system less likely to lie about the domain.


Conventions are interfaces, not just habits

The word convention is often used to mean “a nice thing the team tries to remember.” That undersells its importance. In mature systems, conventions are often functioning as interfaces.

A repository convention tells developers how to think about module ownership, dependency sharing, and the shape of local changes. A route convention tells callers what kinds of values represent legitimate states. In both cases, the convention is not merely social. It is a contract with operational consequences.

This is why monorepo tooling matters so much. Without it, the repository becomes a social agreement enforced by memory and code review. With it, the repository can express its own rules. That makes the system more resilient to growth, because rules that live in tools are harder to forget than rules that live in people’s heads.

Enum binding similarly turns a naming pattern into an executable contract. Imagine an endpoint that handles only three order statuses: pending, shipped, and delivered. Without enum binding, the route accepts any string, and every consumer layer must revalidate the value. With enum binding, invalid statuses never reach the business logic. The route is no longer just a path. It is a type boundary.

This matters because stringly typed systems are seductive. They feel flexible. They are easy to extend. But that flexibility often hides a cost: every new caller can invent a slightly different interpretation of the same concept. Today it is draft, tomorrow it is Draft, next week it is DRAFTED. Soon the code is not talking about domain states anymore, it is negotiating spelling.

A system that accepts everything eventually understands nothing.

That does not mean we should overconstrain every boundary. It means we should be strategic about where meaning is supposed to crystallize. If a value represents a closed set of possibilities, then the system should treat it like a closed set. If dependencies are meant to be shared coherently, then the repository should treat them like a shared graph. Conventions become interfaces when they are enforced by tools rather than ornamented by documentation.


A shared design pattern: shrink the valid surface area

The deepest commonality between these ideas is not “developer convenience.” It is a design pattern: shrink the valid surface area.

The phrase sounds technical, but the intuition is simple. Every system has a surface where input enters and decisions are made. If that surface is too large, too vague, or too permissive, the system becomes fragile. If the surface is intentionally narrow, the system becomes more reliable and easier to reason about.

In a pnpm monorepo, the valid surface area shrinks because packages resolve dependencies through a coherent workspace model instead of ad hoc duplication. You no longer need to wonder which copy of a library you are talking to, or why one package sees a version another package does not. The system narrows the space of possible dependency states.

In enum route binding, the valid surface area shrinks because the route only matches recognized values. You no longer need to imagine every possible string that could reach a controller. The router reduces the input space before your application logic even begins.

This is powerful because most software failures are not dramatic. They are shape mismatches. A package sees the wrong version. A controller receives an impossible state. A team member assumes the wrong directory convention. These are boundary failures, not core logic failures.

A practical way to think about this is to ask three questions whenever you design a boundary:

  1. What values are actually meaningful here?
  2. What is the smallest set of representations that can express them?
  3. Where should invalid input be rejected, as early as possible?

Both pnpm and enum binding are answers to those questions. They create narrower, clearer, and more trustworthy boundaries. They do not eliminate all complexity, but they move complexity to places where it can be managed deliberately instead of discovered accidentally.


What this means for how we build

There is a temptation in software to treat guardrails as bureaucracy. Engineers often reach for maximal flexibility first, then add constraints only after the system has already become painful. But the better move is often the opposite: design for constraint up front, then allow flexibility inside the safe zone.

That means using tools that encode structure instead of hoping structure will emerge from scale. In a repository, it means choosing workspace management that makes relationships visible and repeatable. In routing, it means using typed boundaries that reject impossible states before they spread.

This does not just prevent errors. It changes team behavior. When the system itself enforces important truths, developers spend less time arguing about what should happen and more time building what should happen. Review becomes easier because the code makes fewer implicit promises. Onboarding becomes easier because the system teaches by constraint. Refactoring becomes safer because the domain is less porous.

A concrete example helps. Suppose you are building an admin dashboard and you have a route like /reports/:status. If status can only be one of three known values, treating it as an enum is a declaration that the domain is closed. That means your UI, API, and analytics can all assume the same vocabulary. Now imagine the same dashboard inside a monorepo with shared packages for UI, validation, and data access. pnpm helps keep those shared dependencies aligned so that the meaning of “status” is consistent across the codebase. The routing layer protects the entry point. The monorepo protects the internal coherence.

This is why these tools feel especially good together. One preserves meaning at the edge of the system. The other preserves meaning inside the system. In combination, they reduce the gap between what the software claims to mean and what it can actually execute.

Key Takeaways

  1. Treat boundaries as design opportunities. Ask what values are truly valid and encode that truth in the system, not only in documentation.

  2. Use tools to make conventions enforceable. A convention becomes much more powerful when the tooling can check it automatically.

  3. Reduce accidental complexity before it spreads. Shared dependency graphs and typed route values prevent ambiguity from multiplying across layers.

  4. Optimize for navigability, not just correctness. The best structure makes systems easier to understand, not merely harder to break.

  5. Prefer narrow, explicit interfaces over permissive ones. Flexible input often looks convenient, but explicit constraints make large systems more coherent.


The real lesson: good systems make meaning harder to fake

The surprising connection between workspace tooling and enum route binding is not that they both improve developer experience. It is that they both defend meaning.

A monorepo managed well does not let packages drift into hidden relationships. An enum bound route does not let arbitrary strings masquerade as valid domain states. In both cases, the software refuses to pretend that all inputs are equally real. That refusal is a form of clarity.

And clarity is the true luxury in software. Not more abstraction, not more flexibility, not more cleverness. Clarity. A system with clear boundaries can evolve without turning into folklore. A team working inside those boundaries can move faster because they are not constantly rediscovering what the system already knows.

So the next time you reach for a tool that seems to “just” improve structure, ask a deeper question: what meaning is this tool making harder to fake? That answer is often the difference between a codebase that merely runs and a codebase that remains intelligible as it grows.

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 🐣