Why Overusing If‑Else Breaks Your Backend and How a Flow Engine Fixes It

The article explains how excessive if‑else branching in business‑centered back‑ends leads to tangled, hard‑to‑maintain code, and demonstrates how a flow‑engine combined with plugin extensions can isolate business logic, improve extensibility, and simplify testing, using the open‑source MemberClub project as a concrete example.

Top Architect
Top Architect
Top Architect
Why Overusing If‑Else Breaks Your Backend and How a Flow Engine Fixes It

Problem

Backend services often accumulate long if‑else chains to handle many business scenarios. When dozens of business lines are added, the code becomes tangled, hard to understand, test, or modify without risking regressions.

Solution

Introduce a flow engine that lets each business configure its own execution chain.

Use a plugin‑extension mechanism so that only the divergent parts need custom code.

MemberClub Project

https://gitee.com/juejinwuyang/memberclub https://github.com/juejin-wuyang/memberclub

Configuring Flow Execution Chains

The class DemoMemberPurchaseExtension defines three configurable flow chains. Each membership product can bind its own chain through the UI.

Defining Flow Nodes

A flow node implements four core methods: process – main execution success – post‑success handling rollback – error recovery callback – final callback

Flow Execution Process

During execution, a FlowChain receives a context object and invokes FlowChain.execute. Nodes are processed sequentially. If a process call throws an exception, the engine triggers rollback on already‑executed nodes in reverse order. If all process calls succeed, success is invoked on each node in reverse order, followed by a final callback.

Flow Engine Implementation (FlowChain.execute)

public <T> void execute(FlowChain<T> chain, T context) {
    Exception exception = null;
    int index = -1;
    for (FlowNode<T> node : chain.getNodes()) {
        try {
            node.process(context);
            index++;
        } catch (Exception e) {
            if (e instanceof SkipException) {
                CommonLog.warn("Current flow:{} sent Skip, stop later execution", node.getClass().getSimpleName());
                break;
            }
            exception = e;
            break;
        }
    }
    if (exception != null) {
        for (int i = index; i >= 0; i--) {
            FlowNode<T> node = chain.getNodes().get(i);
            try {
                node.rollback(context, exception);
            } catch (Exception e) {
                CommonLog.error("rollback exception, ignore name:{}", node.getClass().getSimpleName(), e);
            }
        }
    } else {
        for (int i = index; i >= 0; i--) {
            FlowNode<T> node = chain.getNodes().get(i);
            try {
                node.success(context);
            } catch (Exception e) {
                CommonLog.error("success exception, ignore name:{}", node.getClass().getSimpleName(), e);
            }
        }
    }
    for (int i = index; i >= 0; i--) {
        FlowNode<T> node = chain.getNodes().get(i);
        try {
            node.callback(context, exception);
        } catch (Exception e) {
            CommonLog.error("callback exception, ignore name:{}", node.getClass().getSimpleName(), e);
        }
    }
    if (exception != null) {
        throw exception;
    }
}
Full source file: https://gitee.com/-/ide/project/juejinwuyang/memberclub/edit/master/-/memberclub.common/src/main/java/com/memberclub/common/flow/FlowChainService.java

Technical Stack Used in MemberClub

MyBatis‑Plus

ShardingSphere (sharding and multi‑data‑source)

Redis / Redisson

Apollo configuration center

Spring Cloud (Feign, Eureka)

RabbitMQ

H2 in‑memory database

Swagger

Lombok & MapStruct

Key Components Demonstrated

Flow engine (responsibility‑chain style execution)

Extension‑point engine for business‑specific plugins

Distributed retry component

Common logging component

Inventory management

Distributed lock component

Redis Lua scripting utilities

Spring context utility classes

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

backend architectureflow enginespringbootprocess chain
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

0 followers
Reader feedback

How this landed with the community

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.