Skip to content

Commit 2aa4c9b

Browse files
committed
docs: refactor desegmentation page
1 parent 802f963 commit 2aa4c9b

1 file changed

Lines changed: 124 additions & 80 deletions

File tree

  • i18n/en/docusaurus-plugin-content-docs/current/guides/issues

i18n/en/docusaurus-plugin-content-docs/current/guides/issues/desegmented.mdx

Lines changed: 124 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -3,95 +3,139 @@ sidebar_position: 2
33
sidebar_class_name: sidebar-item--wip
44
---
55

6-
import WIP from '@site/src/shared/ui/wip/tmpl.mdx'
7-
8-
# Desegemented
9-
10-
<WIP ticket="148" />
11-
12-
## Situation
13-
14-
Very often, there is a situation on projects when modules related to a specific domain from the subject area are unnecessarily desegmented and scattered around the project
15-
16-
```sh
17-
├── components/
18-
| ├── DeliveryCard
19-
| ├── DeliveryChoice
20-
| ├── RegionSelect
21-
| ├── UserAvatar
22-
├── actions/
23-
| ├── delivery.js
24-
| ├── region.js
25-
| ├── user.js
26-
├── epics/
27-
| ├── delivery.js
28-
| ├── region.js
29-
| ├── user.js
30-
├── constants/
31-
| ├── delivery.js
32-
| ├── region.js
33-
| ├── user.js
34-
├── helpers/
35-
| ├── delivery.js
36-
| ├── region.js
37-
| ├── user.js
38-
├── entities/
39-
| ├── delivery/
40-
| | ├── getters.js
41-
| | ├── selectors.js
42-
| ├── region/
43-
| ├── user/
6+
import Tabs from '@theme/Tabs';
7+
import TabItem from '@theme/TabItem';
8+
9+
# Desegmentation
10+
11+
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.
12+
13+
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:
14+
15+
- 📂 app
16+
- 📂 components
17+
- 📄 DeliveryCard.jsx
18+
- 📄 DeliveryChoice.jsx
19+
- 📄 RegionSelect.jsx
20+
- 📄 UserAvatar.jsx
21+
- 📂 actions
22+
- 📄 delivery.js
23+
- 📄 region.js
24+
- 📄 user.js
25+
- 📂 composables
26+
- 📄 delivery.js
27+
- 📄 region.js
28+
- 📄 user.js
29+
- 📂 constants
30+
- 📄 delivery.js
31+
- 📄 region.js
32+
- 📄 user.js
33+
- 📂 utils
34+
- 📄 delivery.js
35+
- 📄 region.js
36+
- 📄 user.js
37+
- 📂 stores
38+
- 📂 delivery
39+
- 📄 getters.js
40+
- 📄 actions.js
41+
42+
This pattern also occurs in FSD codebases, in the form of generic folders:
43+
44+
- 📂 features
45+
- 📂 delivery
46+
- 📂 ui
47+
- 📂 components ⚠️
48+
- 📂 entities
49+
- 📂 recommendations
50+
- 📂 utils ⚠️
51+
52+
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`:
53+
54+
- 📂 pages
55+
- 📂 delivery
56+
- 📄 index.ts
57+
- 📂 ui
58+
- 📄 DeliveryCard.tsx
59+
- 📄 DeliveryChoice.tsx
60+
- 📄 UserAvatar.tsx
61+
- 📂 model
62+
- 📄 types.ts ⚠️
63+
- 📄 utils.ts ⚠️
64+
- 📂 api
65+
- 📄 endpoints.ts ⚠️
66+
67+
<Tabs>
68+
69+
<TabItem value="types.ts" label="types.ts">
70+
```ts title="pages/delivery/model/types.ts"
71+
// ❌ Bad: Mixed business domains in generic file
72+
export interface DeliveryOption {
73+
id: string;
74+
name: string;
75+
price: number;
76+
}
77+
78+
export interface UserInfo {
79+
id: string;
80+
name: string;
81+
avatar: string;
82+
}
4483
```
84+
</TabItem>
85+
86+
<TabItem value="utils.ts" label="utils.ts">
87+
```ts title="pages/delivery/model/utils.ts"
88+
// ❌ Bad: Mixed business domains in generic file
89+
export function formatDeliveryPrice(price: number) {
90+
return `$${price.toFixed(2)}`;
91+
}
92+
93+
export function getUserInitials(name: string) {
94+
return name.split(' ').map(n => n[0]).join('');
95+
}
96+
```
97+
</TabItem>
98+
99+
<TabItem value="endpoints.ts" label="endpoints.ts">
100+
```ts title="pages/delivery/api/endpoints.ts"
101+
// ❌ Bad: Mixed business domains in generic file
102+
export async function fetchDeliveryOptions() { /* ... */ }
103+
export async function fetchUserInfo() { /* ... */ }
104+
```
105+
</TabItem>
106+
</Tabs>
107+
108+
## The Problem
45109

