A project from the initial rapid development online, to the middle business rapid development, and then to the late stable maintenance. In this process, with the increasing number of project developers, the business code will be bloated, and the code coupling between functions will gradually increase. At this time, in order to improve the code quality and maintainability, it is inevitable to carry out architecture reconstruction. Since the current business line is planning to do componentization related content, this paper analyzes excellent componentization landing plan in the industry, so as to find the landing plan suitable for my own business.

1. Component and modularization

componentization

A component is a single functional component. Like video components, payment components. During actual componentization, each component is a separate Module, and each Module can be run as a separate Application or as a separate Library.

modular

Modules refer to independent business modules, such as payment modules and login modules. In AndroidStudio, a Module also corresponds to a Module. Modularization is to divide the business into different Module modules, which call and communicate with each other through mutual dependence.

From the perspective of architecture, the core idea of both is to divide and conquer, both to improve the quality and maintainability of code, but the difference lies in the granularity of partition, module granularity is higher than component granularity, usually a module may contain multiple components.

Componentization is vertical stratification, modularization is horizontal partition.

Advantages of componentization

  1. Improve development efficiency: Reduce the interdependence between components through componentized decoupling, so that each component is in a highly cohesive and low-coupling state. Changes made to one component alone do not have a significant impact on the other components and improve productivity for both development and testing. At the same time, maintainability is also greatly improved.
  2. Functional reuse: Each individual component is a single function, and for line-of-business development teams, it is possible to develop functionality quickly by using components directly, while reducing repetitive development efforts.

2. Componentized cases

In this part, it mainly analyzes the componentization scheme shared by some excellent teams on the Internet.

2.1 Android componentization of Wechat Mall

The componentization scheme shared by Yousan micro-store introduces the background of the implementation of componentization scheme in detail. In the increasingly complex business modules, there is a lot of redundancy in the code, the gradual increase of packaging time and the mutual coupling between various business modules. The problems are:

  • Modules are just concepts of project structure (one module at a timeModule), there is no such thing as a module at the logical level
  • The module itself has no lifecycle control
  • Public service centralization, public logic parts are all inCommonIn the module
  • The service exposed by the module is unknowable and depends directly on the code logic inside the module
  • Modules cannot be packaged separately. Code changes to modules can only be seen after they are fully packaged

These problems are also the problems that many projects have to face when they reach a certain stage. In order to solve these problems, it is necessary to adjust and reconstruct the architecture and split the business modules in strict accordance with the strong requirements of componentization. Let’s take a look at how the Awesome team implements componentized solutions.

1. Module splitting and abstraction

Module functions are abstracted from base classes to form modular support components. This base Module provides the following functions:

  • Abstract the module itself as a container for some kind of business, that is, all business modules need to implement their own module classes, inherited from oursBaseModuleAnd, inAppRegistration in shell engineering;
  • Module objects followActivitySimilarly, you have the concept of a life cycle and need to deal with your own logic (registering services, initializing data, etc.) at different stages of the life cycle;
  • The module can register the realization of the exposed service. When registering the module, the service carried by the module will also be registered in the service center of the App.
2. Decentralization of public services

The Common business here refers to the Common module extracted from App. As the complexity of the project increases, this module looks like a big locker, and everyone fills a lot of business codes into it, resulting in the increase of code redundancy and maintenance difficulty of this module. The solution is:

  • Pulling common business modules up into business modules (so-called servitization of business modules);
  • Abstract the underlying component into a separate component;
  • Sink some base classes into the underlying core library that does not contain the business logic.
3. Servitization of service modules

In simple terms, the business is divided into multiple modules, and the interaction between modules is completed in the way of providing services to each other. Common basic ways are:

  • AModule direct dependencyBModule, directly calledBModule code logic;
  • willABThe common parts of the moduleCommonModule, by callingCommonModule code implementation dependencies;

In the good componentization, proposed through THE WAY of API implementation, each module through API exposure of internal data and services, so as to complete the communication. Common API implementations are:

  • Protocol, something like thatapp://order/detail/get? id=100Through theJSONData transfer, but the problem is high maintenance cost, service modification leads to no perception of referees;
  • Interface, through the exposed interface to complete the data interaction, the reference party needs to rely on the module, the dependency and publishing cost is high;

