docs: add guidance on when to create an entity#898
Conversation
built with Refined Cloudflare Pages Action⚡ Cloudflare Pages Deployment
|
illright
left a comment
There was a problem hiding this comment.
The content is great, thank you! I agree with @Gaic4o that the diagram should perhaps be inserted as an image because it is unreadable when rendered by Docusaurus:
And I also think that the Reference section is not the best place to put advice. This documentation is structured by the Diataxis framework (https://diataxis.fr/), and we've been keeping advice mostly in Guides. Speaking of which, there is a guide about Excessive entities (Code smells & issues), and I have a feeling that this new section shares a lot of content with that guide, could we perhaps deduplicate and leave a link instead?
dyakubovskiy
left a comment
There was a problem hiding this comment.
I replaced the diagram with a Mermaid
dyakubovskiy
left a comment
There was a problem hiding this comment.
I replaced the diagram with a Mermaid one
|
[RU] Рекомендации по выявлению сущностей. Сущность - объект предметной области, который отражает суть бизнеса. Отличительная черта сущности - его уникальность. При проектировании слоя entities в рамках FSD нужно сначала определиться с бизнесом, что есть сущность по его уникальности. Например, уникальный атрибут у заказа - номер, у товара - артикул. Иногда, есть данные, которых не хватает для однозначного определения сущности. Тогда нужно изучить структуру, которую отдает бэк и найти уникальный атрибут, например, id. Если и этого не хватает для однозначного определения сущности, то можно подумать об объекте в реально жизни. Может ли он обладать своей уникальностью? Слой entities отражает ваши основные объекты и нуждается в проектировании на ранних этапах. Пример: Типичная задача. Заголовок: Описание:
Первый пункт. Может ли ФИО говорить об уникальности? Нет. А что с пользователем? Если по бизнесу нет явных атрибутов указывающих на ее уникальность, а их нет, то мы смотрим на технические атрибуты. У пользователя как и у роли есть атрибут id. Вывод: пользователь - сущность. Другой пример Заголовок: Описание:
Второй пункт нас не интересует. Первый пункт нам говорит о том, что у отчета есть уникальный ключ, который характеризует его как сущность. Не бойтесь общаться с бизнесом. Слой entities должен изменятся именно с изменениями в бизнесе. Я рекомендую нарезать сущности сразу, чтобы избежать анемичной модели (https://en.wikipedia.org/wiki/Anemic_domain_model). Важно! Это противоречит подходу с page first, потому что требует чуть больше времени и усилий. [EN] Recommendations for identifying entities. An entity is a domain object that reflects the essence of a business. The distinguishing feature of an entity is its uniqueness. When designing the entities layer within the FSD framework, it is necessary to first determine the business and identify the entity based on its uniqueness. For example, the unique attribute of an order is its number, while the unique attribute of a product is its SKU. In some cases, there may be data that is insufficient to uniquely identify an entity. In such cases, it is necessary to examine the structure provided by the back-end and identify a unique attribute, such as an ID. If even this is insufficient to uniquely identify an entity, it may be necessary to consider the entity in real life and determine whether it possesses its own uniqueness. The entities layer represents your primary objects and requires early design. Example: This is a typical task. Title: Description:
First point: Can the Full Name be considered unique? No. What about the user? If there are no explicit business-oriented attributes that indicate its uniqueness, and there are none, then we look at the technical attributes. The user, like the role, has an id attribute. Therefore, the user is an entity. Another example Title: Description:
We are not interested in the second point. The first point tells us that the report has a unique key that characterizes it as an entity. Don't be afraid to communicate with the business. The entities layer should change with changes in the business. I recommend slicing entities immediately to avoid an anemic model (https://en.wikipedia.org/wiki/Anemic_domain_model). Important! This goes against the page first approach because it requires a little more time and effort. |
…ced/documentation into feature/update_entities_info
|
I still think this page should not be in the Reference, but rather, in Guides. It gives advice rather than describing definitions and base principles, as the reference should, in my opinion. |
Solant
left a comment
There was a problem hiding this comment.
I got a read, I see good points how we can show proper usage of entities, but I am a bit concerned about a current state of this article:
- it is quite large and repeats itself a lot (in regards to business-management communication)
- examples are vue-specific, and it would be much better to show how to handle business logic in pure js (without react state and vue reactivity), as it might be hard for React developers to follow Vue example and vice-versa
- while text states that there should be a good reason to create an entity, in the examples there are couple of entities created straight from the
DTOtype, without any abstraction. so it looks like examples are trying to create an entity when it is not required (just for the sake of it), which can lead to leaky abstractions - some paragraphs are repeating already existing pages from the documentation
|
One concern about the In real-world products, “User” is often a very broad umbrella concept, so readers might interpret this page as “put all user-related business logic into With that in mind, I wanted to ask (carefully) whether there might be a better example than Also, in larger domains, it’s common to either: (a) modularize within the same slice by responsibility (e.g., splitting read/write operations and separating model concerns), for example: entities/user/
api/
queries/ # read operations
mutations/ # write operations
model/
permissions/
...(b) or split by domain context into more specific entities or slice groups. For example: entities/user/
guide/
profile/It might be helpful to mention these evolution paths so readers don’t assume a single giant Looking at the current example code, it seems like most of it follows a structure like this: shared/
api/
client.ts # infrastructure only
types.ts
entities/
user/
api/
user-api.ts # API + mapping (~100 lines)
model/
types.ts
use-user-permissions.ts # business logic (~150 lines)
index.tsSo I brought this up after thinking about it in that context. |
|
Taken into account and implemented in the new version. The file has been fully rewritten and moved from the reference section to guides — examples are now in React+TS and plain TypeScript without framework reactivity, repetitions are removed, the Approach A section is condensed with a link to the existing api-requests page, and architectural issues are fixed (entity type moved from |
Solant
left a comment
There was a problem hiding this comment.
I think the flow is a bit fragmented: some paragraphs have no text except the small code samples, and lists consisting of minimal synopses might not be enough for the reader to understand the idea behind the reasoning. So I suggest adding some reasoning/explanation
…eature/update_entities_info
Gaic4o
left a comment
There was a problem hiding this comment.
I’m also sharing a few additional suggestions that may help make the document clearer overall.
Gaic4o
left a comment
There was a problem hiding this comment.
I think the topic of this document is good. When to Create an Entitys something people often struggle with when applying FSD, so I think it makes sense to cover it as a separate guide.
That said, some parts of the current content seem to overlap with the existing Excessive Entities document. It might be better to link to that document for the overlapping parts, and have this document focus more on what kinds of logic should be managed in the entities layer after an entity is introduced.
In practice, once the entities layer is introduced, it can often be unclear which logic belongs to the entity itself and which logic is closer to a specific feature or user scenario. From that perspective, I think explaining the boundary with the features layer would help readers understand the role of the entities layer more clearly.
|
|
||
| ## Philosophy of the Approach | ||
|
|
||
| FSD follows the **"Local First"** principle — start with local code in `pages/`, and extract to common layers only when there's **real necessity**. |
There was a problem hiding this comment.
I read through the PR again, and I think some parts overlap with the existing Excessive Entities document.
In particular, the approach of using shared/api and the idea that the entities layer does not need to be added from the beginning are already covered in that document. So it might be better to link to it as a reference for those parts. Otherwise, the roles of the two documents may end up feeling somewhat overlapping.
Instead, I think this document could focus more on what criteria should be used to decide whether to create an entity, and what kinds of code should be managed together inside the entities layer once we decide to separate something as an entity.
What do you think?
| **Approach 0: Locality** (always recommended as a starting point) | ||
| - Code stays in `pages/` | ||
| - Used in only one place | ||
|
|
||
| **Approach 1: Centralized API** (`shared/api`) | ||
| - API and types in one place | ||
| - Migration to `entities/` when complexity grows | ||
|
|
||
| **Approach 2: Domain API** (`entities/*/api/`) | ||
| - Driven by business domain understanding — if an object has a unique business identifier and meaningful behavior, it warrants its own slice | ||
| - API placement inside the entity slice follows from that decision, not the other way around | ||
| - Full encapsulation from day one | ||
|
|
||
| All three approaches align with **FSD philosophy**: avoid premature decomposition and add layers as needed. |
There was a problem hiding this comment.
I also thought about the section that introduces Locality, Centralized API, and Domain API as three separate approaches.
I think it might be clearer to describe this as a recommended gradual flow rather than as three separate options. In practice, code usually starts locally in the pages layer. When it starts being reused across multiple pages, it can move to shared/api. Then, once business rules or domain responsibilities become clearer, it can move to entities/*.
With the current structure, readers might understand these as three approaches to choose from depending on the situation, rather than as steps that naturally build on each other. Presenting them as a gradual flow could make the document more aligned with the Local First principle and easier to follow.
What do you think?
| **2. Other developers start copying your code** | ||
|
|
||
| If colleagues are copying your code — that's a signal to extract a shared module. |
There was a problem hiding this comment.
I also thought a bit about this part.
The current wording could read a bit strongly, as if other developers starting to copy the code naturally means the next step is to extract it into a shared module. However, in the From a custom architecture section of the official docs, it says that copy pasting is not architecturally wrong by itself, and that in some cases duplicating code can be more appropriate than abstracting it into a new reusable module.
So instead of framing this as a signal that the code should be extracted into a shared module, I think it might fit better with the tone of the official docs to describe it as a signal to check whether the same code is being repeated with the same intent in multiple places, and whether extracting it into a reusable module would actually be more appropriate.
What do you think?
| ### Utility Functions | ||
|
|
||
| ```typescript title="shared/lib/formatters.ts" | ||
| // These are utilities, not business logic | ||
| export const formatDate = (date: Date) => | ||
| new Intl.DateTimeFormat('en-US').format(date) | ||
| ``` | ||
|
|
There was a problem hiding this comment.
I think the formatDate example might not be necessary in this section. It seems clearly closer to a reusable utility function than a business entity, so it does not feel like a case where readers would really wonder whether it should belong in the entities layer.
For this document, I think it might be more helpful to use an example where the placement is actually a bit ambiguous. Otherwise, I think this example could also be removed.
What do you think?
| - Teams starting to work with FSD | ||
| - Small projects (fewer than ~10 screens) | ||
| - Projects with frequently changing business logic | ||
| - When it's unclear which entities have stabilized |
There was a problem hiding this comment.
- Teams starting to work with FSD
- Small projects (fewer than ~10 screens)
- Projects with frequently changing business logic
- When it's unclear which entities have stabilized
....
## Approach 2: Domain API (`entities/*/api/`)
In this approach, each entity lives fully inside its own slice — including the API, DTO mapping, domain types, and business logic.
### When to Use
- Medium and large projects
- Teams experienced with FSD
- Projects where backend API stability matters
- Long-lived enterprise applications
I agree with the idea that shared/api can be a more practical option for small projects or for teams that are not yet familiar with FSD. If a team introduces the entities layer too early without being comfortable with FSD, the structure can become more complex and harder to manage consistently.
That said, I think the “fewer than 10 screens” criterion might be worth handling a bit carefully. Even if a project has only a small number of screens, there can still be cases where the same DTOs or API responses are reused across multiple pages, or where the same mapping logic starts appearing in several places. In those cases, it may be hard to decide based on project size alone.
So rather than focusing on the number of screens, I think it might feel more natural to explain this in terms of how the code is actually reused, whether the domain responsibility is clear, and whether the team can manage that layer consistently.
What do you think?
Background
Русский:
Добавляет практические рекомендации по выделению сущностей (entities) на этапе масштабирования проекта. Рекомендации помогают избежать распространённых ошибок при проектировании архитектуры: преждевременного выделения сущностей или, наоборот, запоздалого рефакторинга.
English:
Adds practical recommendations for extracting entities during project scaling. The guidelines help avoid common architectural pitfalls: premature entity extraction or, conversely, delayed refactoring when the codebase has already become entangled.
Changelog
Русский:
English: