Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Excessive Entities

The entities layer in Feature-Sliced Design is the first layer that incorporates business logic, distinguishing it from the `shared` layer. Unlike the `model` segment, it is globally accessible (except by `shared`), making it reusable across the application. However, its global nature means changes can have a widespread impact, requiring careful design to avoid costly refactors.

## How to keep `entities` layer clean

To keep a maintainable `entities` layer, consider the following principles based on the application's data processing needs. Keep in mind that this classification is not strictly binary, as different parts of the same application may have “thin” or “thick” parts:

- Thin Clients: These applications rely on the backend for most data processing. They often do not require an `entities` layer, as client-side business logic is minimal and involves only data retrieval.
- Thick Clients: These handle significant client-side business logic, making them suitable candidates for the `entities` layer.

It is acceptable for an application to lack an `entities` layer if it functions as a thin client. This simplifies the architecture and keeps the `entities` layer available for future scaling if needed.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: when I was reading this part, I thought that this text is the advice on how to keep the Entities layer clean, but turns out that it's just an informational aside, and the actual advice is in the subsequent headings

suggestion: perhaps let's just make this an aside, that way those readers who already know about the distinction of thick vs thin clients could just skip it over:

Suggested change
## How to keep `entities` layer clean
To keep a maintainable `entities` layer, consider the following principles based on the application's data processing needs. Keep in mind that this classification is not strictly binary, as different parts of the same application may have “thin” or “thick” parts:
- Thin Clients: These applications rely on the backend for most data processing. They often do not require an `entities` layer, as client-side business logic is minimal and involves only data retrieval.
- Thick Clients: These handle significant client-side business logic, making them suitable candidates for the `entities` layer.
It is acceptable for an application to lack an `entities` layer if it functions as a thin client. This simplifies the architecture and keeps the `entities` layer available for future scaling if needed.
## How to keep `entities` layer clean
To keep a maintainable `entities` layer, consider the following principles based on the application's data processing needs — it is acceptable for an application to not have an `entities` layer if it functions as a thin client. This simplifies the architecture and keeps the `entities` layer available for future scaling if needed.
:::info[What are thick and thin clients?]
_Thick_ vs. _thin client_ distinction refers to how the application processes data:
- _Thin_ clients rely on the backend for most data processing. Client-side business logic is minimal and involves only exchanging data with the backend.
- _Thick_ clients handle significant client-side business logic, making them suitable candidates for the `entities` layer.
Keep in mind that this classification is not strictly binary, and different parts of the same application may be "thicker" or "thinner" clients.
:::

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although I kinda want to have the thick/thin client be the "0th principle" — like "do you even need the entities layer"


### Avoid Unnecessary Entities

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`:

```plaintext
📂 entities
📂 order
📄 index.ts
📂 model
📄 apply-discount.ts // Business logic using OrderDto from shared/api
📂 shared
📂 api
📄 index.ts
📂 endpoints
📄 order.ts
```

### Exclude CRUD Operations from Entities

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`:

```plaintext
📂 shared
📂 api
📄 client.ts
📄 index.ts
📂 endpoints
📄 order.ts // Contains all order-related CRUD operations
📄 products.ts
📄 cart.ts
```

For complex CRUD operations (e.g., atomic updates, rollbacks, or transactions), evaluate whether the `entities` layer is appropriate, but use it with caution.

### Store Authentication Data in `shared`

Avoid 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:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: I think this also collides a bit with the guide for authentication, where we present the entities layer as one of the options for storing auth data

suggestion: let's simply recommend storing auth data in shared for simple cases (i.e. most cases)


- 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).
- Using entities for auth data can lead to cross-layer imports (e.g., `entities` into `shared`) or usage of `@x` notation, complicating the architecture.

Instead, store authentication-related data in `shared/auth` or `shared/api`:

```plaintext
📂 shared
📂 auth
📄 use-auth.ts // Hook returning authenticated user info or token
📄 index.ts
📂 api
📄 client.ts
📄 index.ts
📂 endpoints
📄 order.ts
```

### Minimize Cross-Imports

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:

Non-Isolated Business Context (Avoid):

```plaintext
📂 entities
📂 order
📂 @x
📂 model
📂 order-item
📂 @x
📂 model
📂 order-customer-info
📂 @x
📂 model
```

Isolated Business Context (Preferred):

```plaintext
📂 entities
📂 order-info
📄 index.ts
📂 model
📄 order-info.ts
```

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.