Total 227 article

19, 2018

Since meituan was founded in 2013, its business has been developing rapidly. Meituan’s daily orders have exceeded 18 million, making it one of the most important businesses of Meituan Dianping. The client entrance of Meituan Takeout has expanded from a single independent takeout App to multiple App entrances such as takeout, Meituan and Dianping. The business of Meituan takeout has also developed from a single catering business to more than ten major categories of business, including catering, supermarkets, fresh vegetables, fruits and vegetables, medicines, flowers, cakes and errands. The rapid development of services poses new challenges to client architecture.

Platform background

Long ago, take-out as an incubation project only had meituan Take-out App (hereinafter referred to as take-out App) as an entrance. Later, take-out was connected to Meituan App (hereinafter referred to as Take-out Channel) as a sub-channel, with parallel and iterative development of businesses at both ends. In the early days, in order to go online quickly, the developer directly copied the code of the take-out App to the take-out channel, and soon connected it to meituan App after making simple adaptation.

In the early days, the delivery App and the delivery channel were maintained separately by the two teams, but in the subsequent period, the difference between the two code systems became larger and larger. Finally evolved into two sets of code from the network, image and other basic libraries to UI controls, class naming, etc. Although the two teams were later merged, the historical differences formed, and for a long time we had to pile more functionality on top of the two sets of code in order to prioritize business needs. The cost of maintaining two sets of code is conceivable, and the rapid growth of the business makes this problem even more intolerable.


While we are exploring solutions to code reuse at both ends, the development of business has posed new challenges to us. With the expansion of team members several times, the separation of vertical categories such as Shang Chao fresh, and the establishment of a remote RESEARCH and development team, the platform of takeaway client is put on the agenda. Before this, takeout App and takeout channel basically maintained single project development, which obviously could not support multi-team collaborative development. Therefore, we need to quickly refactor the code into a multi-engineering pattern to support platformization, while also considering the decoupling of business modules, so that new businesses can copy the existing code quickly online. In addition, in the process of implementing platformization, the problem of code reuse at both ends has not been solved. If the codes at both ends are not unified and the platformization business is directly dewarehousing, it will inevitably lead to complications.

In this context, we can see that compared with other platform-based apps, the problem we are facing is more special and complex: we need to solve the platformization of food delivery business and the problem of code reuse at both ends of food delivery App and food delivery channel.

Repeated exploration

The road to platformization and code reuse at both ends is not smooth, and many solutions don’t know the problem until they are tried. Many times we have seen a design completed, and the team is fully engaged in development, but the original design has to be changed due to a change in business shape. In the process of constant exploration and practice, we went through many intermediate stages. There were many failures, but valuable experience in architectural design was also accumulated, and the team gained a deeper understanding of business and architecture.

Search library splitting practices

In the early stage, the merger of meituan Takeout App and Meituan Takeout Channel brought about the biggest pain point of code reuse rather than platformization, and for a long time, we did not think of solving the problem of code reuse at both ends from the perspective of platformization. However, some failed attempts of code reuse have brought a lot of valuable experience to the subsequent platform architecture. What was the solution to the code reuse problem? Through communication with product and design students, we agreed on future requirements, and we will try our best to keep both ends consistent in terms of requirements content, interaction and style. After many discussions, the team initiated a technical scheme for code reuse at both ends. We decided to separate the search module from the main project and realize code reuse at both ends. However, the search module code at both ends is very different from each other at the bottom. There is no unity of BaseActivity and BaseFragment, UI style, data Model, picture, network and buried point, and the release cycle at both ends is also different. The solutions to these problems are:

  1. Use proxy to prevent the inconsistency between Activity and Fragment base classes.

  2. Both ends of the main project style overwrites the search library UI style;

  3. Search library uses independent data Model, the upper layer to do data adaptation;

  4. All other differences throw up interfaces for the upper layer implementation;

  5. Communicate with PM to align product requirements with release cycle.

The architecture is generally shown as follows:

Although search library into independent project in a short time, and realized the vast majority of both ends of the code reuse, but not for long, just update after several versions, due to differences in demand and release cycle, search library started into two branches, and the difference of two branches is more and more big, the code cannot merge and finally had to permanently maintain two search library. The search library is actually a failed split, with three problems summed up:

  1. In the case of huge differences between the two ends of the bottom, the forced split from top to bottom leads to a large number of implementation and adaptation left at the two ends of the main engineering implementation, such a chaotic design hierarchy, fuzzy boundary, and greatly increased the complexity of business development;

  2. It is unrealistic to expect the demand and release cycle at both ends to be exactly the same. If there is no scalable space for the differences at both ends in the architecture, reuse is ultimately unsustainable.

  3. Conventions or specifications, limited by organizational structure and individual implementation, are too uncertain.

