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:

  1. Code is easy to find and locate. The code is organized in a way that reflects the product structure and corresponds to product requirements.

  2. 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.

  3. 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/componentsThe List contains application-wide shared components, so the List can use all of them.
  • src/features/posts/componentsList 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 fromlistViewdetailView, 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.