High quality app architecture design and thinking!

Time:2020-3-31

Recently, I have been working on a small number of apps with small functions and complex businesses. In the past, I found that I never considered some architectural problems when I was working on an app. I just wrote code according to my previous habits and ignored the design of the app. This sharing mainly includes some small experience and skills of developing app. Let’s share the development and design of app.

Let’s shareThe design and organization of entity class

Organization of entity class

There are many entity classes in app development. The more complex the project, the more entity classes. After some thinking, I can roughly divide the entities into the following major numbers:

  • Database oriented
  • Data entity returned by the server
  • Entities used to render the view (using databinding)

Generally, the operation of entity class will go through the following steps:

  1. App requests server to get data
  2. Save data to database (optional)
  3. Render page display data

High quality app architecture design and thinking!

The current entity generation only needs to be created when the server data is requested. In fact, a set of entities can be used for subsequent database and page rendering:

High quality app architecture design and thinking!

First of all, if you don’t want to do this, the use of the same entity in three places will cause field ambiguity. For example, if the server data has ID and the local data has ID, the two ID fields will conflict and have to change the field name.

In another case, rendering and data itself do not correspond one by one. Sometimes, the back-end data gives a pure number while the front-end page shows that both strings do not correspond. It will cause more problems if they are forced together.

The correct organization form of the entity class should be:Mutual isolation and non-interference

High quality app architecture design and thinking!

Data entities need to be prepared before rendering. For example, in the ViewModel, the int type data is converted to text type data, and then the data binding + page rendering entity is used to render the page.

Elegant handling of network data

Now most of the network libraries used in Android development areOkhttp + Retrofit, it’s very simple to use retrofit network interaction. A service interface can do everything. Metz ~ ~, now most of the data returned by the back end will be in the following forms:

{
    "code":0,
    "data": {},
    "msg": ""
}

Although it can’t cover all the data, messages, success or not! Focus on the frontdataFields, othermsgcodeEtc. belong to auxiliary fields. The entity object corresponding to the front end should be (pseudo code):

public class ApiResponse<T> {
    private int code;
    private T data;
    private String msg;
}

The corresponding service must be defined as follows (rxjava is used):

public intface UserService {
    @GET("/xx/{id}")
    Single<ApiResponse<UserInfo> getUserInfoById(@Path("id") Long userId);
}

It can be seen from the interface that the return value of the method has several layers. If you want to getdataFields need to go through:ApiResponse -> UserInfoAnd judge before you take itcodeField:


...

if(ApiResponse.code == 0){
    UserInfo info = ApiResponse.getData();
}

...

To eliminate this redundant code, you can useCallAdapterThe data returned by the service method is the entity class directly:

public intface UserService {
    @GET("/xx/{id}")
    Single<UserInfo> getUserInfoById(@Path("id") Long userId);
}

CallAdapterThe code will not be pasted. You can find it by yourself. Another problem with this isHow to judge whether the interface is successful or failed by business code, the front end must be friendly to give the user an error prompt instead of making a load around all the time. At this stage, the most convenient way of error transmission is to useJava anomaly, front end can be definedBusiness exceptionorNetwork anomaly

public class BizException extends RuntimeException {
    ...
}

stayCallAdapterCheck whether the return value of apiresponse is successful:


if(!ApiResponse != 0){
    throw new BizExcepiton(ApiResponse);
}

If the back end returns a business exception, the front end will throw a correspondingBizExcepitonIf it is an HTTP error such as 404, 400, it can be thrownHttpException。 exceptBizExcepitonandHttpExceptionIn addition, you can use specific exceptions, such as the back-end return password error exception:

public class InvalidPasswordException extends BizException {
    ...
}

If special treatment is required, the requirements can also be met.

Robust data layer

Now many applications are developed using MVVM development mode data layer is usedRepositoryForData drivenThe development mode and the page change of should be updated with the data change,The data changes and the page responds。 Repository splitting should be a little more detailed. It is not recommended to make a simple oneUserRepositoryIncluding login, registration, password update and other operations, designRepositorySome ideas:

  1. Interface oriented programming
  2. keepSingle principle
  3. The function boundary should be clear (for example, login and registration can be separated)
  4. Minimize business logic (consider presenter for complex business)

A way to judge whether a design is good or not can be as follows: a landing page from active / fragment to ViewModel to repository, whether there is redundant code. Like the one aboveUserRepositoryIncluding login and registration, but there is no need to have the registration function in a login page. From the login page, the registration code is redundant (some apps login / register in a page ~ ~).

One including login and registrationUserRepositorySimple graph:

High quality app architecture design and thinking!

Another point is to try to centralize the management of some things used by the repository, and introduce a basic Repository:

public class SimpleRepository {
    
    protected final  <T> T getService(Class<T> clz){
        return Services.getService(clz);
    }
}

Do asSimpleRepositoryNo need to consider where to get the service.

Simple UI layer

The UI level can be divided into ViewModel and view (activity / fragment). The responsibilities of view should only be two points:

  1. Show business data
  2. Collect business data

For example, the organization and judgment of some data should not appear in the view, such as:

 if (Strings.isNullOrEmpty(phone)) {
       ...
        return;
 }

 if (Strings.isNullOrEmpty(pwd)) {
        ...
        return;
  }

Code like the above should not appear in view, but in ViewModel, view onlyCollect user dataPassed to ViewModel for data validation. For example, if / else code like this should also be placed in the ViewModel:

int age = 10;
 String desc = "";
 if(age < 18){
    Desc = "Youth";
 }else if(age < 29){
    Desc = "middle age";
 }

If there is too much data display and collection, it is recommended to use data binding to bind data in both directions. CollocationLiveDataEnable view as an observer to monitor data changes in real time:

registerViewModel.getRegistryResult().observe(this, new SimpleObserver<RegistryInfo>(this));

Once the data changesLiveDataThe observer will be notified to update, and the data of each page will be updated through databinding.

High quality app architecture design and thinking!

Besides, ViewModel should only contain some simple code to judge, check and get through the data. If the business is too complex, you can consider adding presetner. If it’s really super complex, you can reflect on whether this complex logic should be put on the front end or the back end?

Welcome to WeChat public’s official account, high quality technical articles for the first time.

High quality app architecture design and thinking!

Recommended Today

PHP Basics – String Array Operations

In our daily work, we often need to deal with some strings or arrays. Today, we have time to sort them out String operation <?php //String truncation $str = ‘Hello World!’ Substr ($STR, 0,5); // return ‘hello’ //Chinese string truncation $STR = ‘Hello, Shenzhen’; $result = mb_ Substr ($STR, 0,2); // Hello //First occurrence of […]