|
| 1 | +# Excessive Entities |
| 2 | + |
| 3 | +The `entities` layer in Feature-Sliced Design is one of the lower layers that's primarily for business logic. That makes it widely accessible β all layers except for `shared` can access it. However, its global nature means that changes to `entities` can have a widespread impact, requiring careful design to avoid costly refactors. |
| 4 | + |
| 5 | +Excessive entities can lead to ambiguity (what code belongs to this layer), coupling, and constant import dilemmas (code scattered across sibling entities). |
| 6 | + |
| 7 | +## How to keep `entities` layer clean |
| 8 | + |
| 9 | +### 0. Consider having no `entities` layer |
| 10 | + |
| 11 | +You might think that your application won't be Feature-Sliced if you don't include this layer, but it is completely fine for the application to have no `entities` layer. It doesn't break FSD in any way, on the contrary, it simplifies the architecture and keeps the `entities` layer available for future scaling. For example, if your application acts as a thin client, most likely it doesn't need `entities` layer. |
| 12 | + |
| 13 | +:::info[What are thick and thin clients?] |
| 14 | + |
| 15 | +_Thick_ vs. _thin client_ distinction refers to how the application processes data: |
| 16 | + |
| 17 | +- _Thin_ clients rely on the backend for most data processing. Client-side business logic is minimal and involves only exchanging data with the backend. |
| 18 | +- _Thick_ clients handle significant client-side business logic, making them suitable candidates for the `entities` layer. |
| 19 | + |
| 20 | +Keep in mind that this classification is not strictly binary, and different parts of the same application may act as a "thick" or a "thin" client. |
| 21 | + |
| 22 | +::: |
| 23 | + |
| 24 | +### 1. Avoid preemptive slicing |
| 25 | + |
| 26 | +In contrast to previous versions, FSD 2.1 encourages deferred decomposition of slices instead of preemptive, and this approach also extends to `entities` layer. At first, you can place all your code in the `model` segment of your page (widget, feature), and then consider refactoring it later, when business requirements are stable. |
| 27 | + |
| 28 | +Remember: the later you move code to the `entities` layer, the less dangerous your potential refactors will be β code in Entities may affect functionality of any slice on higher layers. |
| 29 | + |
| 30 | +### 2. Avoid Unnecessary Entities |
| 31 | + |
| 32 | +Do not create an entity for every piece of business logic. Instead, leverage types from `shared/api` and place logic in the `model` segment of a current slice. For reusable business logic, use the `model` segment within an entity slice while keeping data definitions in `shared/api`: |
| 33 | + |
| 34 | +```plaintext |
| 35 | +π entities |
| 36 | + π order |
| 37 | + π index.ts |
| 38 | + π model |
| 39 | + π apply-discount.ts // Business logic using OrderDto from shared/api |
| 40 | +π shared |
| 41 | + π api |
| 42 | + π index.ts |
| 43 | + π endpoints |
| 44 | + π order.ts |
| 45 | +``` |
| 46 | + |
| 47 | +### 3. Exclude CRUD Operations from Entities |
| 48 | + |
| 49 | +CRUD operations, while essential, often involve boilerplate code without significant business logic. Including them in the `entities` layer can clutter it and obscure meaningful code. Instead, place CRUD operations in `shared/api`: |
| 50 | + |
| 51 | +```plaintext |
| 52 | +π shared |
| 53 | + π api |
| 54 | + π client.ts |
| 55 | + π index.ts |
| 56 | + π endpoints |
| 57 | + π order.ts // Contains all order-related CRUD operations |
| 58 | + π products.ts |
| 59 | + π cart.ts |
| 60 | +``` |
| 61 | + |
| 62 | +For complex CRUD operations (e.g., atomic updates, rollbacks, or transactions), evaluate whether the `entities` layer is appropriate, but use it with caution. |
| 63 | + |
| 64 | +### 4. Store Authentication Data in `shared` |
| 65 | + |
| 66 | +Prefer `shared` layer to creating a `user` entity for authentication data, such as tokens or user DTOs returned from the backend. These are context-specific and unlikely to be reused outside authentication scope: |
| 67 | + |
| 68 | +- Authentication responses (e.g., tokens or DTOs) often lack fields needed for broader reuse or vary by context (e.g., private vs. public user profiles). |
| 69 | +- Using entities for auth data can lead to cross-layer imports (e.g., `entities` into `shared`) or usage of `@x` notation, complicating the architecture. |
| 70 | + |
| 71 | +Instead, store authentication-related data in `shared/auth` or `shared/api`: |
| 72 | + |
| 73 | +```plaintext |
| 74 | +π shared |
| 75 | + π auth |
| 76 | + π use-auth.ts // authenticated user info or token |
| 77 | + π index.ts |
| 78 | + π api |
| 79 | + π client.ts |
| 80 | + π index.ts |
| 81 | + π endpoints |
| 82 | + π order.ts |
| 83 | +``` |
| 84 | + |
| 85 | +For more details on implementing authentication, see [the Authentication guide](/docs/guides/examples/auth). |
| 86 | + |
| 87 | +### 5. Minimize Cross-Imports |
| 88 | + |
| 89 | +FSD permits cross-imports via `@x` notation, but they can introduce technical issues like circular dependencies. To avoid this, design entities within isolated business contexts to eliminate the need for cross-imports: |
| 90 | + |
| 91 | +Non-Isolated Business Context (Avoid): |
| 92 | + |
| 93 | +```plaintext |
| 94 | +π entities |
| 95 | + π order |
| 96 | + π @x |
| 97 | + π model |
| 98 | + π order-item |
| 99 | + π @x |
| 100 | + π model |
| 101 | + π order-customer-info |
| 102 | + π @x |
| 103 | + π model |
| 104 | +``` |
| 105 | + |
| 106 | +Isolated Business Context (Preferred): |
| 107 | + |
| 108 | +```plaintext |
| 109 | +π entities |
| 110 | + π order-info |
| 111 | + π index.ts |
| 112 | + π model |
| 113 | + π order-info.ts |
| 114 | +``` |
| 115 | + |
| 116 | +An isolated context encapsulates all related logic (e.g., order items and customer info) within a single module, reducing complexity and preventing external modifications to tightly coupled logic. |
0 commit comments