1. Client modular decoupling practice-Router

background

As the business has entered a period of rapid development, business lines have expanded rapidly, and the project structure has become huge and complex, resulting in higher and higher iteration costs. The larger the size of the project also makes the compilation time of the whole project longer and longer. Modular operation (project self-operation, self-management) after the project is split is a better way out, but the complex mutual references between projects make it impossible for us to start, and how to remove the references between these projects is today’s topic

produce

First of all, we can sort out the current situation. The biggest problem we encountered is actually the messy coupling and quotation between projects.

 

Regarding these couplings and dependencies, we can simply analyze: In theory, each project is responsible for a separate business and should exist independently of each other. But in fact, in the same company's business system, it is impossible to truly achieve a complete separation between projects . (Cooperation may exist between companies, and projects and projects are of course even more likely)

It seems that it is impossible to remove business dependencies from the source of the business. We can only do the coupling between projects and the removal of references from our technical point of view. And the most critical point is: coupling, interdependence , and the concept of Router is put forward to solve these problems.

So what exactly is Router?

Router is a model with the idea of closing and distributing , which is used to deal with direct dependencies and calls between modules (projects). The most direct manifestation is actually an agreement and a rule, which is parsed according to the agreement and rules , and then distributed.

 

development of

In view of some of the above problems, we can actually get some key features, close the mouth , and distribute them .

OK, now that the key information has been obtained, the pseudo code can be typed out soon:

 

    public static void jump(String rule){
        if(rule){
            gotoBusinessActivity()
            return;
        }
    
        if(rule){
            invokeBusinessFunction();
            return;
        }
    }

Perfect !!! easy call, really did shut , distribution

But with the development of the business, the shortcomings have become more and more obvious. After careful analysis, some problems can be summarized

Swell

  • With the growth of the business, the expansion is too great, thousands of lines of code are located in this category, a veritable hodgepodge

Maintenance cost

  • All projects are maintained at the same time, and the correction of one project may cause other projects to be affected as well
  • if-elseLogic maintenance is too complicated
  • The distribution logic is hardcode , once an error occurs , it cannot be modified
  • The projects cannot be truly separated

Expand

  • From the code structure, it is not difficult to see that the distribution here is essentially “ hands-on” and not real distribution , and “ hands-on” can not achieve real splitting.

Judging from the above questions, it is not difficult to close the mouth , but how to distribute it is a difficult task.

Looking back at the requirements and existing problems, I feel that my if-elsemodel has actually lost one thing: I didn’t pull out a unified process.

How to define the process?

When I design, I like to compare with real life, and Router is nothing more than. And this model is very interesting

I want to send it by courier

This is my requirement, so what should I do? The two most important points

  1. address
  2. package

I only need to give the courier's address and the package , then it will be delivered to me (unless the address is wrong), but I want to emphasize that I am sending a courier and it is not a courier to accept the package. The courier only delivers , and the person at the address actually receives it .

Thinking of this, you can actually sort out the core life cycle and non-core life cycle of Router . When the Router conveys the intention of the caller to the receiver , it has completed its cycle. The next thing is that the receiver does it, and it has nothing to do with the Router .

 

 

At this point, the basic framework of Router has been determined (because the process has been separated), then the rest is the matter of specific modules. It is not difficult to analyze the two core modules of Router : rule processing and executor

rule

By model, we need to know two things: address , parcel , that correspond to the program is nothing more than the target point , the data , and then fit into our current business scenario, the rule is not difficult to extract out:

protocol://path?data

Isn't it familiar? In fact, it is a simplified version of our universal URL . In fact, the focus is on three messages:

  1. Protocol, used for version distinction, function distinction, etc.
  2. Target point, path, recipient of intent
  3. Data

Similarly, our rule is defined as

tctclient://project/module?key=value

The definition of the protocol is complete, but the difficulty is coming: How to deal with the mapping of Path

For example, Path is hotel/list, but this is just a string, I really want to call the hotel list HotelListAction, how would Path and targeting associates, this is a problem. In the process of discussion, there are actually three options:

  1. if-else Direct logical association
  2. Use Mapassociate
  3. Use xml for association

In fact, in essence, they are all the same, all for data association. But there are differences in maintenance and expansion.

if-elseNeedless to say, direct quotation will generate a very complicated dependency network , and it is impossible to extract the distribution . All distributions need to be associated in the current environment.

Map& XMLLogic like, are the path with the treatment class corresponding. But in terms of maintenance and scalability, we finally chose xml , the advantages are obvious: no code coupling , dynamic update . The MAPadvantage is that no data is loaded, the performance of this part of the saving.

Actuator

The concept of executor is much easier to understand. After a rule is parsed into a readable intent, I need to pass the intent and data to the recipient, and this recipient may be handled by various businesses. Therefore, I need to design an interface (otherwise there is no directivity) to receive, and the business department can process related logic by implementing this interface.

 

Although the process is basically over here, some special logic will be derived from the actual business logic, such as:

I want to open the hotel list, but there is a requirement that I must be logged in before I can enter directly, otherwise I need to log in first.

Perhaps only from the point of view of this requirement, it is not difficult to complete it with the current process, and it can be completed with two receivers . But when there are a lot of special logic derived in the middle and may be needed by multiple businesses, the use of two (multiple) receivers may be very bloated. At this time, in fact, another concept emerged- interceptors .

Interceptor

Interceptors are some special and general logic processing performed before a rule has its final effect .

The processing logic is actually very similar to the View Touch event. When a Touch event is generated, it is first allocated (distributed) , then intercepted , and finally consumed .

And our interceptor is slightly different

  1. There can be multiple interceptors
  2. Only when all interceptors are satisfied (pass) will it go to the executor (consumption)
  3. This interceptor model can be implemented through recursion

 

expand

For Router framework designed to use up to now been more than two years, business needs, it is also basically completed, to meet. It has indeed achieved the separation of the Router framework, the determination of the process, and the maintenance of the business logic (including the mapping relationship). When a business requirement arises, only a new rule needs to be generated to maintain it.

However, under re-examining the current framework, there are still many things that need to be improved:

  1. Data mapping is mapped through xml, so it will inevitably bring about I/Othe performance overhead of loading
  2. Whether the project call needs to write a very lengthy rule, for example jump("tctclient://hotel/list"), and this kind of string parameter usually cannot be checked by the compiler to check whether it is correct or not

For these two problems, we actually use (plug-in) tools to complete.

Gradle Plugin + Freemarker

The establishment of auxiliary classes at compile time

  • The loading of xml can directly generate Map relationship maintenance at compile time .
  • Verbose rules can be maintained through enumeration (enumeration is generated by xml), and the calling method is changed tojump(Bridge.HOTEL_LIST)

to sum up

This article is more about my mental journey when I received this demand. Everyone has their own feelings when writing code. In fact, we can find a lot of truth from the design of Router

There is no one-size-fits-all model

For example, at the beginning if-else, when the business volume is small, this may be a very good way to deal with it. When the business expands and the current structure is not applicable, it needs to be reconstructed in time.

If the framework is separated from the business, it is nothing. Only a framework that fits the business is a good framework.

Thinking is more important than coding

When a demand is received, it is more to think and design. The key to extract the core point, the process for the process to tease out the core of the life cycle of the non-core life cycle is very important



Author: sandking
link: https: //www.jianshu.com/p/54d0e13dd7e3
Source: Jane books
are copyrighted by the author. For commercial reprints, please contact the author for authorization, and for non-commercial reprints, please indicate the source.

Guess you like

Origin blog.csdn.net/weixin_56492685/article/details/115236344