App splitting
Group: Layers
The first level of separation: according to the scope of responsibility of the module
Self-check
"Which application layer does the module belong to?"
โโโ src/
โโโ app/ # Initializing application logic
โโโ processes/ # (Optional) Application processes running over pages
โโโ pages/ # Application pages
โโโ widgets/ # Independent and self-contained blocks for pages
โโโ features/ # (Optional) Processing of user scenarios
โโโ entities/ # (Optional) Business entities that domain logic operates with
โโโ shared/ # Reused modules, non business specific
Layer order
If you look at the order of the layers , you can distinguish two general patterns:
By the level of knowledge/responsibility
app
> processes
> pages
> features
> entities
> shared
The module "knows" only about itself and the underlying modules, but not the ones lying above
This also affects the allowed imports
By the level of danger of changes
shared
> entities
> features
> pages
> processes
> app
The lower the module is located , the more dangerous it is to make changes to it
Because most likely it is used in many overlying layers
Group: Slices
The second level of separation is by specific BL functionality
The methodology has almost no effect on this level and much depends on the specific project
Self-check
"What scope of BL does the module affect?"
Before that , it is necessary to determine the scope of responsibility (layer)
โโโ app/
| # Does not have specific slices,
| # Because it contains meta-logic on the project and its initialization
โโโ processes/
| # Slices implementing processes on pages
| โโโ payment
| โโโ auth
| โโโ quick-tour
| โโโ ...
โโโ pages/
| # Slices implementing application pages
| # At the same time, due to the specifics of routing, they can be invested in each other
| โโโ profile
| โโโ sign-up
| โโโ feed
| โโโ ...
โโโ widgets/
| # Slices implementing independent page blocks
| โโโ header
| โโโ feed
| โโโ ...
โโโ features/
| # Slices implementing user scenarios on pages
| โโโ auth-by-phone
| โโโ inline-post
| โโโ ...
โโโ entities/
| # Slices of business entities for implementing a more complex BL
| โโโ viewer
| โโโ posts
| โโโ i18n
| โโโ ...
โโโ shared/
| # Does not have specific slices
| # is rather a set of commonly used segments, without binding to the BL
Rules
Since a slice is a specific level of abstraction, the methodology is obliged to impose certain rules on it
Low Coupling & High Cohesion
Slices of the same layer cannot use each other directly, and their interaction and composition should be determined on the upper layer, relative to their current one
// Bad: the feature imports another feature (slices of the same layer)
import { Bar } from "features/bar"
function Baz({ foo, ...barProps}) {
...
<Bar {...barProps} />
}
// Good: features are compiled on the page (overlying layer)
import { Baz } from "features/baz"
import { Bar } from "features/bar"
function Foo() {
...
<Baz {...fooProps}>
<Bar {...barProps} />
</Baz>
}
Grouping
In most cases, you should avoid nesting in slices, and use only structural grouping by folders, without additional coupling logic
features/order/ # Feature group
โโโ add-to-cart # Full-fledged feature
โโโ total-info # Full-fledged feature
- โโโ model.ts # General logic for the group
- โโโ hooks.ts # General hooks for the group
โโโ index.ts # Public API with feature re-exportAt the same time, some layers (e.g., pages) initially require nesting due to the requirements of the project / framework
pages/
โโโ order/
| โโโ cart/
| โโโ checkout/
| | โโโ delivery/
| | โโโ payment/
| โโโ result/
| โโโ index.tsx
โโโ auth/
| โโโ sign-in/
| โโโ sign-up/
โโโ home/
โโโ catalog/
Important
Nested slices should be avoided as much as possible, but even if you have to use them (for example, for pages), you need to link them explicitly, to avoid unforeseen consequences
Group: Segments
The third level of separation: by the purpose of the module in the code and implementation
Self-check
"What part of the technical implementation of the logic affects the module?"
Before that, it is necessary to determine the scope of influence (layer) and domain affiliation (slice)
{layer}/
โโโ {slice}/
| โโโ ui/ # UI-logic (components, ui-widgets,...)
| โโโ model/ # Business logic (store, actions, effects, reducers,...)
| โโโ lib/ # Infrastructure logic (utils/helpers)
| โโโ config*/ # Configuration (of the project / slice)
| โโโ api*/ # Logic of API requests (api instances, requests,...)
At the same time, each segment can be represented as a file, or as a separate directory - depending on the complexity and size
Restrictions
The methodology was developed with the aim of not limiting and not bothering developers with the rules for choosing abstractions (it's desirable to use any segment in any layer)
However, as a result of discussions and analysis of extensive experience - it was determined that it is better and more practical to limit each layer to segments used internally.
General rules
- The higher the layer is located , the more it knows about the BL of the application and vice versa
- API logic recommended should be put in
shared
so that the logic is not scattered around the project
- Usually, it is common and presented as single instances
- Edge-case "exceptions": GraphQL, react-query hooks
Application for layers
Layer | Content | Allowed Segments |
---|---|---|
app | Does not include slices and contains initialization logic | The existing segments are not quite suitable, and therefore /providers (/hoc, ...) , /styles , etc. are usually used. It depends very much on the project and is unlikely to be solved by the methodology |
processes | The slices inside include only business logic, without displaying (1) | ui lib model (api ) |
pages | The slices inside include a ui and model composition of various features for a specific page | ui lib model (api ) |
features | The slices inside include the composition of entities and the implementation of BL in the model + display | ui lib model (api ) |
entities | The slices inside represent a disparate set of submodules for using | ui lib model (api ) |
shared | Contains only infrastructure logic without BL (1) | ui lib api |
See also
- (Discussion) Methodology abstractions, their goals and naming
- Discussions on naming entities
processes
vsflows
vs ...- Primary description of abstractions
- (Article) About the organization of the code base with a complete comparison of several approaches
- (Article) About project modularization
- (Reference) Layers
- (Reference) Segments