What is complexity
The three reasons software systems become complex are size, structure, and change.
For three causes, we can simplify the system in the following ways:
- Divide and conquer, control size
- Keep the structure clear and consistent
- Embrace change
With these principles in mind, how do we organize our files and manage front-end project complexity?
There are two common ways to organize file structures in front-end projects
File-Type First (FTF)
“Organized by file type” is also the most common way to organize front end projects. Such as:
├── exercises │ ├── exercises │ ├── exercises │ ├─ exercises │ ├─ exercises │ ├─ exercises │ ├─ exercises │ ├─ exercises │ ├─ exercises │ ├─ exercises │ ├─ exercises │ ├─ exercises │ ├─ exercises │ ├─ exercises └ ─ ─ the UserList. Js ├ ─ ─ containers │ ├ ─ ─ home │ ├ ─ ─ posts │ │ └ ─ ─ index. The js │ └ ─ ─ the users │ └ ─ ─ index. The js ├ ─ ─ the actions │ ├ ─ ─ .js │ ├── reducers │ ├── pros.js │ ├── users.js │ ├─ sagas │ ── pros.js │ ├── users.jsCopy the code
Feature First
Organized by Functions and features. Such as:
The SRC ├ ─ ─ components │ ├ ─ ─ footer │ ├ ─ ─ the header │ └ ─ ─ index. The js ├ ─ ─ the features │ ├ ─ ─ posts │ │ ├ ─ ─ action. Js │ │ ├ ─ ─ The components │ │ │ └ ─ ─ index. Js │ │ ├ ─ ─ containers │ │ │ └ ─ ─ index. The js │ │ ├ ─ ─ reducers. Js │ │ └ ─ ─ sagas. Js │ └ ─ ─ the users │ ├ ─ ─ action. Js │ ├ ─ ─ components │ │ └ ─ ─ index. The js │ ├ ─ ─ containers │ │ └ ─ ─ index. The js │ ├ ─ ─ reducers. Js │ └ ─ ─ sagas. Js └ ─ ─ index.jsCopy the code
The “separation of concerns” difference
Both file organizations are doing “separation of concerns.” The difference is the understanding of “concerns.”
- File-type First’s “focus” is on technology and means.
- The “focus” of Feature First is functionality and goals.
Language is separated from component
A feature based approach to React development
Separate functions and Features
Why React developers should modularize their applications?
Which approach should you take?
File-type First is simple, direct, and intuitive. Feature First is better at managing the complexity of large-scale projects.
Delve into how Feature First files are organized
The advantages of Feature First file organization:
-
Code is easy to find and locate. The code is organized in a way that reflects the product structure and corresponds to product requirements.
-
The code is easier to maintain the isolation of each Feature. When the code in one Feature is modified, the modification and refactoring will not affect other features. When multiple features are developed in parallel, merge conflicts are avoided to a greater extent.
-
The Feature Flags mechanism is enabled
Feature Flag is a technique for configuring functional features without redeploying code.
Requirements such as A/B Testing can also be implemented using Feature Flags.
Example code:
// features.json{... .portal: true.users: true.posts: false
}
// index.js
export function isFeatureEnabled(feature) {
return features[feature] || false;
}
Copy the code
Complete Feature First
If a certain Feature is complex, it can be subdivided in one step to form a nested structure of Feature. For example, subdivide features/ Users into
features/users/features/detailView
features/users/features/listView
The SRC ├ ─ ─ the features │ └ ─ ─ the users │ ├ ─ ─ components │ │ ├ ─ ─ Table. Js │ │ └ ─ ─ index. The js │ └ ─ ─ the features │ ├ ─ ─ index. The js │ ├ ─ ─ DetailView │ │ ├ ── components │ │ ├ ─ detail.js │ ├ ─ listView │ ├ ─ components │ ├ ─ index.jsCopy the code
How do I organize shared components in my application
Some components can be reused across features and some components can be reused across pages within a Feature. To ensure good maintainability, the organization of shared components should follow clear rules.
Here is an example. (Index. js in the Components directory is only responsible for export components and does not implement specific functions.)
SRC ├── components │ ├── class.js │ ├─ features │ ├── posts │ ├── components │ ├─ index.js │ ├─ exercises └ ─ ─ the users │ ├ ─ ─ components │ │ ├ ─ ─ Table. Js │ │ └ ─ ─ index. The js │ └ ─ ─ the features │ ├ ─ ─ index. The js │ ├ ─ ─ the detailView │ │ └ ─ ─ │ ├─ class.js │ ├─ class.js │ ├─ class.js │ ├─ class.js │ ├─ │ ├─ Index.js │ ├── pagin.js │ ├── components │ ├─ index.js │ ├─ index.jsCopy the code
Please think about it, in the project structure, SRC/features/users/pages/listView/components/List. What are the components of js can share use?
Next, let’s look at each of them:
src/components
The List contains application-wide shared components, so the List can use all of them.src/features/posts/components
List is a different Feature from List, so you cannot use the components in the List.src/features/users/pages/detailView/components
, although the List belongs to the same Feature, if allowed fromlistView
到detailView
, will also increase the complexity of file reference in Feature. Therefore, such references are also prohibited.src/features/users/pages/listView/components/components
(components directory at the same level as List), the sub-components of the List are in the components directory at the same level, so access is allowed.src/features/users/pages/listView/components/components/component
(a child of the Components directory at the same level as List), “cross-layer references” also add complexity, so such references are not allowed.
The above situation can be summed up in one sentence:
In addition to the same directory file, a component can only refer to the Components directory in the path of its file level.
The SRC/features/user/pages/listView/components/List. Js in accordance with the above rules:
src/features/user/pages/listView/components/components
src/features/user/pages/listView/components
src/features/user/pages/components
src/features/user/components
src/features/components
src/components
You see this, you might be looking for a familiar figure. Yes, it is similar to the module lookup rule in CommonJS.
What to put in the Components directory? The strict meaning of the Components directory is to place only child components that are reused by their peers. For example, the above components directory, which is the same as List, should contain only the sub-components that List and Title can reuse.
Project complexity beyond the Feature
New logical hierarchy
In enterprise-level applications such as talent management and financial management, only apps and features can no longer correspond to the product structure as scheduled.
At this point, we need a new logical level, such as Solution. A Solution contains several apps, and each App has multiple features.
With the new logical level of Solution, the original Feature can be split into different apps according to the cohesion. Compared with Feature, the coupling between apps is smaller and can even be regarded as independent deployment units.
From multi-Module to multi-package
As the scale of the project grows, dependency management challenges arise. To reduce dependencies between features and further isolate between apps, modules reused across apps cannot simply be imported.
To reduce coupling between apps, reuse units need to be packaged into packages, and then each App declares its dependencies in package.json. Similarly, in the eyes of Solution, each App is also a package.
By moving from multi-module to multi-package, the coupling is reduced, but it also brings new costs to development, which can be solved by tools such as Lerna.
Using Lerna solves dependency and versioning issues, but in addition to that, you need to do a good job of layered package design.
Layered design in multi-package management
The App is a package, and the module the App depends on is also a package, but the two types of packages are of different quality.
In order to make the project structure clearer and easier to understand, we need to differentiate these packages and design them in layers. Such as:
│ ├── solutions │ ├── login.sln │ ├── finance.sln │ ├─ apps │ ├─ portal.app │ ├─ │ ├── Commissari.htm │ ├── Commissari.htm │ ├── Commissari.htm │ ├── Commissari.htm │ ├── Commissari.htm │ ├── Commissari.htm │ ├── Commissari.htm │ ├── Commissari.htm │ ├── Commissari.htm │ ├─ Network ├── Base-libs │ ├── UI-Components │ ├─ animations ├── Vin-libs │ ─ router ├─ state-managerCopy the code
conclusion
Compared with file-type First, Feature First has obvious advantages in improving the maintainability of large-scale projects.
- Easier to find and locate code files;
- Better control of the scope of impact when refactoring or changing code;
- Use Feature Flags more easily;
When organizing shared components within an application, you can follow a similar approach to finding modules as in CommonJS: components only refer to the Components directory in the path of their file level.
In large-scale projects such as enterprise-level applications, project complexity can be further controlled by introducing new logical layers and multi-package management.
The resources
- An in-depth analysis of software complexity
- feature-u: Feature Based Project Organization for React
- A feature based approach to React development
- How to better organize your React applications?
- How to use Redux on highly scalable javascript applications?
- The 100% correct way to structure a React app (or why there’s no such thing)
Author: Kong Changzhu
BDEEFE is recruiting excellent front-end engineers all over the country for a long time.