46-
## Problem
110+
While this structure is easy to start with, it can lead to scalability issues in larger projects:
47111

48-
The problem manifests itself at least in violation of the principle of * * High Cohesion** and excessive stretching * * of the axis of changes**
112+
- Low Cohesion: Modifying a single feature often requires editing files in multiple large folders, such as `pages`, `components`, and `stores`.
49113

50-
## If you ignore it
114+
- Tight Coupling: Components can have unexpected dependencies, leading to complex and tangled dependency chains.
51115

52-
- If necessary, touch on the logic, for example, delivery - we will have to keep in mind that it lies in several places and touch on several places in the code-which unnecessarily stretches our * * Axis of changes**
53-
- If we need to study the logic of the user, we will have to go through the whole project to study in detail * * actions, epics, constants, entities, components** - instead of it lying in one place
54-
- Implicit connections and the uncontrollability of a growing subject area
55-
- With this approach, the eye is very often blurred and you may not notice how we "create constants for the sake of constants", creating a dump in the corresponding project directory
116+
- Difficult Refactoring: It requires additional effort to manually extract code related to a specific domain.
56117

57118
## Solution
58119

59-
Place all modules related to a specific domain/user case - directly next to each other
60-
61-
So that when studying a particular module, all its components lie side by side, and are not scattered around the project
62-
63-
> It also increases the discoverability and clarity of the code base and the relationships between modules
64-
65-
```diff
66-
- ├── components/
67-
- | ├── DeliveryCard
68-
- | ├── DeliveryChoice
69-
- | ├── RegionSelect
70-
- | ├── UserAvatar
71-
- ├── actions/
72-
- | ├── delivery.js
73-
- | ├── region.js
74-
- | ├── user.js
75-
- ├── epics/{...}
76-
- ├── constants/{...}
77-
- ├── helpers/{...}
78-
├── entities/
79-
| ├── delivery/
80-
+ | | ├── ui/ # ~ components/
81-
+ | | | ├── card.js
82-
+ | | | ├── choice.js
83-
+ | | ├── model/
84-
+ | | | ├── actions.js
85-
+ | | | ├── constants.js
86-
+ | | | ├── epics.js
87-
+ | | | ├── getters.js
88-
+ | | | ├── selectors.js
89-
+ | | ├── lib/ # ~ helpers
90-
| ├── region/
91-
| ├── user/
92-
```
120+
Group all code that relates to a specific domain in one place.
121+
122+
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.
123+
124+
Avoid generic file names like `types.ts` if possible, especially in slices with multiple domains:
125+
126+
- 📂 pages
127+
- 📂 delivery
128+
- 📄 index.tsx
129+
- 📂 ui
130+
- 📄 DeliveryPage.tsx
131+
- 📄 DeliveryCard.tsx
132+
- 📄 DeliveryChoice.tsx
133+
- 📄 UserInfo.tsx
134+
- 📂 model
135+
- 📄 delivery.ts
136+
- 📄 user.ts
93137

94-
## See also
138+
## See Also
95139

96140
* [(Article) About Low Coupling and High Cohesion clearly](https://enterprisecraftsmanship.com/posts/cohesion-coupling-difference/)
97141
* [(Article) Low Coupling and High Cohesion. The Law of Demeter](https://medium.com/german-gorelkin/low-coupling-high-cohesion-d36369fb1be9)

0 commit comments

Comments
 (0)