What is componentization?

What is a component? “Component” is generally used to name small function blocks, such as drop-down refresh component and prompt box component. And the larger granularity of business functions, we used to call “module”, such as: home module, my module, news module.

The topic of this discussion is componentization, and for the sake of presentation, the following modules and components represent the same thing, both of which refer to business modules with larger granularity.

2. What is componentization?

Componentization, or modularization, is used to divide, organize, and package software. Each module completes a specific sub-function, and all the modules are assembled in a certain way to become a whole to complete the function required by the whole system.

From the level of engineering code, componentization is usually implemented by middleware to solve the problem of header file direct reference and dependency disorder between components. In terms of actual development, the biggest requirement between components is the page jump, which needs to jump from the pageA page of component A to the pageB page of component B, avoiding direct dependence on the ViewController header file of component B.

Two, why to componentize?

It is discussed from two aspects:

1. What problems is componentization to solve?

An APP has multiple modules, which communicate with each other and call each other. For example, our securities APP has modules such as home page, market, information and mine. These modules will call each other, for example, the bottom of the home page needs to display part of the information, market; Market bottom need to display stock information; Information page needs to jump to quotes, etc.

How do we usually call, take the home page call information as an example, will write:

#import "HomeViewController.h"
#import "NewsViewController.h"

@implementation HomeViewController

+ (void)gotoNews {

 NewsViewController *detailVC = [[NewsViewController alloc] initWithStockCode:self.codeNum];
 [self.navigationController.pushViewController:detailVC animated:YES];
}

@end
Copy the code

It looks good, it’s straightforward, there’s nothing extra, it’s recommended to do it quickly at the beginning of the project, but as the project gets bigger, what’s wrong with it?

Problem 1: Each module is inseparable from other modules, which are interdependent and glued together into a lump:

3. The business side’s development efficiency is not high enough (only care about their own components, but compile the whole Project, mixing with other irrelevant code).

2, the benefits of componentization?

General meaning:

Faster compilation (no need to compile a large pile of host and guest code); Free choice of development posture for each component (MVC/MVVM/FRP); Component engineering itself can develop tests independently, which makes it easy for QA to conduct targeted tests; Standardize the communication between components, so that each component provides a black box service externally, reduce communication and maintenance costs, improve efficiency; Practical significance for the company’s existing projects:

Business is layered and decoupled to make code maintainable; Effectively split and organize the increasingly large engineering code, so that the project catalog becomes maintainable; It is easy to split and extract all business functions to realize real function reuse. Business isolation, cross-team development code control and version-risk control implementation; Modularization has certain requirements on the encapsulation and rationality of the code, so as to improve the design ability of the development students; In the case of good maintenance of all levels of components, random combination to meet different customer needs; (Just assemble the previous multiple business component modules in the new main App to quickly iterate the next new App)

3. Under what circumstances is componentization appropriate?

Of course, componentization also has its drawbacks:

The cost of learning is high, and the requirements for developers to master various tools are also high, which makes it difficult for beginners to get started.

Due to the complexity of tools and processes, collaboration between teams becomes more costly and, in some cases, less effective.

When the project App is in the initial stage and each requirement module is becoming mature and stable, componentization may not be so urgent, and even considering the componentized architecture may affect the development efficiency and demand iteration.

After a certain period of project iteration, some relatively independent business functional modules will appear, and the size of the team will gradually grow with the project iteration. This is the time to consider the componentization of small and medium-sized applications. For better division of labor, it is common for teams to arrange for each team member to maintain a relatively independent business component.

This is the right time to introduce a componentization solution. In the long run, the benefits of componentization far outweigh the disadvantages, especially as the project grows in size

Three, how to componentize?

The development of componentization needs to solve the following levels of problems:

1. The architectural goal of componentization?

To borrow Limboy’s picture:

2. How to divide components?

  • Basic Functional Components
  • Base product Components
  • Personalized business component

