2

I. Introduction

With the rapid development of business, the current Internet apps are getting bigger and bigger. In order to improve team development efficiency, modular development has become the mainstream development model. Just recently completed the work of modular transformation of the Vivo official website App business, so this article will give a comprehensive introduction to the modular development model and summarize the modular transformation experience to help brother projects avoid pits.

2. What is modular development

First of all, we clarify two concepts. There are currently two models for Android client development: single project development model and modular development model .

  • Single project development model: has less business and fewer developers in the early days. One App corresponds to one code project, and all codes are concentrated in one module of this project.
  • Modular development mode: simply to divide an App into multiple independent code modules according to business functions, and the entire App is integrated by these independent modules.

Before talking about modular development, we first define two concepts: components and modules.

  • component: refers to a single functional component, such as login component and sharing component;
  • Module refers to services and functions with relatively independent functions and clear boundaries. If the word module appears separately in this article, it generally means that. In a narrow sense, it refers to a business module, which corresponds to a product business, such as a mall module and a community module.

The essential ideas of modules and components are the same, both for business decoupling and code reuse, and the granularity of components is finer than that of modules. When dividing, the module is business-oriented, divided into independent business modules, and the component is function-oriented, divided into independent functional components.

Modular development mode is divided into two specific development modes: single project multi-module mode and multi-project mode .

single project multi-module mode :

All the codes are located in a project, and the module exists in the form of a module of AndroidStudio, which is composed of an App module and multiple modules. As shown in the figure:

Multi-engineering mode :

Each module code is located in a project, and the entire project consists of a main module project and multiple sub-module projects. Among them, the main module project has only one App module, which is used to integrate sub-modules for overall debugging and packaging. The sub-module project consists of an App module and a Library module. The App module contains the debugging and test code, and the Library module contains the business and function code. As shown below:

Let's compare the advantages and disadvantages of the single-project multi-module mode and the multi-project mode:

Through the above comparison, we can see that the multi-engineering model has obvious advantages in code management, development and debugging, business parallelism, etc. It is very suitable for apps with many business lines, large engineering, and many developers like the vivo official website, so vivo This mode is currently used on the official website. When explaining modular development in this article, it generally refers to the multi-engineering model.

The single-project multi-module mode is more suitable for projects with few developers and low business parallelism. However, the multi-project mode also has : there are more code warehouses, and multiple projects need to be opened during development. . For these two shortcomings, we also have solutions.

code warehouse problems

It is required that the granularity of splitting modules should not be too fine. When a module expands to a certain extent, we will split it again to maintain a balance between the efficiency improvement brought by modularization and the increase in code warehouse management costs.

To open multiple project development issues

We have developed a code management tool based on the Gradle plug-in, which can be easily switched through code dependent submodules or maven dependent submodules. The actual development experience is the same as the single project multi-module mode, as shown in the figure below;

The process of modular development is also very simple:

  • In the early stage of the version, each module is under the responsibility of a specific developer, and each sub-module is independently developed and debugged;
  • After the sub-module development is completed, it is integrated into the main module project for overall debugging;
  • After successful integration debugging, enter the test.

Three, modular development

3.1 Why do we do modular development?

Here we talk about some of the pain points of a single project development model.

team collaboration efficiency

  • In the early stage of the project, there is little business and fewer developers. With business development and team expansion, because the code is in the same project, although the functions developed by each person are different, they often modify the code in the same place. At this time, relevant development is required. Personnel communicate and coordinate to meet their respective needs and increase communication costs;
  • When submitting the code, the code conflicts should also be communicated how to merge (otherwise it may cause problems), increasing the cost of the code;
  • Parallel version development is not possible, or parallel development reluctantly, at the cost of large differences in code branches and difficulty in merging code.

Code maintenance cost is high

  • In the single engineering mode, because the codes are all together, the code coupling is serious. There are many coupling codes between business and business, business and public components. It can be said that you have me in you, and you are in me. Any modification may be affected. Move your whole body, with the iteration of the version, the maintenance cost will become higher and higher.

