-
Notifications
You must be signed in to change notification settings - Fork 213
docs: add entities.mdx example #859
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,47 @@ | ||||||||
| --- | ||||||||
| sidebar_position: 5 | ||||||||
| --- | ||||||||
|
|
||||||||
| # Entities | ||||||||
|
|
||||||||
| `entities` layer in Feature-Sliced Design encapsulates core business logic, similar to entities in backend applications. However, its use in frontend applications is not always necessary and should be approached with caution to avoid overcomplicating the codebase. | ||||||||
|
|
||||||||
| ## When to Use the `entities` Layer | ||||||||
|
|
||||||||
| Most frontend applications function as "thin clients" with minimal business logic, relying on the backend for data processing. In such cases, `entities` layer can often be omitted in favor of `shared/api`. Use `entities` layer only when the following conditions are met: | ||||||||
|
|
||||||||
| - The application handles **client-only data structures** with significant **client-only business logic**. | ||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. issue: I don't entirely agree here that a data structure needs to be client-only to warrant a place in entities. As an example from my practice, one application I worked on had some non-trivial logic of computing whether the project in its current state can be moved to the next stage. The project was made up of blocks, and each type of block needed to fulfill a certain different condition before the whole project was ready to move to the next step. This logic was implemented on the backend, but for real-time feedback, it was also reimplemented on the frontend. To me, this reimplementation of business rules is still very much business logic, even if it's not client-only (although to be fair, maybe this particular case relates more to features than entities, but I think my point here still stands). suggestion: let's broaden the definition:
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I messed up the "suggested change", I meant to replace not just the first bullet point, but both of them There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I refactored this section a bit to make sure that “hybrid” is not an exceptional case: The idea is to make sure that:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This comment wasn't really addressed by that change — the "client-only" part is still present further in the text |
||||||||
| - The entity is **heavily reused** across multiple parts of the application. | ||||||||
|
|
||||||||
| If you end it a situation where you can't create an entity, but you have a significant amount of reused client-only business logic, you can do a hybrid approach: | ||||||||
|
|
||||||||
| - Keep all types/DTOs in `shared/api` without creating a new entity. | ||||||||
| - Use `shared/api` for data fetching operations like create, read, update, delete, filter, etc. | ||||||||
| - Use `entities/<name>/model` for client-only business logic. | ||||||||
|
||||||||
|
|
||||||||
| ### Examples of Valid Use Cases | ||||||||
| 1. **Client-Only Entities**: If the frontend manages an entity that does not exist on the backend and involves complex business logic, consider placing it in `entities` layer. This is appropriate only if the entity is used extensively across the application. | ||||||||
|
||||||||
| 2. **Aggregating Microservices Data**: When the backend is split across microservices and the frontend needs to combine data with significant client-side business logic, an aggregate entity in `entities` layer may be justified. | ||||||||
illright marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||
|
|
||||||||
| :::note | ||||||||
|
|
||||||||
| Both heavy client-side business logic and client-only data structures must be present to justify creating an entity. If either criterion is missing, avoid creating an entity. | ||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. issue: this line forbids doing something without really offering an alternative, which could leave the user stranded, not knowing what to do suggestion: this whole line would also probably change if we remove the "client-only" condition. Regardless, I think we should direct the user towards some libraries for managing server state like TanStack Query, although I'd prefer if this wasn't our only suggestion, since there's a fair amount of people who dislike it. At least for TanStack Query we have a guide that we can point to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will try to address several points at once: I did this proposal in a more prescriptive manner intentionally to create a steiger-like ruleset. So the new developers and developers with heavy DDD-like background don't find a leeway in definitions that will let them create unnecessary entities and prevent them from creating bad abstractions (and blaming FSD for this) I agree that repeating the same idea 3 times might be an overkill, but I would like to keep the overal "prescriptiveness" (especially now, when logic can be placed to this layer without creating a new entity) |
||||||||
|
|
||||||||
| ::: | ||||||||
|
|
||||||||
| ## Best Practices | ||||||||
|
|
||||||||
| To maintain a clean and maintainable codebase, adhere to the following rules: | ||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. issue (non-blocking):
this feels like an overpromise to me :) There are many other factors in maintaining a clean and maintainable (tautological btw) codebase suggestion:
Suggested change
|
||||||||
|
|
||||||||
| - **Avoid Dangling Entities**: Do not create entities that are used only once. Treat `entities` layer like any other layer in a pages-first approach, ensuring entity is actually needed. | ||||||||
|
||||||||
| - **Avoid Dangling Entities**: Do not create entities that are used only once. Treat `entities` layer like any other layer in a pages-first approach, ensuring entity is actually needed. | |
| - **Avoid Dangling Entities**: Be suspicious of entities that are used only once. If the entity doesn't facilitate code reuse across several pages, consider moving its code into the page itself if it's possible and practical. This will increase the cohesion of your code, ensuring that related things are close to each other. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick (non-blocking): I'm also not sure what the point of the title case is in "Avoid Dangling Entities". It's okay-ish on this line, but on the next line, "Do Not Replicate Backend Entities", it makes my eyes jump way too often as I read.
suggestion: I think these rules would look just as good without title case:
- **Avoid dangling entities**: …
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: this feels a bit too prescriptive. I don't see that much of a problem with putting API requests and DTOs in Entities as long as it's a conscious decision because for some reason, putting them in shared/api didn't sit right with the team. I think we should advocate for putting API code in Shared, but not prescribe it
suggestion: let's tone this down a bit:
| - **Do Not Replicate Backend Entities**: Backend entities and API responses belong in `shared/api`, not `entities` layer. `entities` layer is for client-specific logic, not for mirroring server-side data structures. | |
| - **Consider keeping backend-related code in `shared/api`**: The Entities layer works best for encoding business logic rules. If these rules are mostly encoded on the backend, consider moving your API request functions, DTOs, and mappers into `shared/api`. This provides fewer architectural restrictions, which can help you iterate faster and avoid arguments when a backend endpoint relates to several kinds of entities at once. |
I also added an explanation for why it's preferable to consider that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: I think we've made our point, this feels like rephrasing the same thing again :D
suggestion: let's drop this section

Uh oh!
There was an error while loading. Please reload this page.