Design and consideration of trading platform system

Preface

For nearly two years, I have been doing research and development of mid-range systems in an enterprise. Recently, this experience may be over.This article is also a review and reflection of this experience.

system architecture

What I want to say here is Service Access Layer. There is no Service Access Layer in our current system architecture.However, in my future reflection, I feel that the existence of service access layer is still necessary.

Role of Service Access Layer

  1. Antiseptic effect.Because the business center serves multiple lines of business within the enterprise, different business needs should be met in daily development. We often add many conversion and interpretation logic in the underlying services, and introduce the service access layer, we can put these codes into the service access layer.
  2. Business isolation.Each line of business within an enterprise has its own unique scenario of business, some calls to services are relatively smooth, and some business may erupt centrally at a certain time.As a broadcaster, we don't want a scenario or bug in one business to make all business unavailable, so we can limit the flow of services in the access layer for business (the main solution is Sentinal's hot parameter limit).
  3. Easy to manage the external output capacity.In subsequent development, developers only need to write interface documentation and maintain the documentation for the interface of the access layer.Secondly, the developers of the whole platform can have an understanding of the overall capabilities of the platform as long as they know that the access layer outputs those capabilities to the outside world, and they do not need to face each interface with a large number of services at the bottom level.

Main trading points

In fact, there are two main design points in building trading or business platforms:

  1. How to provide a reasonable access process to the business party.Enable business parties to complete their own business while providing fast access
  2. How does the Mid-Taiwan Business System cope with differences in business processes between different businesses

Access process

The main access processes are shown in the following figure:





Users buy goods on the front page.At this time, the business side interface is called, and the business side calls the interface of the middle station to submit information such as purchased goods, create a transaction order, get the transaction number and associate it with its own business data, and then invoke a common payment component based on the transaction number.
The logical business party that rouses the payment component to the payment does not need to be concerned. The payment component interacts directly with the trading platform.
After successful payment, the trading desk processes the order logic, and calls back the business party when the processing is completed, then the business party processes its own business logic according to the callback transaction number.

In fact, the access process encountered some problems in the design and evolution:
Initially, the business side created the invisible order data in the first step, which also caused a large number of invalid order data in the trading system, and then optimized into a trading order, the order number reuses the transaction number, which has no effect on the business side in fact transparency.
There is also the process of handling payment callbacks and callbacks to the business side, which is initially a synchronous call, which also causes the reverse flow of the order state to depend on the business side's system. When the business side's system fails, the order state cannot flow properly.

Business differences

Let's take two business examples below. I'll just describe the general process. True business processes may be more complex.

When eliminating business differences, first of all, analyze the processes of each business, find out which business is the most complex as a sample, and analyze which is the common logic and which is the logic with differences.
In the example, the process of the shop may be the most complex, and that of the members is simpler.Based on the figure above, we can also divide the persistent order data into two processes.
Pre-processing before order persistence, post-processing after order persistence.
We form a single component for logical pull-out and create different component call chains for pre-processing and post-processing depending on the business.
Here is the sample code:
Let's first define the components






public interface Processor<T, R> {
    /**
     * Execute content, interrupt throws {@link com.xxx.xxx.infrastructure.exception.ProcessorInterruptedException}
     *
     * @param context
     * @param result
     */
    void process(T context, R result);

    /**
     * Trigger the call to the next Processor
     *
     * @param context
     * @param result
     */
    void fireNext(T context, R result);

    /**
     * Check whether the Processor is executed
     *
     * @param context
     * @param result
     * @return
     */
    boolean check(T context, R result);
}

public abstract class AbstractProcessor<T, R> implements Processor<T, R> {
    private AbstractProcessor<T, R> next = null;

    public AbstractProcessor<T, R> getNext() {
        return next;
    }

    @Override
    public boolean check(T context, R result) {
        return true;
    }

    public void setNext(AbstractProcessor<T, R> next) {
        this.next = next;
    }

    public void invoke(T context, R result) {
        try {
            process(context, result);
            fireNext(context, result);
        } catch (ProcessorInterruptedException ex) {
            return;
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
            throw ex;
        }
    }

    @Override
    public void fireNext(T context, R result) {
        if (next != null) {
            if (check(context, result)) {
                next.invoke(context, result);
            } else {
                if (next.getNext() != null) {
                    next.getNext().invoke(context, result);
                }
            }
        }
    }
}

Then define the abstract class that builds the component chain

public abstract class AbstractProcessorBuilder<T, R> {
    @Autowired
    protected AutowireCapableBeanFactory autowireCapableBeanFactory;
    protected AbstractProcessor<T, R> instance;

    @PostConstruct
    public void init() {
        initProcessor();
    }

    public abstract void initProcessor();

    public AbstractProcessor<T, R> build() {
        return instance;
    }

    public void addLast(AbstractProcessor<T, R> processor) {
        if (instance == null) {
            instance = autowired(processor);
            return;
        }
        AbstractProcessor<T, R> next = instance;
        while (next.getNext() != null) {
            next = next.getNext();
        }
        next.setNext(autowired(processor));

    }

    protected AbstractProcessor<T, R> autowired(AbstractProcessor<T, R> processor) {
        autowireCapableBeanFactory.autowireBean(processor);
        return processor;
    }
}

The preceding call chain for the above two businesses is

@Component
public class StoreSubmitPreProcessorBuilder extends AbstractProcessorBuilder<SubmitOrderContext, ResultDTO<SubmitOrderResult>> {
    @Override
    public void initProcessor() {
        addLast(new CheckSubmitOrderNumProcessor());
        addLast(new CheckItemBuyNumLimitProcessor());
        addLast(new PaddingAddressProcessor());
        addLast(new CheckDeliveryLimitProcessor());
        addLast(new QuerySkuProcessor());
        addLast(new CheckSkuProcessor());
        addLast(new CalPromotionProcessor());
    }
}


@Component
public class PrimeSubmitPreProcessorBuilder extends AbstractProcessorBuilder<SubmitOrderContext, ResultDTO<SubmitOrderResult>> {
    @Override
    public void initProcessor() {
        addLast(new QuerySkuProcessor());
        addLast(new CheckSkuProcessor());
        addLast(new CalPromotionProcessor());
    }
}

The simplified submission order code is:

        getSubmitPreProcessorBuilder(bizType).build().invoke(context, ret);
         if (!ret.isOk()) {
                return ret;
         }
         //.....

In this componentized way, we can get different ProcessorBuilder s for different businesses to cope with process differences.

Mid-stage thinking

The platform provides not only interface and components, such as trading platform, but also order management background, order data visualization, through the continuous strengthening of the capabilities of the platform, to make the foreground business more focused on its own business.

The ability provided by the platform should be continuously promoted. When the needs of a single business are meaningful, it can be used as a successful case to promote to other businesses after implementation, so that other businesses can enjoy the dividends of the platform construction. Only by continuous promotion and continuous business feedback, the capability of the platform will be stronger.

The platform is not only a business structure, but also an organizational structure. Only an independent organizational structure can ensure that certain businesses will not have resource skews.

The building of the platform should be based on the actual situation of the enterprise, clear vision, and solve the corresponding problems of the enterprise.

Tips: The business example in this article is also a reference to the Jingdong business example, the sample code is also a modification to the actual code

Added by Brand Hill on Sun, 05 Apr 2020 08:39:52 +0300