For a project that has not implemented component-based splitting, which is likely to be full of irrational classes, methods, headers, and miscellaneous dependencies, the first step is to split modules.

Module splitting can be divided into two parts, basic module splitting and business module splitting. Base modules are usually stable dependent code, while business modules are code that involves the business and needs to be changed frequently.

Basic module split

Basic modules are required by any App, such as performance statistics, Networking, Patch, network diagnosis and data storage modules. For base modules, they should be self-consistent, that is, they can be compiled individually or several modules together can be compiled separately. All dependencies should be business module to base module. Horizontal dependencies between base modules should be avoided as much as possible.

Service module splitting

For business modules, considering that the old code may not have the relevant horizontal decoupling strategy, the dependencies between business modules will be very complex and difficult to separate, so we take the approach of reorganizing from the group perspective first.

For high-volume projects, I personally prefer a “business-layered” structure to a “layer-business” structure, such as the following group structure:

- BusinessA
  - Model
  - View
  - Controller
  - Store
- BusinessB
  - Model
  - View
  - Controller
  -Store
Copy the code

Instead of the one used in the current project:

- Controllers
  - BusinessA_Controller
  - BusinessB_Controller
- Views
  - BusinessA_View
  - BusinessB_View
- Models
  - BusinessA_Model
  - BusinessB_Model
Copy the code

3. Technical difficulties of componentization?

Componentization is, intuitively, a matter of putting the code for each business component in its own folder or JAR package.

This leads to the following:

3.1 Problem of component splitting:

You can use CocoaPods and Git to do code version management, independent business module into a separate library.

But this is only a physical split, the split code will not be able to compile, because:


#import "MainViewController.h"
#import "HomeViewController.h"
#import "NewsViewController.h"
#import "MeViewController.h"
#import ...

@implementation MainViewController

@end
Copy the code

The MainViewController can’t find headers for other modules it depends on. This leads to another question:

3.2 How to decouple components?

Decoupling between components is a problem that must be solved in componentization. In other words, how to remove horizontal dependencies between business modules. Take the example above:

How to import xxViewControllers from MainViewController when the App’s root view MainViewController needs to manage the home page, news, My, etc.?

It is quite simple. According to the idea of software engineering, it subconsciously adds a Mediator:

Intuitively, however, this does not have any benefits. The dependence relationship is not removed. Mediator relies on all modules, while the caller relies on Mediator, and finally it is still a lump of mutual dependence.

What we hope to achieve in the end is a one-way dependency, namely:

3.3. In this regard, we can refer to the popular schemes in the industry:

Based on the URL Router, ModuleManager represents: Mogujie Limboy

Based on target-action, Runtime, and Category: Casa

The specific implementation scheme is abstract, so we will not discuss it in detail here. We can refer to Demo:

Not based on the Target – the Action

Demo2 is based on URL Router

Four, other

Development process control

Hosting platform selection

The use of their own open source scheme to build a private hosting platform, the maximum limit to ensure the security of the code. The best-known and most widely used open source solution is Gitlab.

Componentization allows us to go from a single master project to a master project + multiple split base modules + a unified private Spec repository. In order to avoid the impact of one person’s work on the development environment of others, the development process of the entire group needs to be standardized.

Git-flow is the first recommended workflow for both the main repository and the submodule repository. Only the owner can make changes to the master branch of a repository. If other contributors want to make changes, they need to create a new branch (fork it on Github), make changes, and then send a Pull Request to the original repository. A Pull Request is a consolidated Request in which changes made by contributors can be seen and reviewed by the project owner and other maintainers to discuss changes together. When the project owner thinks the changes are OK, he can merge the Pull Request and merge the code into the main branch.

The process is completely distributed, meaning that multiple contributors can work on different branches at the same time, and eventually merge on the main branch to achieve parallel collaboration.

At the same time, in the Pull Request audit stage, in addition to manual audit code, Github also added support for continuous integration, which can check whether the Pull Request can pass the test, further ensuring the quality of the code.