WORK STORY / 03

Turn folder structure into executable rules

CONTEXT

Context

As the number of repositories, Shared Packages, and products grew, I encountered another problem.

Even when everyone knew:

  • Where a component should live
  • Which layer should own business logic
  • What contexts, hooks, and services should each own

Implementations by different engineers could still easily produce different dependency directions.

Over time, folder structure became only:

“the files look neatly organized”

while the actual dependencies had already penetrated one another.

A component directly accessing a service, a lower-level module depending back on an upper layer, or even a type definition assigned to the wrong owner could gradually create circular dependencies.

DECISION & ACTION

My Decision & Action

I therefore began developing folder structure from a directory-naming convention into an architectural rule.

I redefined the responsibilities of each layer, including:

  • pages
  • containers
  • components
  • hooks
  • contexts
  • services
  • utils

and further defined the import directions allowed between them.

For example, components should not access services directly; contexts, hooks, and containers may obtain capabilities only from specific layers; and TypeScript types must have clear owners rather than being referenced everywhere for convenience.

Besides documenting these relationships with text and dependency diagrams, I gradually constrained imports through ESLint rules so architectural rules were not merely instructions written for people.

OUTCOME

Outcome

Folder structure no longer asked only:

“Which folder should this file go in?”

It began to answer:

“What should this layer know, and what should it not know?”

The team could use one structure to understand module responsibilities and detect unreasonable cross-layer dependencies early in development.

REFLECTION

Reflection

This is also a principle I have continued to follow:

If an engineering rule truly matters, it should not exist only in documentation.

Documentation is suited to explaining why, but anything tooling can judge should preferably be judged directly by tooling.

Otherwise, standards ultimately become shared conventions engineers must uphold through memory.