Platform reuse of Meituan Takeout mainly refers to multi-terminal code reuse. As described in the promotion, support and thinking article of Meituan Takeout iOS multi-terminal reuse, multi-terminal includes two meanings: The first is multiple portals for the same business, which means that Meituan takeout business needs to be launched simultaneously on Meituan Takeout App (hereinafter referred to as takeout App) and Meituan App takeout channel (hereinafter referred to as Takeout channel). The other refers to the various business lines on the platform. The different business lines of Meituan Takeout rely on basic services such as login and positioning.
Multiple portals and lines of business bring great challenges to the platform reuse of Meituan Takeout. This problem was also mentioned in our previous blog “Evolution Practice of Meituan Takeout’s Android Platform Architecture” (hereinafter referred to as “Evolution Practice of Architecture”). Based on the chapter “code reuse”, The challenges of platform reuse and corresponding solutions are further introduced.
Meituan takeout platform reuse background
The takeout channel services of Meituan App and Meituan App are basically the same, but due to historical reasons, the codes at the two ends differ greatly. As a result, the same sub-business needs need to be realized at the other end after one end is online, which is a serious waste of development resources. In the paper “Architecture Evolution Practice”, the platform architecture of Meituan Takeout Android client is divided into platform layer, business layer and host layer. We hope to realize multi-terminal reuse of platform layer and business layer in the platform architecture, so as to save sub-business requirement development resources and realize multi-terminal deployment.
The difficulties in summary
Although the services at both ends are basically the same, there are still differences in UI, basic services and requirements. These differences exist in each module of platform layer and business layer in meituan takeout platform architecture, which brings great challenges to platform reuse. We summarized the differences between the two codes, mainly including the following aspects:
- Differences in basic services: Including differences in basic activities, network libraries, image libraries, and other underlying libraries.
- Component implementation differences: including differences in basic data Model, drop-down refresh, page jump and other basic components.
- Page differences: include differences in UI, interaction, service, and version release time between the two ends.
In the early exploration
In the early stage, we tried to bypass the above differences through some design schemes, so as to achieve code reuse at both ends. We chose the secondary channel page (hereinafter referred to as King Kong Page) to try the scheme, and the design is as follows:
KingKongInjector is a collection of interfaces for the difference between two ends, including page jump (difference between two ends), page refresh interval, default resources, etc. Corresponding interfaces have been implemented for WMKingKongInjector and MTKingKongInjector in takeout App and takeout channel respectively.
NetworkController uses Retrofit to implement a unified network request encapsulation. PageListController is used to handle the logic of page-loading of lists and exceptions such as page blank and network load failure.
In the king Kong page design scheme, we use the “proxy + inheritance” way, to achieve the use of a unified network library to achieve the network request, define a unified basic data Model, unified part of the basic services and basic data. The difference of the base Acitivity at both ends was screened by KingKongDelegate, and the difference part at both ends was treated by KingKongInjector. However, we found the following problems in this design scheme:
- While this resolves the differences between the network library and images, it does not mask the differences between the underlying activities at both ends.
- KingKongInjector has provided a way to deal with the differences between the two ends, but KingKongInjector has a lot of unrelated method sets and it is difficult to control its boundaries. In addition, KingKongInjector has to be called by multiple submodules, which makes KingKongInjector difficult to manage.
- As the models at both ends are different, it is necessary to realize the unified Model used by this module, but it is not unified with the Model with the same meaning used by other pages.
Platform reuse scheme design
Through the preliminary summary of code reuse attempts, we concluded that platform reuse needs to consider four things:
- Differentiated unified management.
- Reuse of underlying services.
- Reuse of underlying components.
- Reuse of pages.
The overall design
On the basis of realizing the platform architecture, through continuous exploration, we finally formed a platform reuse design suitable for takeaway business: the whole is divided into basic service layer – basic component layer – business layer – host layer. The design drawing is as follows:
- Basic service layer: includes multi-terminal unified basic services and different basic services, among which unified basic services include network library, picture library, statistics, monitoring and so on. As for the differences between login, sharing and positioning between takeout App and takeout channel, we shield the differences between the two ends through abstract service layer.
- Basic component layer: including the unified Model, buried point, pull-down refresh, permissions, Toast, A/B test, Utils and other basic components reused at both ends.
- Business layer: includes specific business modules of takeout, which can be divided into list page module (such as home page, King Kong page, etc.), business module (such as business page, commodity details page, etc.) and order module (such as single page, order status page, etc.). The characteristics of these service modules are: the possibility of reuse between modules is small, but the possibility of reuse within modules is large.
- Host layer: Mainly initialization of services, such as Application initialization, DEX loading, and initialization of various other necessary components.
The hierarchical architecture can achieve the separation of responsibilities between the functions of each layer, and at the same time, we require that the upper layer is not aware of the multiple differences of the lower layer. By partitioning components between layers, we also require that the caller is not aware of the component’s multiterminal differences. Such a design can make the overall architecture clearer, improve the reuse rate, and not affect the complexity and flexibility of the architecture.
Differentiated management
Compared with common services, the biggest challenge for services requiring multi-terminal reuse lies in differentiated management. Firstly, the innate conditions of multi-terminal determine the difference of multi-terminal multiplexing services. Secondly, multi-terminal reuse services have personalized requirements. In the differentiated management scheme of multi-terminal reuse, we summarize the following two schemes:
- Differential branch management scheme.
- Pins Project +Flavor management scheme.
Differential branch management
Branch management is usually applied to the scenario where multiple requirements are online at one end and need to be followed up at a certain time node at the other end, as shown in the following figure:
- If there are too many differences between the two ends of the demand, there will be many branches, resulting in branch management difficulties.
- Fine-grained differentiation management, such as differentiation within modules, is not supported.
Differentiated management of Pins Project +Flavor
In the section “Configuring and Building Variants” on the Official website of Android, it is introduced that Product Flavor (Flavor for short) can be used to manage the full version and demo version differently. You can configure Gradle to generate different APK versions based on different flavors. Therefore, Flavor is used to achieve differentiated management within modules, as shown in the following figure:
You can also configure Flavor to manage requirements in different versions on both ends, as shown in the following figure:
Based on the two different code implementations, we choose Flavor to achieve code differentiation management. Its advantages are as follows:
- A functional module only needs to maintain one set of code.
- Differential codes are implemented in different flavors of the service library, facilitating the tracing of code implementation history and comparison of differential implementation.
- For the upper layer, only different Flavor versions of the underlying code will be relied on; The lower layer exposes the interface to the upper layer basically the same, the upper layer does not care about the difference between the lower layer implementation.
- The requirement version difference only needs to be implemented in the corresponding Flavor on the online end, and then moved to the shared SourceSet to reuse the required code.
From the perspective of Android engineering structure, using Flavor can only be reused within modules, but module granularity reuse is too restrictive for differentiated management. This means that different codes of different modules in the same module exist in the corresponding Flavor directory, or each submodule needs to be created into a different module. In this way, code management is very inconvenient. An important concept called Pins project is mentioned in the paper “Practice of Wechat Android Modular Architecture Reconstruction”. Pins Project can construct a complete multi-sub-engineering structure within module. We reduced the differentiated snap-in from Module to Pins project by creatively using Pins Project +Flavor. The Pins project can be defined down to the smallest business unit, such as a Java file. The overall design is as follows:
productFlavors {
wm {}
mt {}
}
Copy the code
Then using the Pins project structure, each sub-business is treated as a Pins project and Gradle configuration is implemented as follows:
Through the differentiated management method of Pins Project +Flavor, we not only realized the differentiated management at the demand level, but also realized the differentiated management of functions within the module. At the same time, Pins project better controls the code granularity and code boundary, and also controls the differential code in a smaller granularity than Module.
Reuse of underlying services
For an App, the importance of basic services is self-evident, so in platform reuse, basic services are often the most different. As basic services are widely used, if the differences of basic services cannot be effectively handled and the differences are perceived by the upper layer, the coupling between architectural layers will increase, and the difficulty of the upper layer to implement services will also increase. Here is an example we encountered in practice to illustrate our main solution.
In the early exploration section, we mentioned that the king Kong page uses proxy classes to implement Activity lifecycle distribution due to the differences in the base activities at both ends. By using a unified interface and Flavor, we can unify the basic Activity components on both ends, as shown in the figure below:
Some common basic components are widely used. If they are not unified or differ greatly, the code implementation of the business layer will differ greatly, which is not conducive to code reuse. So the strategy we adopt is that the takeout App looks like the takeout channel. Before code reuse, the main network library used by takeout App is Volley, which is uniformly switched to MTRetrofit used by takeout channel. The image library used by takeout is Fresco, and the unified switch to takeout channel is MTPicasso; Other unified components also include dynamic loading framework, WebView loading component, network monitoring Cat, online monitoring Holmes, log retrieval Logan and traffic limiting degradation, etc. When codes at both ends are reused, the ability to repair problems and monitor data is unified.
For general basic services such as login and positioning, our principle is to unify as much as possible, so as to effectively reduce the multi-terminal maintenance costs brought by multi-terminal reuse and turn multiple services into one. For services that cannot be unified, a unified service interface can be abstracts so that the upper layer does not perceive the difference, thus reducing the reuse cost.
Component reuse
Componentization can greatly improve the reuse rate of an App. The same is true for platform-based reuse businesses. The same functionality is often used across multiple modules, such as drop-down refresh, paging load, buried points, styles, and so on. Separating these commonly used functions into components that can be invoked by the upper business layer can greatly improve reuse. It can be said that componentization is one of the necessary conditions for platform reuse.
Faced with the complex and numerous business functions of takeout App, the basic principle that a function can be divided into components is the common business function or behavioral function of different businesses in different business libraries. The extracted components are then divided into base common components, base business components, and UI common components based on the proximity of dependencies in the business implementation, top-down dependencies.
Basic generic components are those that do not vary much and are irrelevant to the business, such as the page load pull-down refresh component (P_refresh), logging related component (P_log), and exception exception component (p_exception). Basic business components refer to business-based components: review common component (P_UGC), buried component (P_Judas), search common component (P_search), red envelope common component (P_Coupon), etc. UI common components refer to common View or UI style components, common components associated with View (p_widget), and common components associated with UI style (p_theme).
What about the differences between the multiple ends of the extracted base component? For example, for the bottom of the bag component, yellow is the main tone of the takeout pocket pattern, while green pellets are the main tone of the takeout channel, as shown in the figure:
Page reuse
For both ends of the same page, most of the functional modules are reusable, but there are inconsistent functional modules. Take the home page of takeout App and Meituan takeout channel as an example. The middle flow area and other businesses are basically the same, but the style function of the top navigation bar and the layout of the middle flow area are different at both ends, as shown below:
Shield
Taking the home page as an example, the Block reuse architecture of the home page is shown in the following figure. The UI display, data, and functions of the navigation bar in the head of the home page on both ends are different. The entire function of the navigation bar is implemented with a Flavor on both ends. Although the overall UI layout of the traffic area in the middle of the merchant list is different, the single function Block business logic and the whole data are the same, and the services in the traffic area in the middle continue to be blocked. The same functions at both ends of the merchant list item below are implemented using a public Block. Based on the realization of each unit Block, the home page at both ends is constructed into the home page Fragment.
Summary and Outlook
Meituan takeout business needs to be deployed on both the takeout platform and Meituan platform at the same time, so the problem of platform reuse occurs in the process of meituan takeout platform architecture. And how to achieve platform reuse? I think you need to think of different granularity: base services, components, pages. For basic services, we need to unify as much as possible, and abstract the service layer if not. At the component level, you need to slice and layer dependencies. Page reuse, the most important is page modularization and page module responsibility separation. The biggest difficulty of platform reuse lies in difference management and shielding. This paper proposes the scheme of Pins project +Flavor, which can effectively solve the management of differential codes. At the same time, using the layered strategy, each layer handles its own differences, so that the upper layer does not care about the differences of the lower layer. Platform-based reuse can not only pursue reuse rate, but also take into account the personalization of the end.
So far, we have realized the code reuse of most takeout apps and takeout channels, with the overall code reuse rate reaching 88.35% and the human efficiency increasing by more than 70%. In the future, we may reuse codes on the takeout platform, Meituan platform and Dianping platform, and the scene will be more complicated. Of course, when we do platform reuse, we need to evaluate the ratio of “cost savings” from reuse to “cost increases” for reuse. In addition, the perspective of platform reuse should not be limited to the reuse of business pages, but also for monitoring, testing, research and development tools, operation and maintenance tools, which is the core value of the concept of platform reuse.
The resources
- Evolution practice of Meituan Waimai’s Android platform architecture
- Promotion, support and thinking of Meituan Takeout iOS multi-terminal reuse
- Practice of wechat Android modular architecture reconstruction
- Configuration build variant
- Shield – Open source modular development framework for mobile pages
Author’s brief introduction
Xiao Fei, technical expert of Meituan Dianping. In 2015, he joined Meituan Dianping, one of the early developers of Take-out Android. Currently, I am responsible for takeout Android App, mainly responsible for version management and business architecture.
Jin Guang, Senior engineer of Meituan Dianping. Joined Meituan-Dianping in 2017, mainly responsible for code reuse and platform transformation of food delivery.
Wang Fang is a senior engineer at Meituan Dianping. In 2017, I joined Meituan Dianping and was mainly responsible for related page businesses such as merchant list page.
recruitment
Meituan takeout is looking for senior/senior engineers and technical experts in Android, iOS and FE based in Beijing, Shanghai and Chengdu. Please send your resume to [email protected].