In the Android SDK article, we talked about modularization and componentization. Now let's talk about what's behind componentized development. Componentization was first applied in advertising SDKs, but it is also applicable to general application development. The following is very exciting, please be prepared. If you don't understand, please send a private message to communicate. This article is not recommended for novices. If you are new to Android development, please give up reading this article immediately. Modularity and componentization Modularity Componentization is not a new concept, and it has always been highly valued in all walks of life. As for when componentization was first proposed in the field of software engineering, it is no longer possible to trace it. However, it can be confirmed that componentization was first applied to server-side development. Later, under the guidance of this idea, front-end development and mobile development also developed their own development methods. Before understanding componentization, let's review the definition of modularity. Modular programming is a software design technique that emphasizes separating the functionality of a program into independent, interchangeable modules, such that each contains everything necessary to execute only one aspect of the desired functionality. Simply put, modularization is to split a program into independent modules according to its functions, so that each module only contains content related to its function. We are relatively familiar with modules, for example, the login function can be a module, the search function can be a module, and the car's transmitter can also be a module. Componentization Now let's take a look at "component-based development". Here we look at its definition: Component-based software engineering (CBSE), also known as component-based development (CBD), is a branch of software engineering that emphasizes the separation of concerns in respect of the wide-ranging functionality available throughout a given software system. It is a reuse-based approach to defining, implementing and composing loosely coupled independent components into systems. This practice aims to bring about an equally wide-ranging degree of benefits in both the short-term and the long-term for the software itself and for organizations that sponsor such software. In simple terms, componentization is to split a large software system into multiple independent components in the form of separation of concerns for the purpose of reusability, which has less coupling. It seems very abstract at first glance. I still don't understand it after talking so much. What is a component? A component can be a module, a web resource, or a software package. For example, a car engine is a module and a component. Or a calendar control in the front end is a module and a component. Modularity vs Componentization When you see this, you must be feeling a chill in your heart: Modularization? Componentization? What the hell is that? What's the difference? It is right to have this feeling. The essential idea of modularization and componentization is the same, both are "big to small", and the purpose of both is reuse and decoupling, but the names are different. If you have to say the difference, then you can think that modularization has a smaller granularity and focuses more on reuse, while componentization has a slightly larger granularity than modules and focuses more on business decoupling. Advantages and disadvantages of componentization The benefits of component-based development are obvious: the control strength at the system level is refined to the control strength at the component level, and the construction of a complex system is ultimately the result of component integration. Each component has its own independent version and can be independently compiled, tested, packaged and deployed. After the product is componentized, it can be configured and sold according to the needs in a complete sense. Users can choose which components to use, and the components can be flexibly assembled. Configuration management, development, testing, packaging, and release are fully controlled at the component level, which brings many benefits. For example, if a minor version of a component is upgraded and the interface provided to the outside world has not changed, other components do not need to be tested at all. However, component-based implementation places higher demands on developers and team managers. Compared with traditional methods, it is more difficult to manage and organize projects, and requires developers to have a deeper understanding of the business. Entering the Android project Why should we implement component-based development in Android? Why do we need to implement component development in Android? The fundamental reason is that the growth of business has increased the complexity of the project. In order to better adapt to team development and improve development efficiency, componentization is the general trend. In order to better help you understand the above sentence, I will start with the earliest Android project development method. Simple development model The so-called simple development model is the most basic development method. There is no so-called module or planning in the project. It is often seen in demos written by beginners in the learning stage or in the personal learning process. Its structure is roughly as follows: It is not difficult to find that there is often a lot of business logic in one interface, and the business logic is full of various network requests, data operations and other behaviors. There is no so-called module concept in the entire project. The basic unit of the project is not the module, but the method level. There is nothing much to say about this development model. We all experienced it in the early days, but now it is rarely seen except for very old projects and beginners' practice. Single Project Development Model This development model has a clear module division and presents a good structure through logical stratification. This model is the most familiar to us and is usually used for rapid development of early products when the team size is small. The structure of this development model is as follows: With the iteration of products, the business becomes more and more complex, which brings with it the extreme increase in the complexity of the project structure. At this time, we are faced with several problems:
In the face of these problems, we rethink componentization to see if it can solve the problems we encounter in Android project development. Main project multi-component development model With the idea of componentization, we extract the businesses in the business layer and encapsulate them into corresponding business components based on the "single project" model, extract the parts in the basic library and encapsulate them into basic components, and the main project is a runnable app, which serves as the entrance to each component (the main project is also called the shell program). These components are presented in the form of jar or aar. The main project uses the functions provided by the components in a dependent manner. (Note that this is an ideal structural diagram. In actual projects, business components will communicate with each other and will also have dependencies. We will discuss this below.) Both jar and aar are essentially libraries, and they cannot be run independently from the main project. When team members participate in the development of a project together, each member's development equipment must have at least the main project and the components they are responsible for. It is not difficult to see that by componentizing the project, each member can focus on the business they are responsible for without affecting other businesses. At the same time, with the help of stable basic components, code defects can be greatly reduced, so the entire team can efficiently advance the development progress in a parallel development manner. Moreover, componentization allows us to assemble products flexibly. All we have to do is configure the corresponding components according to the needs and finally produce the products we want. It is a bit like playing with building blocks. By placing them in different ways, we can get the shape we want. For testers, it can effectively reduce the testing time: the original business does not need to be functionally tested again, and you can focus on testing the changed business and the final integration test. So far, we have effectively solved some problems in the "single project development model", which is enough for most teams, but there are still some points that can be improved in this model: every time a dependent package is modified, it is necessary to recompile and generate lib or aar. For example, Xiaoyan took over a project with more than 40 components. When all the components were finally integrated, Xiaoyan found that there was a problem with one of the components. In order to locate and modify the problem in the component, Xiaoyan kept debugging the component. Because under this model, the component cannot be separated from the main project, it means that after each modification, Xiaoyan has to wait in a long compilation process. What's worse is that there are only 5 hours left before the launch, and each compilation takes 10 minutes. In order to fix this bug, it has been compiled 20 times. Well... There is nothing to do. I can submit my resignation report. How to solve the problem that every time a component is modified, it must be compiled together with the main project? Let's see how the main project multi-sub-project development model solves this problem. Main project multiple sub-project development model This development model is an improvement on the "main project multi-component" development model. Its structure diagram is as follows: It is not difficult to find that this development model is no different from the "main project with multiple components" in structure. The only difference is that all business components are no longer mouble but as a sub-project. The basic components can be moudle or sub-project. The sub-project is different from the main project: in Debug mode, it is an app and can be developed, run and debugged independently; in Release mode, it is a library and is relied on by the main project to provide services to the main project. In this model, what will Xiaoyan do when she finds a defect in a business component? For example, if there is a problem with basic component 2, since basic component 2 can run independently as an app in Debug mode, it is easy to modify and debug the module separately. After the modification, you only need to recompile the entire project once. It is not difficult to find that this development model effectively reduces the number of full compilations, reduces compilation time, and facilitates developers to develop and debug. For testers, functional testing can be done in advance and can be involved in the development process in a timely manner to minimize risks. So far, we have explained the convenience brought to us by component-based development at a theoretical level. Empty words are not convincing. In the following section, we will talk about how to implement component-based development in Android. Problems encountered during componentization Component Division The first thing to do in componentization is to divide components. There is no exact standard for how to divide. I suggest that when implementing componentization in the early stage, it can be done at a "coarse" granularity. The advantage of this is that it can be further divided later as the business is understood, without too much cost. Of course, I suggest that the work of dividing components should be negotiated and customized by team architecture personnel and business personnel. Sub-project working mode switching In the "Main Project Multi-Sub-Project Model", we mentioned that the sub-project runs as a separate Application in Debug mode and runs as a Library in Release mode. How to dynamically change the running mode of the sub-project? We all know that in a project built with Gradle, apply plugin: 'com.android.application' is used to identify the application, and apply plugin: 'com.android.library' is used to identify the library. Therefore, we can modify the working mode of the sub-project by judging the parameters in the build environment during compilation. Add the following script snippet to the head of the gradle script of the sub-project: In addition, the AndroidManifest.xml of the sub-project is different in different running modes, and you need to provide your own AndroidManifest.xml file for each sub-project: create two directories under the src directory of the sub-project (create in other locations) to store different AndroidManifest.xml files. For example, I created debug and release directories here. Next, you also need to formulate the construction method in the gradle construction script of the sub-project: Component communication and component dependency In the ideal model of "main project with multiple components", business components do not communicate or depend on each other, but the reality is the opposite, as shown in the following figure: Here, business component 1 and business component 3 provide services to business component 2 at the same time, that is, business component 2 needs to rely on business component 3 and business component 1 at the same time. Now let's look at a worse situation: From this point of view, when the business is complex, the interdependence between components will bring two problems: Repeated dependency: For example, business component 3 may depend on business component 1, and business component 2 may depend on business component 3 and business component 1, which results in repeated dependency on business component 1. Subsystem communication cannot rely on traditional display intent. In this model, using display intent will lead to high coupling of components. For example, business component 2 depends on business component 1 and communicates through display intent. Once business component 1 is no longer used, errors will occur in business component 2 where display intent is used, which obviously runs counter to the purpose of our componentization. Solving component communication Let's first solve the problem of business component communication. When we saw the complex component communication diagram above, it was not difficult for us to think of the operating system introducing a bus mechanism to solve the device mounting problem. Similarly, borrowing the concept of the bus, we added a "component bus" to the project for communication between different components. At this time, the structure is as follows: All business components mounted on the component bus can achieve two-way communication. The communication protocol is similar to the HTTP communication protocol, that is, it is based on the URL. As for the implementation method, one can be based on the implicit intent provided by the system, and the other is to completely implement the component bus by yourself. This article does not intend to explain it in detail. Resolving duplicate dependencies For the Library output in aar format, gradle will keep the latest version of aar for us when building the project. In other words, if the dependencies are provided to the main project in aar format, there will be no problem of duplicate dependencies. If the dependencies are provided directly in the form of a project, duplicate code will appear in the packaging process. There are currently two ways to solve the problem of duplicate project dependencies: 1. For libraries or jar packages of pure code projects, compile is only executed in the final project, and the provider method is used in other cases; 2. Detect dependent packages during compilation, and no longer rely on the already dependent packages Resource ID conflict When merging multiple components into the main project, resource reference conflicts may occur. The easiest way is to avoid it by implementing a convention on resource prefixes (resourcePrefix), which needs to be configured in the component's gradle script: Once resourcePrefix is configured, all resources must start with the prefix. For example, if the prefix is moudle_prefix, all resource names must be prefixed with the prefix, such as moudle_prefix_btn_save. Component Context Finally, you need to pay attention to whether the required Context is what you want in Debug mode and Release mode to avoid forced conversion exceptions. Conclusion I first came into contact with the concept of componentization when I was working on advertising SDK. Recently, I have made some summaries, so I wrote this article about "componentized development". In addition, componentized development is not a silver bullet and cannot completely solve the current complex business situation. Before implementing and improving the project, you must consider it more. Please look forward to the second article, where we will introduce how to implement componentization in the project. |
<<: How to write a beautiful DSL using Objective-C
>>: Android quick release project to jcenter
This year, the mini program war between BAT and B...
Since the birth of the first video website in Chi...
Have you ever been overwhelmed by the "terri...
[[127291]] The suspicion of counterfeit goods in ...
What is the price for joining the Dehong Lottery ...
The main point we will talk about today is relati...
gossip White kidney beans can block carbon water ...
In community operations , building a good persona...
In January 2025, a research team from the Institu...
How to attract traffic through Kuaishou ? I think...
What is biocomputing? If a scientist tells you th...
Icon design requires proficiency in the use of so...
Preface Artificial Intelligence (AI) is a collect...
As an operator, I have always been paying attenti...
Recently, it was reported that Snapchat’s daily v...