File Structure Feature First

Organise files by feature/domain (not by type), grouping components, hooks, tests, and styles together.

Why?  Reduces cross‑tree hopping and clarifies ownership.

Clustering everything a user story touches—UI, logic, styles, and tests—inside one feature folder slashes cognitive load. Engineers scroll less, own more, and reason about changes without spelunking through parallel “components vs hooks vs tests” silos.

Correct Example

src/
├─ features/
│  ├─ dark-mode/
│  │  ├─ DarkModeToggle.tsx         // UI
│  │  ├─ useDarkMode.ts             // hook
│  │  ├─ DarkModeToggle.test.tsx    // behavior test
│  │  └─ index.ts                   // public barrel
│  └─ reports/
│     ├─ ReportsPage.tsx
│     ├─ useReports.ts
│     ├─ ReportsPage.test.tsx
│     └─ ReportsTable.tsx
├─ App.tsx
└─ main.tsx

Why it’s good:

  • One glance reveals all dark-mode assets; new devs grok ownership instantly.
  • Deleting a feature is a one-command rm -r features/dark-mode.
  • Tests live beside implementation, encouraging maintenance.

Incorrect Example

src/
├─ components/
│  ├─ DarkModeToggle.tsx
│  └─ ReportsPage.tsx
├─ hooks/
│  ├─ useDarkMode.ts
│  └─ useReports.ts
├─ tests/
│  ├─ DarkModeToggle.test.tsx
│  └─ ReportsPage.test.tsx
├─ styles/
│  ├─ dark-mode.css
│  └─ reports.css
└─ App.tsx

What’s wrong:

  • Updating dark mode spans four distant directories—easy to miss one.
  • Shared buckets grow endlessly; merge conflicts and unused files pile up.
  • Ownership is opaque: who “owns” useDarkMode.ts when five features live in /hooks?

Key Takeaways

  • Folder = Feature: everything user-visible belongs together.
  • Keep cross-feature utilities (lib/, ui/) tiny and generic; resist dumping features there.
  • Colocation boosts delete refactorability and reduces review diff noise.
  • Tests and styles live with code they cover—no hunting.
  • Barrel-export (index.ts) a feature’s public surface; internal files stay private.