Page componentization practices

After the failure of search library splitting, we think that there is no condition to realize module splitting and reuse at present, so we move to another direction, that is, to realize the componentization of page to achieve the goal of partial component reuse. The design idea of page componentization is as follows:

  1. Split the page into smaller components that contain both the UI implementation and the data and logic layers;

  2. Components provide personalized configurations to meet the requirements of the two ends. If the requirements cannot be met, the components are discarded by the proxy.

Page componentization is a good design, but it is mainly used to solve the problem of Activity bigness. Because of the huge differences at the bottom, it is difficult to achieve large-scale reuse of page componentization, and the reuse efficiency is low. On the other hand, page componentization leaves no room for scalability for 2-end differences.

MVP layered reuse practices

We also tried to use design patterns to solve the problem of code reuse at both ends. The idea is to divide the code into mutable and stable parts. The mutable part can be differentiated at both ends and the stable part can be reused at the lower level. The main design ideas are as follows:

  1. Use Clean MVP architecture to split code into Presenter, Data Repository, Use Case, View, Model and other roles according to their responsibilities.

  2. The logic of UI, animation, data request, etc. is only interfaces in the lower layer, implemented in the upper layer and injected into the lower layer;

  3. For inconsistent data models at both ends, the converter ADAPTS to the unified Model at the lower level.

The architecture is generally shown as follows:

This is a flexible, elegant design that allows some code to be reused and resolves differences in the base libraries and UI at both ends. This scheme has been used in some modules of the home page and secondary channel page for a period of time, but the promotion is slow due to the high learning cost. In addition, this is a time when platformization is on the agenda. Business pain points determine that we must quickly implement the splitting and reuse of the whole module, and elegant design patterns are not suitable for solving this kind of problem. Even from the perspective of reusability, such a design will make business development more complex, difficult to debug, difficult for newcomers, and ultimately difficult to promote the implementation.

Middle layer practice

Through many practices, we realize that the unification of the base library is an inevitable work to realize the reuse of code at both ends, and is the foundation of all other work. Otherwise, complex and difficult-to-maintain designs will inevitably result, ultimately leading to the inability of both ends to move forward quickly.

There is a saying in computing that “any problem in computer science can be solved by adding an intermediate layer.” (Original version by computer scientist David Wheeler.) We certainly thought about shielding the base library differences at both ends with a mid-tier design. For example, network library, takeout App based on Volley implementation, takeout channel based on Retrofit implementation. We used to encapsulate a network framework on top of Volley and Retrofit, exposing a unified interface where the top layer could switch between Volley and Retrofit. But that middle tier never came online, and we ended up unifying the web libraries at both ends into Retrofit.

There are several reasons for this: Retrofit itself is a high level of encapsulation and has an elegant design pattern that makes it theoretically difficult to encapsulate a more scalable interface; Secondly, in the long term, the risk of the change of the underlying network framework is very low, and it is time-consuming and labor-consuming to adapt various plug-ins of the network layer, so the cost performance of maintaining the network middle layer is very low. In addition, replacing network requests at both ends with mid-tier interfaces is obviously more work than just keeping the dependency on one end.

Through practice, we realize that the middle layer design is a double-edged sword. If the base framework itself is extensible enough, the design of the middle layer will appear redundant, and even lose the good characteristics of the original framework.

Platform practice

Good architecture comes from constant evolution, not design. The platform architecture construction of takeout Android client also went through the same process. From how to solve the problem of code reuse, we gradually evolved into how to solve the two problems of code reuse and platformization. In fact, take-out platform is a good medicine to solve the reuse of code at both ends. By establishing a takeout platform, we reduce the existing takeout business to a channel, and connect the takeout business to the takeout platform and Meituan platform respectively in the form of AAR. In this way, the problem of code reuse will be perfectly solved while the takeout platform is solved.

Platform Architecture

After a whole year of hard work, the platform architecture of Meituan Takeout Android client is formed as shown in the figure:

From the bottom to the top are the platform layer, the business layer and the host layer.

  1. The content of the platform layer includes carrying the data communication and page jump of the upper layer; Provide core delivery services, such as merchandise management, order management, shopping cart management, etc. Provide configuration management services; Provide unified infrastructure capabilities, such as network, picture, monitoring, alarm, location, sharing, hot repair, burial point, Crash reporting, etc. Provide additional management capabilities, such as life cycle management, componentization, etc.

  2. The business layer includes take-out business and vertical business.

  3. The contents of the host layer include the Waimai App shell and the Waimai-channel shell of Meituan Takeout Channel. This layer is used for Application initialization, DEX loading, and initialization of various other necessary components or base libraries.

In the process of building a platform architecture, we encountered the problem of how to maintain the hierarchical boundaries of our platform architecture for a long time. Imagine if all the code was developed in one project, and hierarchical boundaries were regulated by package names and conventions, any urgent need could break hierarchical boundaries. What is the best way to maintain hierarchical boundaries? Our experience is engineering isolation. Each layer of the platform does engineering isolation, and each business in the business layer establishes its own engineering library to achieve engineering isolation. At the same time, the script is compiled to check whether the business libraries are interdependent. The benefits of engineering isolation are obvious:

  1. Each project can compile and package independently;

  2. Internal modification of each project will not affect other projects;

  3. The business library project can be quickly broken down and integrated into other apps.

But another problem with engineering isolation is, what about business libraries that need to communicate between the same layers? It is necessary to provide a business library communication framework to solve this problem.

Business library communication framework

Libraries in split delivery business business, we can send such a case: the merchant page there is a business, if I found the current merchants are close, will pop up a floating layer, recommended list of similar businesses, and before we divided the take-away child business repository, similar businesses should belong to the page content repository list. So how do you get the merchant business library to access the code in the page library? If we rely on the page library for the merchant library, our hierarchical boundaries will be broken and our dependencies will be complicated. Therefore, we need to provide an inter-layer communication framework in the architecture, which solves the problem of completing inter-layer communication without breaking the boundary of the hierarchy.

Summary of inter-layer communication scenarios can be roughly divided into: page jump, transfer of basic data types (including the transfer of serializable common class objects), internal module custom methods and class invocation. For the above situation, our architecture provides two modes of inter-level communication: Scheme routing and the ServiceLoaders SDK built by Meituan. Scheme routing essentially uses the Scheme principle of Android to communicate, while ServiceLoader essentially uses Java reflection mechanism to communicate.

The scheme route invocation looks like this:

End result: All service page jumps need to be distributed through the Scheme route of the platform layer. Through Scheme routing, all services are decoupled, and the page jump and basic data type transfer can be realized without mutual dependence.

The serviceloader call looks like this:

The provider and the consumer constrain their interaction through an interface at the platform layer. The user obtains the provider’s implementation object through the platform layer ServiceLoader. This approach solves the problem of calling custom methods and classes within a module. For example, we mentioned earlier that the merchant library needs to call the page library code. ServiceLoader can solve this problem.

Takeaway kernel module design

In the course of practice, we also encounter businesses where hierarchical boundaries are difficult to delineate in the business itself. We can see from the three-tier architecture diagram of Meituan takeout that the takeout business library, such as merchants and orders, is at the same level as the vertical business library of Takeout. In fact, it is uncertain whether the sub-business of takeaway business should be kept at the same level as the vertical business.

At present, the vertical business connected by takeout is a sub-channel of takeout business, and it still relies on the core model and core service of takeout, including commodity management, order management, shopping cart management, etc. Therefore, there is no problem for it to be on the same level with the sub-business library of takeout business, such as orders. However, with the development of the supermarket business, it may build its own commodity management, order management and shopping cart management services in the future, and then the supermarket business will rise to the same level of business as the takeout business. At this point, the core delivery management service, located at the platform level, will cause the hierarchical boundaries of the architecture to become unclear.

Our solution is to adapt to future changes by designing a kernel module belonging to takeaway business. The design of kernel module is shown as follows:

  1. The inner circle is the basic model class, which forms the basis of the core business of takeout (from store to order to shopping cart to order);

  2. The middle circle is the base services (CRUDS) built on the base model classes;

  3. The outermost circle is the business of all dimensions of takeout, and the inner circle depends on the basic model circle and the basic service circle of takeout.