development and debugging efficiency

  • Any modification, even one character, needs to compile the entire project code. With more and more codes, compilation becomes slower and slower, which greatly affects development efficiency.

3.2 How to solve the problem

After talking about the pain points of the single project development model, let's take a look at how the modular development model can solve these problems.

Improve team collaboration efficiency

  • In the modular development mode, the code is split into independent modules according to business and function. The code is located in different code warehouses. When the versions are developed in parallel, each business line is only developed in their own module code warehouses, and does not interfere with each other. Responsible for the modified code;
  • Testers only need to focus on testing the modified functional modules, without all regression testing;
  • The product level is required to have a clear business division, and the versions developed in parallel must be different business modules.

Reduce code maintenance costs

  • Modular development will have clear boundaries for business modules. The codes between modules are independent of each other. Modifications to one business module will not affect other modules;
  • Of course, this also puts forward requirements for developers, and the module code needs to be highly cohesive.

Improve compilation speed

  • During the development phase, you only need to develop and debug in one of your own code warehouses, without the need to integrate a complete App, and the amount of compiled code is very small;
  • In the integrated debugging stage, the developed code warehouse is dependent on code, and other code warehouses that do not involve modification are dependent on aar, and the overall amount of compiled code is relatively small.

Of course, modular development is not to say that all benefits, there are also some disadvantages, such as:

1) Don’t develop modular apps for apps with a single business and few developers, as that will lead to more maintenance costs;

2) Modular development will bring more repetitive codes;

3) The more modules that are split, the more code warehouses that need to be maintained, and the maintenance cost will also increase. It is necessary to balance the split granularity.

To sum up, modular development is like we manage books. When there are only a few books at the beginning, just pile on the desk. With more and more books, when there are dozens or hundreds of books, we need a bookcase, placed in different grids according to the category. Comparing the iterative process of App, at the beginning, there are few businesses and the single engineering mode is the most efficient. As business develops, we need to split different modules according to the business.

All these purposes are to facilitate management and efficient search.

Four, modular architecture design

The idea of ​​modular architecture design, we summarized as two dimensions of vertical and horizontal . In the vertical direction, it is layered according to the degree of closeness with the business, and in the horizontal direction, the modules are split according to the boundary of the business or function.

The figure below shows the overall architecture of our App.

4.1 Vertical stratification

First look at the vertical layering. According to the degree of business coupling, from top to bottom, it is the business layer, the component layer, and the basic framework layer.

  • Business layer: Located at the top of the architecture, it is divided according to business modules (such as shopping malls, communities, etc.), corresponding to product business;
  • Component layer: Some basic functions of App (such as login, self-upgrade) and business common components (such as sharing, address management), provide certain reuse capabilities;
  • Basic framework layer: Basic components (such as network requests, image loading) that are completely unrelated to the business and provide complete reuse capabilities.

From the top to the bottom of the framework level, the business relevance is getting lower and lower, the code stability is getting higher and higher, and the code storage requirements are becoming more and more stringent (you can consider tightening code permissions, the lower the code, the higher the storage requirements) .

4.2 Horizontal sub-module

  • On each layer, separate modules are split according to certain granularity and boundaries. For example, the business layer is split according to product business. The component layer is split according to functions.
  • Large modules can be independent of a code warehouse (such as shopping malls, communities), and small modules are composed of multiple modules to form a code warehouse (for example, the dotted line in the above figure indicates that multiple modules are located in one warehouse).
  • Modules should be highly cohesive and low-coupling, and minimize dependence on other modules.

The object-oriented design principle emphasizes that combination is better than inheritance, parallel modules correspond to the combination relationship, and upper and lower modules correspond to the inheritance relationship. The advantage of combination is that it has good encapsulation and achieves a high cohesion effect. Therefore, when considering the hierarchy of the framework, we are more inclined to the former, that is, the split modules are as parallel as possible to reduce the hierarchy.