In this way, the stability and version control are better. For changes, the compilation process automatically verifies the impact of the change, and the problem of introducing dependencies and high publishing costs can be solved by the build tool (Gradle Plugin).

What the business implementation layer needs to do is to realize the business logic of its own module, realize the API interface provided by itself, and expose external services.

4. Base component abstraction

Many basic components are encapsulated in Common, such as account library, network library, image loading, etc., resulting in the bloated module. In this case, the module needs to be refactored:

  • The common base components are organized into a single abstraction layer, which defines a series of base component interfaces (image loading,WebContainers,JsBridgeCalls, accounts, etc.);
  • Putting a unified implementation component into another dependency can be done inAppThe business module itself can rely on abstraction alone.
5. Single/multi-module packing

This part is to implement the Module type through custom Gradle Plugin. In the development phase, it is the Application type, which can run debugging alone, and in the release phase, it is the Library type.

New architecture diagram:

2.2 Componentization practice of Zhihu Android client

In the article of The componentization practice of Zhihu Android client, it is introduced that with the continuous expansion of the project team, it is also faced with the problem of code coupling and the existing architecture is becoming more and more inadequate in the cooperation of r&d personnel in the development process. Let’s take a look at how zhihu team practices componentization.

1. Decouple service modules

The first step of componentization is to decouple redundant business logic, which mainly includes:

Public code handling

The underlying business logic is split into separate business components, and the Common module is downgraded to severely limit size growth.

Initialize the

Some components manage initialization task dependencies and priorities through a custom lifecycle framework when they need to initialize services at application startup.

routing

The interfaces use URLS to redirect, and a flexible and compact routing framework ZRouter is implemented internally to redirect routes.

interface

There will inevitably be calls between different businesses, and in order to avoid direct communication between components, interface dependencies are usually used. An Interface Provider is implemented to support Interface communication, which dynamically registers an Interface at runtime, as well as ServiceLoader support.

Component API module

Add an API module for each component with external exposure requirements. The API module only contains interfaces and events for the exposed Model and component communication. Components that need to reference these classes simply rely on the API. Such as:

  • Template: component code, which contains all the business code for this component;

  • Template-api: The Interface module of a component that is used to communicate with other components and contains only models, interfaces, and events without any business or logical code.

2. Component engineering semi-automatic disassembly

Decoupling components is a big headache, and if the dependencies are complex, it’s easy to get compiler errors all over the place and have to be moved around by humans. To solve this problem, Zhihu developed an auxiliary tool, RefactorMan: It can recursively parse out all source code references and references in the project, and will automatically analyze all unreasonable dependencies according to the preset rules. After the developer solves the unreasonable dependencies according to the prompts, the component can be moved out by one key, greatly reducing the workload of disassembly components.

3. Compile the complete package jointly

The directory of resources is integrated through sourceSet. SourceSet dependencies are used for compilation and Module dependencies are used for other times to ensure that each sub-service can run independently and only one component is released to the public.

New architecture diagram:

It consists of four levels:

  • Main project: Contains no business code except for some global configuration and main Activity.

  • Business components: The top level of the business, each representing a complete line of business, independent of each other.

  • Base components: The underlying business services that support the operation of the upper-layer business components.

  • Base SDK: Completely business-independent base code.

2.3 Componentization exploration and practice of iQiyi knowledge mobile terminal

Componentization is a necessary process for any App with complex business scenarios. With the separation and development of the company’s business lines, it is inevitable that the same business module will have multiple terminals and multiple sets of codes, resulting in great maintenance costs. Before implementing componentization, identify the business problem that componentization needs to solve, rather than componentization for its own sake.

When implementing componentization in iQiyi knowledge mobile terminal, the objectives of componentization are defined as follows:

  • Solve multi-terminal code maintenance problems

