Skip to main content

Features

When to use?

When it becomes difficult to find the boundaries of specific user scenarios in a project, which worsens the controllability and reuse of logic

Use it only if you are sure that additional separation by features will help your application, and will not cause too much misunderstanding and skepticism! (instead, you can locate such logic directly in widgets) โš ๏ธ

features-themed-bordered

Description

Each feature is a part of the business logic, while it necessarily has meaning and value for the end user

  • ProductList, OfficeMap - can hardly be called features
  • WalletAddFunds, AddToCart - already makes more sense for the end user

At the same time:

  • the underlying layers are used to build the logic
    • shared, entities
  • one feature cannot import another
    • If there is such a need - the dependency needs to be transferred to the layer above / below, or solved through the composition through children-props
  • features cannot be nested, but they can be combined by a common folder, i.e. structurally
    • At the same time, you can not create intermediate files that are necessary for a specific group of features
  • You can only use re-export files

Structure

โ””โ”€โ”€ features/{slice}
โ”œโ”€โ”€ lib/
โ”œโ”€โ”€ model/
โ”œโ”€โ”€ ui/
โ””โ”€โ”€ index.ts

Thus, the feature stores information about:

  1. What data is needed for its operation
  2. By what rules do data changes occur
  3. What entities are needed for the complete construction of the feature
  4. How the data is presented to the user

Rules

One feature = one functionality

The feature contains code that implements one useful functionality for the user.

Structural grouping of features

Often there is a need to put together a number of somewhat related features (at the same time, they can and should not import each other directly)

The methodology recommends avoiding nested features, i.e. features that are strongly connected under a common wrapper with an additional one. by logic

Instead, the methodology suggests that, if necessary, group the necessary features by folders (at the same time, you can not link these features directly, folders are only needed for structural grouping by meaning)

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 re-export of features

Features should not depend on each other

This rule is not always possible to comply with, but it is better to minimize the number of such violations.

Usually, it is precisely because of the neglect of this rule that there is a high coupling between the modules of the system and unpredictable side effects during development.

One of the ways to solve the problem is to use entity.

Examples

From the point of view of the code: not all changes for the user are features, but all features are changes for the user.

Changing the application interface language

  • Feature for the user and the developer.

At the same time, the i18n logic itself can be used not only in this feature, but even in entities. Therefore, this should rather be placed in shared/lib or shared/config

A separate guide will be added later

Transfer of funds between accounts

  • Feature for the user and the developer.

Filter by tags

  • For the user: feature.
  • For the developer: entity tags allow you to implement a filter by tags inside feature.

Hints when filling in the form fields

  • For the user: feature.
  • For the developer: part of form entity.

Authorization by phone

features/auth/by-phone/ui.tsx
import { viewerModel } from "entities/viewer";

export const AuthByPhone = () => {
return (
// for redux - dispatch is additionally needed
<Form onSuccess={(user) => viewerModel.setUser(user)}>
<Form.Input
type="phone"
...
/>
<Form.Button
...
/>
</Form>
)
}

See also

[01/12] logo-mini