Stop Treating `components` and `utils` Like Project Dumpsters
A directory structure that groups by file type instead of business domain directly increases the cost of understanding and modifying a codebase. As a project grows, the `components` and `utils` folders become ungoverned dumping grounds where business rules hide inside files named like utilities, making refactors risky and onboarding slow.
Grouping front-end code by file type into `components`, `utils`, and `views` works for a project's first few weeks, then collapses. The structure tells you what a file is but not which business domain owns it, scattering related logic across a half-dozen directories and making changes a scavenger hunt.
The fix is to organize by the reason a file changes. Business-bound components and functions stay inside a `features/order` module. Pure, reusable UI and utilities sink to a `shared` layer. Application wiring lives in an `app` directory. This boundary answers three questions: what layer a file belongs to, why it will be modified, and what it's allowed to depend on.
A monorepo extends this same logic one level up. Shared infrastructure like a design system, request layer, or build config moves into `packages/` so no single application owns code that multiple apps consume. The directory structure is ultimately a dependency diagram: lower layers like `shared` must never import from upper layers like `features` or `app`.
Calling a directory `utils` provides no boundary at all; the name is so vague it invites any function that doesn't have an obvious home, which is precisely how business logic leaks into supposedly generic code.
The common reflex to extract shared code early is a status display, not an engineering decision. It creates maintenance contracts before the team knows what stable reuse looks like.
A directory structure is a dependency diagram rendered as folders. When a lower layer imports from a higher one, the structure has already failed, regardless of how tidy it looks.
The six diagnostic questions offered are a lightweight, repeatable heuristic that replaces architectural dogma with a single test: what will force this file to change?