If it is determined that the takeout platform needs to access more businesses at the same level as takeout in the future, and the innermost circle is completely different, we will move the takeout kernel module up and establish dependence on the kernel module under the takeout business sub-library. If the future is just more access to the takeout sub-business, then keep our current structure; If the business basic model classes are the same in the future, but their own business services need to be differentiated, then we will retain the core inner circle of the kernel module, and abstract out the service layer to realize the real service by the top layer of takeout and supermarket.

Business library split

When we split the business library, we are faced with such a problem: the relationship between the businesses is more complex, how to split the business library, is more reasonable? At the beginning, we planned to split the takeaway business according to the core process of the takeaway business: page → merchant → order. However, with the rapid development of takeout sub-channel business, sub-channel business has also established its own RESEARCH and development team, in the page, merchants, orders and other links, also began to establish their own pages. If we still split the library according to the process of ordering takeout, there will be joint development between the takeout team and the takeout sub-channel team in the same library, so the responsibility boundary is very unclear, and there will definitely be confusion in the actual development process.

We all know there’s something called Conway’s Law in software engineering:

Organizations which design systems are constrained to produce designs which are copies of the communication structures of these organizations. – Melvin Conway(1967)

The organization that designs a system, the design that produces is equivalent to the communication structure within and between the organizations.

Guided by Conway’s theorem, we believe that the technical architecture should reflect the organizational structure of the team, and that the change of organizational structure should also lead to the evolution of the technical architecture. Meituan takeout platform includes takeout business and vertical category business. As we already have an organizational structure in our team, we should give priority to the organizational structure and separate the independent business library to facilitate the internal communication and collaboration of students in the sub-business library and reduce the cost of their cross-organization communication. At the same time, we further divided the large team responsible for take-out business into page group, merchant group and order group, and students of these groups completed the split of take-out sub-business library in a finer dimension under take-out business. According to the organizational structure of the business library, there is a natural business boundary, each student will continue to improve their business library according to their own business goals. Such dewarehousing is highly cohesive internally and low coupled externally, effectively reducing the cost of internal and external communication and cooperation.

Code isolation in project

After implementing project isolation, we found that the code within the project could still refer to each other. If code isolation cannot be achieved within the project, then the boundaries within the project are blurred. We want at least page-level code isolation within the project, because an Activity is a page unit that makes up an App, and there’s usually a lot of code and resource files around that Activity, and we want those code and resource files centrally managed.

Usually we think of module project as a unit of isolation, but module is a relatively heavy constraint, should each Activity build a Module? This code structure becomes very complex, and for some large business bodies, will form a huge Module.

Then we thought of the standard code, using the package name to remove the artificial agreement, but by the package name constraints of the code, the boundary is vague, from time to time urgent needs, the package name agreement is broken, and the placement of resource files is arbitrary, high migration cost.

How to solve the boundary problem inside the project? An important concept p(Pins) project is mentioned in the paper “Practice of Modular Architecture Reconstruction of wechat”. P Project can be described as an important magic weapon to constrain code boundary within the project. Gradle = sourceSets = sourceSets = sourceSets = sourceSets = sourceSets

sourceSets {    main {        def dirs = ['p_widget', 'p_theme',                    'p_shop', 'p_shopcart',                    'p_submit_order','p_multperson','p_again_order',                    'p_location', 'p_log','p_ugc','p_im','p_share']        dirs.each { dir ->            java.srcDir("src/$dir/java")            res.srcDir("src/$dir/res")        }    }}Copy the code

The effect is as follows:

As can be seen from the figure, this business library is split into multiple P projects by page unit. The boundary of each P project is clear, realizing the code isolation within the project. The benefits of in-project code isolation are obvious:

  1. The minimum granularity code boundary constraint is realized in project P.

  2. Clear responsibilities of modules in engineering;

  3. Business modules can be quickly broken down.

Code reuse

P project meets the requirement of code isolation within the project, but don’t forget that there may be differences between the two terminals (take-out App& Meituan App) in each module. Only if the differences between the two terminals can be realized within the module can our goal be achieved. With that in mind, we came up with productFlavors that Gradle offers to make the difference. To do this, we need to define two flavors: WM and MT.

productFlavors {     wm {}     mt {}}Copy the code

However, p projects generated in this way are parallel, that is to say, all differentiated codes in each P project need to be stored in the SourceSet corresponding to the two flavors, which is contrary to the concept of code isolation between modules, isn’t it? The ideal structure is to divide the flavor inside the P project, and then change the Gradle script as follows:

productFlavors {    wm {}    mt {}}sourceSets {    def dirs = ['p_restaurant', 'p_goods_detail', 'p_comment', 'p_compose_order',                'p_shopping_cart', 'p_base', 'p_product_set']    main {        manifest.srcFile 'src/p_restaurant/main/AndroidManifest.xml' dirs.each { dir ->            java.srcDir("src/${dir}/main/java")            res.srcDir("src/${dir}/main/res")        }    }    wm {        dirs.each { dir ->            java.srcDir("src/${dir}/wm/java")            res.srcDir("src/${dir}/wm/res")        }    }    mt {        dirs.each { dir ->            java.srcDir("src/${dir}/mt/java")            res.srcDir("src/${dir}/mt/res")        }    }}Copy the code

The final engineering structure is as follows:

Through the flexible application of P project and FLAVOR, we finally configured the business library into module units with P project as the dimension, and compatible with the similarities and differences of both ends within P project, which solved the problem of code reuse. At the same time, the differences between the two ends are handled by THE P project itself, without establishing an intermediate layer or leaving the differences to the upper shell project. Such a design follows the principle of clear boundary and downward dependence.

However, in-project isolation presents the same problem as engineering isolation: what if the same level P project needs to communicate? When we split the merchant library, we are faced with such a problem. The product activity page and the product details page can be divided into two P projects according to the page dimension. Both pages use the item of the same product style. How to make the item activity page p project and the item details page P project access the item style item between the same level? In the practice of warehouse demolition, we gradually explore the three-level engineering structure. The three-level engineering structure can not only solve the problem of p engineering communication within the project, but also keep the flexibility of the architecture.

Tertiary engineering structure

Three-level engineering structure refers to the three-level structure of project → Module → P. We can divide any very complex business project into several module projects of independent units. Meanwhile, we can continue to divide the module project of independent units into independent P projects within it. Because the Module is code isolated at compile time, the boundaries are not easily broken and it can be upgraded to a project at any time. The p project that needs to communicate depends on the home directory of module, the base directory, through which communication is realized. The project and Module have the ability to isolate the code on compilation, and the P project has the ability to minimize the constraints on the code boundary. Such a design can make the internal boundary of the project clear and downward dependent. The design is shown in the figure below:

The biggest advantage of the three-level engineering structure is that each level can be flexibly upgraded or downgraded according to the needs. Such flexible upgrading and demotion can adapt to the changes of the team organizational structure at any time and keep the flexibility of architecture splitting and merging, thus dynamically meeting Conway’s theorem.

Engineering construction

An intuitive result of platformization is that there are many sub-libraries. How to manage these sub-libraries effectively will be a problem affecting the efficiency of team research and development. So far, we have made improvements in the following two areas.

One key cut source code

When the main project integrates the business library, there are two dependency modes: AAR dependency and source dependency. Aar dependencies are the default, but they often need to be switched from AAR dependencies to source dependencies during normal development, such as new requirements development, bugfixes, and troubleshooting. In normal cases, we need to manually change compile AAR to compile Project in each project build. If the business library also needs to rely on platform library source code, we need to do the same operation. As shown below:

Doing this manually presents two problems:

  1. Build. gradle changes frequently and can cause conflicts if developers accidentally push it.

  2. As the business library grows, the cost of such changes increases.

Given the versatility of this requirement, we developed a Gradle plug-in that switches to source dependencies with one click from a configuration file in the main project (ignored by Git). For example, if you need a merchant library source code dependency, you just need to turn on the source code dependency switch for that library in the main project. Merchant libraries also rely on platform libraries, which are aar dependencies by default, and can be switched on if you want to change to source dependencies.

A key to pack

As the business library increased, the construction process became more complicated. We delivered two kinds of products: APK for takeout App and AAR for takeout channel. For takeout App, it is easier to associate the source code of the designated branch of each business library on Jenkins and package it directly. However, the situation of take-out channel is more complicated, because due to some limitations of Meituan platform, channel packaging cannot be directly related to the source code of each business library, but can only rely on AAR. Traditionally, it would be inefficient to type aArs for business libraries one by one, integrate them in the channel project, and then type aArs for channels. To this end, we improved the channel packaging process. As shown below:

First draw library aar, follow up automatically to PR to various business platform to modify the version number of the library, then each trigger business library to play the aar, business library play again after the aar automatically make PR to channel the main library to modify business library version number, all businesses such as library aar after closing again channel trigger automatically play the main library of aar, at this point a key finished packaging.

Platform summary