According to the business characteristics, components are divided horizontally and vertically, and the iterative requirements are accepted by components as a unit, and components are reused at each end.

  • Addresses cross-component invocation and inter-component routing

Services are divided more clearly, components are decoupled more thoroughly, and communication between components is more efficient. Original service modules are separated and integrated, and service boundaries between components are defined.

  • Improve development efficiency and facilitate development and debugging

Components can be compiled and debugged separately, allowing module developers to focus more on their module business.

  • Improve integration and test efficiency

You can use tools to quickly integrate and test components needed by each end project.

Based on the above four objectives, combined with its own business requirements, the new architecture is divided into basic components, functional components and business components.

The second part is about the two core technical practices of componentization: intercomponent interaction and intercomponent routing.

Intercomponent interaction

The difficulty of component interaction is to reduce component coupling, preferably to achieve a completely non-intrusive invocation. On the Android side, the ZRouter component is used for interaction between components. Each component provides a service interface service externally, and the implementation of the interface is handed to the corresponding component. During component initial registration, both the Service interface and the corresponding Service implementation are registered. When used by the business side, component functions need only be invoked through the Service interface. In this way, there is no direct dependency between components, realizing decoupling and isolation between components.

Intercomponent routing

In terms of the hop between components, the method of URL registration is used, and the timing of registration can be divided into static, dynamic and lazy loading. Lazy loading is to check whether THE URL and ClassName have been registered and bound when the hop method is called. If not, it will obtain from the module static information table and complete the registration and binding. Here, iQiyi team learned from the industry’s excellent componential ideas and developed a UIRouter for UI jump between components.

3. Realize componentization

3.1 Four steps to realize componentization

Through the analysis of some excellent cases above, when an organization carries out architecture reconstruction and adjustment, it is basically a long-accumulated problem that seriously affects the development efficiency. Therefore, the architecture needs to be reconstructed to improve development efficiency. Combined with the above cases, four steps are summarized to assist us in realizing a componentized architecture design.

1. Define the purpose of componentization

Any architectural refactoring or adjustment is intended to solve a specific problem. Before implementing componentization, it is important to identify the problem that needs to be solved in this architectural refactoring so that it can be targeted, rather than componentization for the sake of componentization.

2. Split services

Componentization has an important purpose to reduce coupling between code, so it needs to be split according to its own business. In the process of business splitting, it usually involves the processing of common code and the splitting of business modules.

3. Divide components

After services are split, they need to be grouped into a single component and classified. Components can be roughly classified into three categories: service components, functional components and basic components.

The business component

Business components correspond to specific business modules, such as home page, search, q&A.

Functional components

Functional components are usually components that have a complete base function, such as sharing, video, player, and so on. It is often referenced directly by business components to quickly implement specific functionality. Generally more stable.

Based on the component

An infrastructure component is a component that covers a number of infrastructure functions that are business-related. Such as network requests, logging frames, image loading. The base component is the most stable component at the bottom.

4. Technical selection

In the process of componentization, it is necessary to ensure that each Module component can run independently and participate in compilation, and at the same time, data interaction and page jump between components are involved. For example, the page jump implementation scheme includes: ARouter, CC, Componet, etc., need to choose specific scheme according to their own business.

3.2 Problems of componentization

Componentization achieves decoupling and isolates App running engineering from component engineering, which inevitably brings some problems that need to be solved.

  • Component debugging and compilation separately
  • Page redirection and routing
  • Component communication between modules
  • ApplicationThe management of
  • Resource conflict

About these problems have more mature solutions, recommended reading: Android componentization development ideas and practice, “Finally understand” series: Android componentization, comprehensive grasp!

4. The last

In this research, I read a lot of excellent practice articles, and I have a certain understanding of the whole practice of componentization. The architecture summary in one of the articles is very useful.

At the heart of any architecture is the issue of layering and communication. Layering is designed to decouple code from data processing (Model), UI display (View), and business processing (X). Communication is how layered modules interact with each other.

Reference article:

  • Has praised the micro mall Android componentization scheme
  • Componentization practice of Zhihu Android client
  • Iqiyi knowledge mobile terminal componentization exploration and practice