Backend Development 8 min read

Why Process Orchestration Is Essential for Backend Systems and How to Implement It with a Flow Engine

The article explains the drawbacks of over‑designing code with tangled if‑else branches, argues that process orchestration and plugin extensions provide clean isolation and extensibility for multiple business lines, and demonstrates a flow‑engine implementation with configuration, node definition, execution, and source code details.

Java Captain
Java Captain
Java Captain
Why Process Orchestration Is Essential for Backend Systems and How to Implement It with a Flow Engine

As a good programmer, one should keep the professional bottom line: simple tasks must be solved with simple solutions, avoiding over‑design and keeping the system concise.

Initially, I scoffed at process orchestration, considering it typical over‑design.

I believe code should be straightforward and reliable; jumping between methods feels messy. Process orchestration places methods into extension classes and combines them into a workflow, which seemed unnecessary to me.

After joining a middle‑platform team, I realized that process orchestration is a lifesaving capability.

A business middle platform must integrate many different business lines, which are not identical; often full reuse is impossible, requiring system adaptation for new business.

When adding new business code, it is crucial to ensure existing functionality remains unaffected. Without process orchestration, the code is filled with numerous if‑else statements.

if (biz == BizA || biz == BizB) {
    //do some thing
    //这部分逻辑相同
    if (biz == BizA) {
        //差异化处理
    }

    if (biz == BizB) {
        //差异化逻辑
    }
}

The example above shows that with many business lines, the number of branches quickly becomes overwhelming.

No one can master all ten‑plus business scenarios; each developer may only handle one. Without logical isolation, maintainers must sift through tangled code, and each new business adds more if‑else clutter, eventually leading to accidental changes that affect other critical services and cause outages.

Imagine after modifying a few lines, testers would need to regress the entire logic of over ten business lines—clearly unrealistic.

The problems can be summarized as code isolation and business extension points. Two solutions are proposed:

Use a flow engine to configure different execution chains for each business.

Use a plugin‑extension engine to implement business‑specific variations.

MemberClub extensively uses a flow engine and plugin‑extension engine to solve isolation and extensibility challenges.

Configure Flow Execution Chain

Considering that different membership product purchase processes vary, the DemoMemberPurchaseExtension implements a purchase extension point and defines three ways to configure flow execution chains. (See screenshot below.)

Define Flow Nodes

Methods in a flow node include process , success , rollback , and callback .

Flow Execution

During execution, provide a flow context object and call the FlowChain.execute method.

In the actual execution phase, each flow node is linked by the engine and executed sequentially, similar to the Chain of Responsibility pattern. The order is: each node’s process runs; if an exception occurs, its rollback runs; if all process calls succeed, success runs in reverse order.

Flow Engine Execution Principle

The following is the implementation of the FlowChain.execute method.

public
void execute(FlowChain
chain, T context) {
    Exception exception = null;
    int index = -1;
    for (FlowNode
node : chain.getNodes()) {
        try {
            node.process(context);
            index++;
        } catch (Exception e) {
            if (e instanceof SkipException) {
                CommonLog.warn("当前流程:{} 发出 Skip请求,后续流程不再执行", node.getClass().getSimpleName());
                break;
            }
            exception = e;
            break;
        }
    }

    if (exception != null) {
        for (int i = index; i >= 0; i--) {
            FlowNode
node = chain.getNodes().get(i);
            try {
                node.rollback(context, exception);
            } catch (Exception e) {
                CommonLog.error("rollback执行异常,忽略 name:{}", node.getClass().getSimpleName(), e);
            }
        }
    } else {
        for (int i = index; i >= 0; i--) {
            FlowNode
node = chain.getNodes().get(i);
            try {
                node.success(context);
            } catch (Exception e) {
                CommonLog.error("success 执行异常,忽略 name:{}", node.getClass().getSimpleName(), e);
            }
        }
    }

    for (int i = index; i >= 0; i--) {
        FlowNode
node = chain.getNodes().get(i);
        try {
            node.callback(context, exception);
        } catch (Exception e) {
            CommonLog.error("callback执行异常,忽略 name:{}", node.getClass().getSimpleName(), e);
        }
    }
    if (exception != null) {
        throw exception;
    }
}

Project Source Code

https://gitee.com/juejinwuyang/memberclub

Author: 五阳 Source: juejin.cn/post/7469330882945318922
Backend Architectureflow engineprocess orchestrationcode isolationplugin extension
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.