With the continuous development and expansion of Youzan’s e-commerce business, the functions assumed by the App end are becoming more and more heavy, especially after the code changes its owner a few times, it starts to become chaotic, and it often happens that the whole situation is influenced by the whole situation. To cope with the growth of the team, we had to isolate the business, precipitate common components, and improve the mobile development infrastructure.
1. The pain points
Before modularization, we mainly face the following pain points:
- Business boundaries are not clear
- Common code is coupled to business code
- Code and resource files are heavily duplicated
- Constants fly all over the place
Among them, the business boundary is not clear is the biggest pain point, the most direct manifestation is thunder everywhere, often introduce new bugs, and many bugs can not be fundamentally solved, the code maintenance cost is high.
2. Refactoring principles
Modular doesn’t happen overnight, new demand in reconstruction as well as we do, every time I see that one tuo old code will have innumerable the only in the heart “grass mud horse pentium, simply rewrite the helpless of love is hard to suppress, results in red bull accompanied by day and write new code, although looks” beautiful “, but actually the problem more, do more harm than good. After a few hard knocks, we came up with three basic principles for refactoring:
2.1 Progressive refactoring
If a piece of code is stable, you can take some features from it and rewrite them. Don’t overwrite the whole thing at first. You can gradually eliminate the old code.
2.2 iOS/Android Reference
Business code is always surprisingly similar, and by referring to each other, you can Review the code and deepen your understanding of the business. It has been proven that early in the project, if manpower is tight, it is possible to have only one developer on one end of the project follow the requirements, and the other end “translate the code” directly, or even one person writing both ends of the code.
2.3 Clear up the business before starting
As the end of the business chain, App developers have a less understanding of the business than the back end due to the limitations of their roles. Haste makes waste. Reconstruction should not be rushed and business logic should be clarified before starting. (Talk to someone familiar with the business — PD, backend, testing)
3 Modular Process
Modularization is a divide-and-conquer process, similar in concept to SOA, in which a vertical split will inevitably lead to the creation of Common modules for business sharing, which can continue to be split horizontally and become thinner until Common disappears.
You don’t need a perfect goal to start with, just be rough and get better over time.
3.1 to extract Common
The Common layer, which serves all upper-layer businesses, is a Common layer and does not allow references to business-layer code.
- Start by delegating the Business layer code used by the Common layer to each Business
- The code shared by multiple businesses is then extracted into the Common layer
- Resource files are handled the same way as the code
The Common layer, as a stopgap, was born to die, eventually producing many functional independent base modules. The process is long, and we can only enrich the Common module while isolating the business, and then break it up into separate modules at certain nodes.
Code can not escape from the separation of long, long must be divided.
3.2 Service Isolation
Business modules cannot depend on each other, but only on common in one direction.
There are two coupling relationships between businesses:
- Page coupling
- Functional coupling
To achieve complete isolation, these two coupling relationships must be broken:
- Page decoupling – jump protocol
- Functional decoupling – Inter-module RPC
3.2.1 Unified Forward Protocol
Page decoupling can refer to the design principle of Web, define a URI for external pages in the service module, and then redirect between pages through the URI.
For example, pages A and B belong to different business modules. Before the decoupling of pages, if A wants to jump to B, it must rely on the module of B, so the jump code will be written in the following form:
Android
Intent intent = new Intent(getContext(), BbbActivity.class);
intent.putParcelable(BbbActivity.EXTRA_MESSAGE, message);
startActivity(intent);Copy the code
iOS
BbbViewController *bbbVC = [[BbbViewController alloc] init];
bbbVC.messageModel = messageModel;
[self.navigationController pushViewController:bbbVC animated:YES];Copy the code
If data needs to be passed between A and B, constants and models need to be shared, and coupling continues to increase.
If we define A uri-wsc ://home/ BBB for page B and then serialize the shared messageModel into A Json string, then A only needs to assemble A jump protocol that conforms to the scheme of page B.
wsc://home/bbb? message={ "name":"John", "age":31, "city":"New York" }Copy the code
There are many ways to implement URL Router, and there are a lot of information on the Internet.
Implementation of Android
-
Define the URI in the Androidmanifest.xml file
< activity android:name=".ui.BbbActivity" < intent-filter> < category android:name="android.intent.category.DEFAULT" /> < action android:name="android.intent.action.VIEW" /> < data android:host="bbb" android:path="/home" android:scheme="wsc" /> < /intent-filter> < /activity>Copy the code
-
Encapsulated jump Intent
final Uri uri = new Uri.Builder().authority("wsc").path("home/bbb") .appendQueryParameter("message", new Gson().toJson(messageModel)).build(); final Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(uri); startActivity(intent);Copy the code
-
Step 2 Further encapsulate the code
ZanURLRouter.from(getContext()) .withAction(Intent.ACTION_VIEW) .withUri("wsc://home/bbb") .withParcelableExtra("message", messageModel) .navigate();Copy the code
IOS implementation
- Save URI mapping to Controller class through plist file
- Package an SDK that jumps to the Controller based on the URI
- Page jump
[ZanURLRouter routeURL:@"wsc://home/bbb"];Copy the code
Matters needing attention
- The protocols on both ends must be consistent
- You need engineering to ensure that the page URI is unique
3.2.2 Inter-module RPC
Remote calls are made between Service A and Remote: server over HTTP or other protocols. Remote: Server is the service provider, and Service A is the service consumer.
For service A, Local: service B is also A service provider, but they do not depend on each other. Therefore, they can communicate only through protocols.
-
IOS provides services through protocol and uses BeeHive for service governance.
-
Android provides services through interfaces, and then we modeled Retrofit to create a “service governance” framework – ServiceRouter, which has the advantage of defining interfaces only in the module of the business provider, allowing for more complete decoupling.
4 Code Management
If the isolated business modules are still in a Project, there is no way to “physically” completely separate code references from each other, we need to ensure that the business is independent from each other in engineering.
4.1 Code Structure
Android (Module) | iOS (Project) |
---|---|
4.2 Independent release
Each subproject can be independently issued and then assembled into an App through coordinate dependence. Take Android as an example:
4.3 independent Repo
We haven’t found a good code organization yet, so our point is:
When the team size is small, one person covers multiple sub-projects, so there is no need for a separate Repo, which can be considered when a Repo needs multiple person covers.
The size of the | Whether the Repo is independent |
---|---|
Developer 1 : N projects | no |
Project 1 : N developers | is |
When the decoupling scheme is determined, modularization is actually a physical work, and rework will become commonplace, so we think the better way should be responsible for one stroke.
5 Poetry and the Distance
- Dynamically deliver the forward protocol through the mobile configuration center
- Extract the mobile business common UI component library
- The main project can optionally rely on business modules