Fundamentals 16 min read

Domain‑Driven and Process‑Driven Code Design Patterns

The article proposes a domain‑model‑driven code paradigm—defining clear business models, core domain objects, and infrastructure abstractions like repositories, facades, and factories—while contrasting it with process‑driven designs using ability nodes and chains, arguing that these patterns cut repetitive effort and boost maintainability.

DaTaobao Tech
DaTaobao Tech
DaTaobao Tech
Domain‑Driven and Process‑Driven Code Design Patterns

The article argues that many project activities (requirement decomposition, business modeling, risk identification, etc.) consume excessive effort, and proposes summarizing experience, methodology, and paradigms to reduce repetitive work, focusing on code module design.

It introduces the domain‑model‑driven code paradigm , which first requires a clear business model and then maps that model to software object models. The domain layer becomes the core asset that can be packaged and migrated without being affected by third‑party services or persistence choices.

Key domain model objects are described:

Entity : identified by a stable ID throughout its lifecycle.

Value Object : represents a concept without a unique identifier; equality is based on attribute values.

Aggregation : a group of entities and value objects with a root entity.

To isolate infrastructure concerns, the article recommends:

Repository – abstracts persistence operations for domain objects.

Facade – shields the domain layer from third‑party service implementations.

Factory – encapsulates complex object creation logic.

Domain services act as the “god hand” that orchestrates business logic and are divided into three layers:

Entity Operation Service (BaseUpdateDomainService) – handles low‑level CRUD actions.

Business Process Service (BaseBizDomainService) – aggregates common business flows.

Use‑Case Domain Service (UserCaseDomainService) – implements specific, non‑reusable use‑case logic.

A typical package structure is shown, where the infrastructure module depends on domain , and the domain module contains no third‑party dependencies.

The article contrasts domain‑driven code with process‑driven code , which abstracts capabilities as functions and uses an execution engine to compose processes.

It defines a Java AbilityNode interface for atomic capability nodes:

public interface AbilityNode
{
    /**
     * Execute a rendering node.
     * @param context execution context
     * @return whether the chain should continue
     */
    boolean execute(C context);
}

And an abstract AbilityChain class that manages context creation, serial and concurrent execution of nodes, and result handling:

public abstract class AbilityChain
> {
    @Resource
    private ThreadPool threadPool;

    public abstract C initContext(Request request);

    public Response execute(Request request) {
        C ctx;
        try {
            ctx = this.initContext(request);
            if (ctx == null || ctx.getOrder() == null || CollectionUtils.isEmpty(ctx.getOrder().getNodeNames())) {
                return null;
            }
        } catch (Throwable t) {
            log.error("{} catch an exception when getRenderContext, request={}, e=", this.getClass().getName(), JSON.toJSONString(requestItem), t);
            return null;
        }
        try {
            for (List
nodes : ctx.getOrder().getNodeNames()) {
                List
> renderNodes = renderNodeContainer.getAbilityNodes(nodes);
                boolean isContinue = true;
                if (renderNodes.size() > 1) {
                    isContinue = this.concurrentExecute(renderNodes, ctx);
                } else if (renderNodes.size() == 1) {
                    isContinue = this.serialExecute(renderNodes, ctx);
                }
                if (!isContinue) {
                    break;
                }
            }
            return ctx.getResponse();
        } catch (Throwable t) {
            log.error("RenderChain.execute catch an exception, e=", t);
            return null;
        }
    }

    private boolean concurrentExecute(List
> nodes, C ctx) {
        if (CollectionUtils.isEmpty(nodes)) {
            return true;
        }
        Set
isContinue = Sets.newConcurrentHashSet();
        List
nodeFuncList = nodes.stream()
            .filter(Objects::nonNull)
            .map(node -> (Runnable) () -> isContinue.add(this.executePerNode(node, ctx)))
            .collect(Collectors.toList());
        linkThreadPool.concurrentExecuteWaitFinish(nodeFuncList);
        return !isContinue.contains(false);
    }

    private boolean serialExecute(List
> nodes, C ctx) {
        if (CollectionUtils.isEmpty(nodes)) {
            return true;
        }
        for (AbilityNode
node : nodes) {
            if (node == null) continue;
            boolean isContinue = this.executePerNode(node, ctx);
            if (!isContinue) return false;
        }
        return true;
    }

    private boolean executePerNode(AbilityNode
node, C context) {
        if (node == null || context == null) return false;
        try {
            boolean isContinue = node.execute(context);
            if (!isContinue) {
                context.track("return false, stop render!");
            }
            return isContinue;
        } catch (Throwable t) {
            log.error("{} catch an exception, e=", nodeClazz, t);
            throw t;
        }
    }
}

An execution order can be expressed as a nested list, where inner lists run in parallel and outer lists run sequentially:

[
    ["Ability1"],
    ["Ability3", "Ability4", "Ability6"],
    ["Ability5"]
]

Aspects are introduced to inject cross‑cutting concerns (e.g., tracing, validation) before or after node execution, ensuring the domain layer remains stable despite changes in external services.

In conclusion, applying these domain‑driven and process‑driven patterns at project inception can dramatically reduce the effort spent on module partitioning and improve code maintainability across iterations.

Javasoftware engineeringDomain-Driven DesignAbility Patterncode architectureProcess-Driven
DaTaobao Tech
Written by

DaTaobao Tech

Official account of DaTaobao Technology

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.