Since the first attempt to split the search library, the architecture of takeout Android client has been continuously explored and practiced for more than two years. At first, in order to solve the problem of code reuse at both ends, we tried to split and reuse from top to bottom, but soon exposed the problems caused by the confusion of hierarchy and fuzzy boundary, and realized that code reuse could not be sustained without providing differentiated solutions at both ends. Later, we tried to use the design pattern to constrain the boundary to achieve decoupling and reuse first, but in the process of promotion, we realized that it is difficult to advance the complicated design quickly.

At the beginning of platformization, the team had developed the concept of an architecture with simple design and clear boundaries. We divided the overall structure into host layer, business layer, and platform layer, and strictly constrained the dependencies among the layers. In the process of business module splitting, we learned from the engineering structure scheme of wechat, divided business boundaries according to the three-level engineering structure, realized flexible code isolation, and reduced the cost of subsequent module migration and migration, making the architecture dynamically meet Conway’s law.

On the issue of code reuse at both ends, we realize that to achieve sustainable code reuse, we must gradually unify the base dependence at both ends from bottom to top, and at the same time, it can easily support the differentiated processing of the upper business at both ends. Flavor is used to manage the difference codes at both ends, minimizing upward dependencies, and applying previous decoupled design experience to implementation to meet the scalability of the architecture.

No scheme can win the approval of everyone. In the implementation process of platformization, team members have had many confrontational discussions about the scheme selection. We leave the technical solution behind, go back to the problem, review the pain points of the business, list the problems to be solved, and then look back to see which solution will solve the problem. We don’t do this very often, but there are moments when decisions are forced and implemented, and problems are revisited and adjusted.

Any design concept has its applicable scenarios. We are constantly paying attention to some excellent architecture and design concepts in the industry, as well as the platform practical experience of meituan App and Comment App teams within the company. We have learned and used many excellent design ideas for reference, but we have also trampled on many pit due to blind abuse. We recognize that the choice of architecture, like other technical issues, should be problem-oriented, not technology-oriented. The evolution of architecture must alternate between theory and practice, and it would be a tragedy to leave either of them.

Looking forward to

After the platformization, the collaboration and development process of each business team has changed greatly. We will face new problems and challenges on how to improve the platform support capability, how to maintain the stability of the architecture, and how to further decouple the services. Three of these issues need to be addressed:

  1. To ensure that architecture is not broken in long-term business iterations, in addition to process specifications, it is necessary to establish more robust inspection tools to constrain the various stages of local compilation, remote commit, code merge, package and test, and currently these tool chains are not complete.

  2. Plug-in architecture is the best way of platform App integration, which not only enables dynamic publishing of sub-services, but also solves the troublesome compilation speed problem. At present, Meituan platform has achieved good plug-in integration in some businesses, and take-out is following up.

  3. A standardized framework for unified page-level development addresses code maintainability, testability, and finer granularity of reusability, and facilitates implementation of various automation solutions. At present, we are trying some business, and will continue to push forward.

The resources

  1. MVP + Clean Architecture

  2. Good architecture comes from constant evolution, not design

  3. Every architect should study Conway’s theorem

  4. The theoretical basis of microservices architecture – Conway’s Law

  5. The essence of architecture is management complexity, and microservices themselves are the result of architecture evolution

  6. Practice of wechat Android modular architecture reconstruction

  7. Configuration build variant

  8. Meituan App plug-in practice

Author’s brief introduction

Wu Kai, technical expert of Meituan Dianping. He joined Meituan-Dianping in 2016 and is now in charge of the Android team of takeout users, mainly focusing on the business support and technology construction of the Android platform of takeout.

Xiao Fei, senior engineer, Meituan Dianping. He joined YuanMeituan in 2015 and was one of the early developers of Take-out Android. Currently, as the head of Take-out Android App, he is mainly responsible for platform and business architecture.

Haibo, Senior engineer, Meituan Dianping. In 2015, I joined YuanMeituan and used to support B-side business such as Shangzhibao. Now, AS the main developer of Takeout Android App, I am responsible for merchant container module and related promotion of platform.

———————-  END  ———————-

Recruitment information

Meituan takeaways is looking for senior/senior engineers and technical experts in Android, iOS and FE, based in Beijing, Shanghai and chengdu. Welcome interested students to send resumes to wukai05#meituan.com.

You might also want to see:

Dianping App short video power consumption optimization actual combat

Meituan takeout front visual interface assembly platform — Lego

Android dynamic log system Holmes