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.
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:
rm -r features/dark-mode
.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:
useDarkMode.ts
when five features live in /hooks
?lib/
, ui/
) tiny and generic; resist dumping features there.index.ts
) a feature’s public surface; internal files stay private.