is that the modification of the lower-level code warehouse will affect more upper-level code warehouses, and the more levels there are, the lower the degree of parallel development and parallel compilation.

module dependency rule:

  • Only the upper-level code warehouse can rely on the lower-level code warehouse, and cannot rely on reverse, otherwise the problem of circular dependency may occur;
  • Code warehouses in the same layer cannot depend on each other to ensure complete decoupling between modules.

Five, what problems need to be solved in modular development

5.1 How to independently develop and debug business modules?

Method 1: Each project has an App module and a Library module, and use the code in the App module to debug the business function code in the Library module.

Method 2: Use code management tools to integrate into the main project for debugging. The code warehouse under development is dependent on code, and other modules are dependent on aar.

5.2 How to realize page jump between parallel modules, including Activity jump and Fragment acquisition?

According to the principle of module dependence, mutual dependence between parallel modules is prohibited. Although implicit Intent can solve this problem, it needs to be managed centrally through Manifest, and collaborative development is more troublesome, so we chose the routing framework Arouter. Activity jump and Fragment acquisition can be perfectly supported. In addition, the interceptor function of Arouter is also very powerful, such as the login function in the process of handling the jump.

5.3 How to call methods between parallel modules?

Arouter service reference- https://github.com/alibaba/ARouter.

5.4 How to transfer data and drive events between parallel modules?

Both Arouter service and EventBus can do it, depending on the specific situation.

Sixth, how to implement modular transformation of old projects

Modularization of old projects requires patience and care, and it is a gradual process.

Let's take a look at the modular evolution history of our project, from a single project to a spindle-shaped multi-project modular model. The figure below shows the four stages of evolution, from the initial single App project to the current 4-layer multi-warehouse structure.

Note: Each square in this figure represents a code warehouse, and the upper code warehouse depends on the lower code warehouse.

Early projects all adopted a single engineering model. With the development of business and the expansion of personnel, it is bound to be faced with the process of modular transformation of old projects. But in the process of modular transformation, we will face many problems, such as:

  • The code logic is complex, lack of documentation, comments, dare not easily modify, afraid of causing functional abnormalities;
  • Code coupling is serious, you are in me and you are in me, it is difficult to split and refactor if you are involved in the whole body;
  • Business version iteration and modular transformation are parallel, and code conflicts are frequent, which affects project progress;

I believe that those who do modularization will encounter these problems, but modular transformation is imperative. We cannot suspend business iteration and invest all manpower in modularization. First, the business side cannot agree, and secondly, the investment is too much. Many people will bring more code conflicts.

Therefore, a feasible transformation idea is needed. We conclude that is divided from top to bottom, and then .

top-down

  • Divide the modules layer by layer from the whole to the details, first divide the business line, then divide the business module, and then divide the functional components in the business module, and finally form a tree diagram.

bottom-up

  • When we have clearly divided the modules and sorted out the dependencies, we need to split from the bottom up, starting with the leaf modules. When we split all the leaf modules, the branch modules can be easily split, and finally completed Splitting of the main part.
  • In addition, the entire modularization work needs to be coordinated and planned by a dedicated person to complete the main transformation work, but if there are complex functions, it can also be requested to the person in charge of each module to assist in the completion of the transformation.

Let's talk about some of our experience in the way of modularization and upgrading. is a gradual progress, each breaking .

6.1 Sorting out business modules

This step is to divide the modules from top to bottom, that is, to determine the sub-module code bins. An old project inevitably goes through many years of iteration. After many people develop it, you don’t have to be familiar with all the codes, but you must have a basic understanding of all business functions, and on this basis, comprehensive product and technical planning for preliminary module division .

At this time, the division of modules can be more coarse-grained, for example, based on business lines or large business modules, but the boundaries should be clear. An App generally has multiple business lines, and each business line has multiple business modules. At this time, we do not need to sort out the business too finely, just keep two layers, otherwise excessive split will greatly increase the implementation. Difficulty.

