Cross-imports
Maqola yozilish jarayonida
Uning yaratilishini tezlashtirish uchun siz:
- π’ Fikr-mulohaza ulashing chiptada (sharhlar/reaksiya emoji)
- π¬ Mavzu boyicha to'plamlarni chiptaga yig'ish suhbatdan olingan material
- βοΈ Hissa qoβshish har qanday boshqa yo'l bilan
π° Stay tuned!
Cross-imports appear when a layer/abstraction starts taking on too much responsibility than it should. That is why the methodology allocates new layers that allow these cross-imports to be decoupled.
Introductionβ
Cross-import is a situation in which, within a layer, there is a need to import data from one slice to another.
The article only deals with conflict situations when importing between slices. Within one slice, fragments can import each other, such a situation is not prohibited.
Let's imagine that we are developing a TODO List application for storing notes. We need to store several task cards and display them on a board. There can be several boards with cards. Let's look at a simplified example of the structure of such an application:
π entitiesπ taskπ uiπ TaskCard
π boardπ uiπ BoardTasks
In this example, the BoardTasks component needs to import the TaskCard component to display cards.
You cannot import the TaskCard component directly, as this would violate the principle of low coupling and make it more difficult to maintain the project in the future.
Cross-import solutions optionsβ
Merging multiple slices into oneβ
As you can see from the example above, the domain of the TaskCard and BoardTasks components are quite similar, which means it is possible to create a derived slice from the two existing ones, where both methods would be in the same directory.
The result of merging the task and board slices:
π entitiesπ boardπ uiπ TaskCardπ BoardTasks
As you can see from the example, we have eliminated the situation where one slice imports data from another and achieved high cohesion and low connectivity within a segment of a single slice.
Moving code to a higher layerβ
This option is more suitable for those cases where combining several slices into one is difficult or impossible.
It is likely that the slice into which you are importing data from another slice is highly logically rich and can be moved to a higher layer to eliminate the connectivity of slices within a single layer.
Let's imagine that the board slice is more dense with business logic than in the example above, then merging it with the task slice will create additional clutter, so a good solution would be to restructure the logic of the board slice in a higher layer.
The result of moving the logic of the task and board slices:
π entitiesπ taskπ uiπ TaskCard
π featuresπ view-boardπ uiπ BoardTasks
By restructuring the logic of the board slice on the features layer (not necessarily on it, any layer higher in the hierarchy will do), its domain area was more specifically clarified, and it became possible to build a correct import mechanism from the point of view of the layer hierarchy.
Duplication codeβ
If the amount of data you are going to import from another slice is small, it may be worth duplicating it into the current slice. However, this option should not be a priority among all the above.
What if cross-import is inevitable?β
The approach described in this section is experimental and has not yet been standardized. However, in exotic situations, the information in this section may be useful.
If your project requires cross-import and the three methods described above did not help, the Feature Sliced ββDesign community offers the following solution to the problem.
π entitiesπ taskπ uiπ TaskCard
@xπ boardπ uiπ BoardTasks
@x
@xβ
@x - this is an experimental approach where within a slice you can create an explicit public export of only those modules that can be used within multiple slices of the same layer.
Let's look at an example (TSX markup):
export { TaskCard } from './ui/TaskCard.tsx';
Component inside slice that needs cross import:
import { TaskCard } from '/entities/task/@x/TaskCard';
export const BoardTasks = () => {Β return (
Β Β <div>
Β Β Β <TaskCard title="Task#1" description="Description..." />
Β Β Β <TaskCard title="Task#2" description="Description..." />
Β Β Β <TaskCard title="Task#3" description="Description..." />
Β Β </div>
Β )
}
As you can see from the import path in the BoardTasks file, thanks to the export from the @x file, it is clear that this module is not intended for public use, but exists only to be imported into another slice.
Lifting the ban on cross-importsβ
If you have tried all the methods in the article, but for some reason still could not get rid of cross-imports, perhaps it is worth considering lifting the ban on them within specific slices, or the entire project as a whole. However, it is important to understand that lifting the ban on cross-imports could potentially have a negative impact on the overall structure of the project.
Useful linksβ
- The Feature Sliced ββDesign team has developed a tool that allows you to automatically check for cross-imports in a project: SteigerΒ
- More information about the cross-import rule: Steiger-Forbidden-ImportsΒ