Skip to content

Conversation

Solant
Copy link
Contributor

@Solant Solant commented Aug 25, 2025

Background

Right now entities is very tricky to use, and we constantly need to assist people with it. The idea of this proposal is to gather feedback and formalize how and when to use this layer, to make sure that everyone understands when and how to use it

After formalization, I would also like to refactor https://feature-sliced.github.io/documentation/docs/guides/examples/auth guide to make sure that we don't suggest creating entities layer before it is actually required by the project

Copy link

github-actions bot commented Aug 25, 2025

built with Refined Cloudflare Pages Action

⚡ Cloudflare Pages Deployment

Name Status Preview Last Commit
pr-fsd ✅ Ready (View Log) Visit Preview 6533882

Copy link
Member

@illright illright left a comment

Choose a reason for hiding this comment

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

Phew, this is a complicated page, but I'm really glad you decided to write it up!

One overarching concern I have with this page is that I'm not sure it belongs in "Guides > Examples" (which frankly is a terrible name for a section, it should be "Guides > Common Tasks" or something, we'll need to workshop this a bit).

I don't think that there is room for this page in the current structure of "Guides", but since it's a very important page, we should probably restructure the Guides section altogether. I don't have any concrete suggestions yet, but I'll think about it.

Anyway, thank you very much, this is great work


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**.
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 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
- The application handles **client-only data structures** with significant **client-only business logic**.
- The frontend encodes certain rules about how data structures behave, i. e., _business logic_.
- This business logic is used in several parts of the application or is central to the entire purpose of the application.

Copy link
Member

Choose a reason for hiding this comment

The 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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  • Developers don't create entities by copy-pasting DTOs, as it will require workarounds like cross-imports and lead to the issue of the entities layer not providing any meaningful abstraction.
  • Let developers put business logic inside the entities layer, but keep DTOs on a different layer to allow future abstractions from DTOs (if required).

Comment on lines 16 to 20
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.
Copy link
Member

Choose a reason for hiding this comment

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

issue: this part is a bit confusing to me overall.

If you end it a situation where you can't create an entity

How can this situation arise? Does "can't" here refer to external factors or does it refer to the rules above that dictate that you "mustn't" create an entity?

you have a significant amount of reused client-only business logic

I think a short example would really benefit this section, off the top of my head I'm struggling to imagine what this might look like. Particularly, in light of my previous comment, I'm not sure what is "client-only" business logic, and if such business logic even exists. To me, a client, a frontend, should never be the only party that controls data consistency and adherence to business rules, because a client can never be trusted.

suggestion: I think this hybrid approach is an idea with great potential, so we might be better off dedicating an entire section to it, rather than trying to squeeze it in here. Then we'd also be able to provide examples and expand on the scenario that this hybrid approach might be preferable, as well as mention some pros and cons

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Answered in #859 (comment) , but we can replace "busines logic" with something like "data processing".

- 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.
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 we're often using the term "entity" without establishing first what an entity is, even though that's what the whole section is about

suggestion: I think DDD has run up against the same issue before, so we might be able to look to them for inspiration for a defintion of "entity". This question on Stack Overflow, for example, provides some insight, but will still probably need more explanation: https://stackoverflow.com/questions/57367017/the-meaning-of-entity-in-domain-driven-design

Copy link
Member

Choose a reason for hiding this comment

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

question: Regarding this part:

This is appropriate only if the entity is used extensively across the application

I'm struggling to come up with an example of an entity that would have complex business logic, but wouldn't be worthy of being put into the entities layer. Do you have some examples?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I will probably need some help with defining "Entity", as for now we only describe it by its properties, and it is challenging to make a good formal description 🤔

And tried to specify "heavy" use with https://en.wikipedia.org/wiki/Rule_of_three_(computer_programming)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I got something like this: "An entity is essentially a logical representation of a specific piece of data that can be uniquely identified and has a distinct existence within a system.", but at this point we are hitting philosophical questions like those:

071-3387264583.jpg


### 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.
Copy link
Member

Choose a reason for hiding this comment

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

suggestion (non-blocking): this point might not necessarily be about microservices, but broadly also about any kind of aggregation and synchronization of data from several sources, we can probably expand the example here or add another point

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done


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

Choose a reason for hiding this comment

The 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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Choose a reason for hiding this comment

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

issue (non-blocking):

To maintain a clean and maintainable codebase

this feels like an overpromise to me :) There are many other factors in maintaining a clean and maintainable (tautological btw) codebase

suggestion:

Suggested change
To maintain a clean and maintainable codebase, adhere to the following rules:
To make the Entities layer easy to navigate, adhere to the following rules:


To maintain a clean and maintainable codebase, adhere to the following rules:

- **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.
Copy link
Member

Choose a reason for hiding this comment

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

issue: there might be legitimate reasons to create entities that are only used on a single page, if that page is the main thing about the application. I'm talking about some highly interactive web app like an editor of some kind.

suggestion: let's loosen this criterion, after all, it's "pages-first", not "pages-only".

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**: 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.

Copy link
Member

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**: …

To maintain a clean and maintainable codebase, adhere to the following rules:

- **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.
- **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.
Copy link
Member

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:

Suggested change
- **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

Comment on lines +39 to +47
## Common Pitfalls

Seasoned developers may be inclined to create an entity for every piece of data in the application. This is a mistake in FSD. Overusing the entities layer can lead to unnecessary complexity and maintenance overhead. Most frontend applications function effectively without `entities` layer, relying instead on `shared/api` for data fetching and minimal logic.

:::note

Prematurely introducing `entities` layer can harm the project's scalability and maintainability. Evaluate whether the layer is truly necessary before adding it.

:::
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 we've made our point, this feels like rephrasing the same thing again :D

suggestion: let's drop this section

@Solant
Copy link
Contributor Author

Solant commented Aug 28, 2025

Hey, thanks for the review, I tried to address the majority of questions

I agree that Guides is not the correct place for this article; I just want to see how far we can get to clarifying entities before moving/refactoring it into an appropriate section.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants