Desegmentation
Desegmentation (also known as horizontal slicing or packaging by layer) is a code organization pattern where files are grouped by their technical roles rather than by the business domains they serve. This means code with similar technical functions is stored in the same place, regardless of the business logic it handles.
This approach is popular in meta-frameworks like Next and Nuxt due to its simplicity, as it’s easy to get started and enables features like auto-imports and file-based routing:
Directoryapp
Directorycomponents
- DeliveryCard.jsx
- DeliveryChoice.jsx
- RegionSelect.jsx
- UserAvatar.jsx
Directoryactions
- delivery.js
- region.js
- user.js
Directorycomposables
- delivery.js
- region.js
- user.js
Directoryconstants
- delivery.js
- region.js
- user.js
Directoryutils
- delivery.js
- region.js
- user.js
Directorystores
Directorydelivery
- getters.js
- actions.js
This pattern also occurs in FSD codebases, in the form of generic folders:
Directoryfeatures
Directorydelivery
Directoryui
- components ⚠️
Directoryentities
Directoryrecommendations
- utils ⚠️
Files can also be a source of desegmentation. Files like types.ts can aggregate multiple domains, complicating navigation and future refactoring, especially in layers like pages or widgets:
Directorypages
Directorydelivery
- index.ts
Directoryui
- DeliveryCard.tsx
- DeliveryChoice.tsx
- UserAvatar.tsx
Directorymodel
- types.ts ⚠️
- utils.ts ⚠️
Directoryapi
- endpoints.ts ⚠️
// ❌ Bad: Mixed business domains in generic fileexport interface DeliveryOption { id: string; name: string; price: number;}
export interface UserInfo { id: string; name: string; avatar: string;}// ❌ Bad: Mixed business domains in generic fileexport function formatDeliveryPrice(price: number) { return `$${price.toFixed(2)}`;}
export function getUserInitials(name: string) { return name.split(' ').map(n => n[0]).join('');}// ❌ Bad: Mixed business domains in generic fileexport async function fetchDeliveryOptions() { /* ... */ }export async function fetchUserInfo() { /* ... */ }The Problem
Section titled “The Problem”While this structure is easy to start with, it can lead to scalability issues in larger projects:
-
Low Cohesion: Modifying a single feature often requires editing files in multiple large folders, such as
pages,components, andstores. -
Tight Coupling: Components can have unexpected dependencies, leading to complex and tangled dependency chains.
-
Difficult Refactoring: It requires additional effort to manually extract code related to a specific domain.
Solution
Section titled “Solution”Group all code that relates to a specific domain in one place.
Avoid generic folder names such as types, components, utils, as well as generic file names like types.ts, utils.ts, or helpers.ts. Instead, use names that directly reflect the domain they represent.
Avoid generic file names like types.ts if possible, especially in slices with multiple domains:
Directorypages
Directorydelivery
- index.tsx
Directoryui
- DeliveryPage.tsx
- DeliveryCard.tsx
- DeliveryChoice.tsx
- UserInfo.tsx
Directorymodel
- delivery.ts
- user.ts