6.2 Extract common components

After dividing the modules, it will be very difficult to split the business modules directly according to this, and there will be a lot of duplicate codes, because many common components are dependent on each business module (such as network requests, image loading, sharing ,Log in). Therefore, the first step of modularization is to extract and sink these common components.

In this step, we will encounter two types of public components when extracting public components, one is the basic framework components that are completely business-independent (such as network requests, image loading), and the other is business-related public business components (such as sharing, Log in).

These two types of public components can be divided into two layers to facilitate the subsequent formation of the overall framework. For example, our lib warehouse stores basic framework components and core warehouse stores business common components. As shown below

6.3 Business module split

After extracting the common components, we have to prepare to split the business modules. This step takes the longest time, but it is also the most effective, because we can develop multiple services in parallel after the disassembly.

Determine the business module to be split (such as the mall business in the figure below), first pull out the code warehouse, and develop new functions directly in the new warehouse.

How to split and migrate the old functions? It is impossible for us to become fat guys with one bite. It is too difficult to split all big business modules at once. At this time, we need to further sort out the internal business modules and find out all the sub-functional modules (such as payment, shopping, business details in the mall business).

According to the degree of independence of the functional modules, from easy to difficult to split one by one, for example, the payment order function is relatively independent, then first split the code of the order function into a new warehouse.

6.4 Splitting of functional modules

When splitting specific functions, we still use the logic of Top-Down to implement. First, find the entry class (such as Activity) and migrate to the new code warehouse. At this time, you will find that it is full of red at a glance, like Bring out a lot of roots like weeding. Dependent layouts, resources, auxiliary classes, etc. cannot be found. We solve them one by one in order from easy to difficult. The dependency problems that need to be solved are as follows:

1) Simple dependencies, such as strings and pictures.

This type is the easiest to solve, just move the resources over.

2) More complex dependencies, such as layout files and drawables.

This kind of solution is relatively easy to solve, and it can be migrated step by step. For example, the layout depends on various drawables, strings, images, and drawables depend on other drawables, which can be solved by migrating one by one from top to bottom.

3) More complex dependencies, similar to A->B->C->D.

There are two solutions to this type of dependency. If the dependent function has no business features or simply encapsulates the system API, then you can consider copying it directly; if the dependent code is shared by multiple functional modules or needs to be maintained by multiple functional modules Consistent, you can consider extracting the function code and sinking it to the next level of code warehouse.

4) Temporarily difficult dependence.

You can temporarily comment it out to ensure normal operation, and then clarify the logic before deciding whether to decouple or refactor. It is very important to cut the dependency chain, otherwise you may not be able to persist.

6.5 Code decoupling

Here are some commonly used code decoupling methods:

Common code extraction sinking

For example: basic components (eg. network request framework), each module needs to maintain the same functional code (eg. adaptation of OS dynamics);

simple code copy

For example, the simple packaging system api (eg. get packageName), the custom view for the function module's own use (eg. prompt pop-up window);

Three tools

Arouter routing, Arouter service, EventBus can meet various decoupling scenarios.

6.6 Coexistence of New and Old Code

Modularization of old projects is a long-term process, and the coexistence of new and old codes is also a long-term process. After the above transformation, a functional module can be independent, because we are all split from the old App project, so the App project can run normally after relying on the new warehouse. When we continue to separate independent modules from the old project, the old project only needs to retain some entry functions as the main project of the integrated sub-module.

Seven, summary

This article introduces the modularization practices of mobile application clients from several aspects such as modularization concept , modular architecture design and old project how to implement modularization reform Of course, the modularization work is far more than that, but also includes module aar management, continuous integration, testing, modular code management, version iteration process, etc. This article will not repeat them one by one, I hope this article can provide for projects that are ready to do modular development help.

Author: vivo Internet Client Team-Wang Zhenyu

vivo互联网技术
3.3k 声望10.2k 粉丝