DEV Community

canonical
canonical

Posted on

Why NopTaskFlow Is a One-of-a-Kind Logic Orchestration Engine

NopTaskFlow is a next-generation logic orchestration engine written from scratch based on the principles of Reversible Computation. Since logic orchestration engines are not new—there are many open-source implementations both domestically and internationally—some may doubt NopTaskFlow’s uniqueness. Why does it call itself a next-generation logic orchestration engine, and what features does it have that others do not? In this article, I briefly analyze the clear differences between NopTaskFlow and existing open-source implementations.

For a detailed introduction to NopTaskFlow, see A Next-Generation Logic Orchestration Engine Written from Scratch: NopTaskFlow

I. Minimal Information Expression

Existing logic orchestration engines are typically written for specific demand scenarios, and as a result often introduce a large number of details that are specific to particular usage contexts. For example, they may depend on the Vertx framework/Redis/RPC frameworks/databases, and introduce specific task queues or schedulers. This greatly limits the applicability of such engines and makes lightweight testing difficult.

NopTaskFlow adopts a design based on so-called Minimal Information Expression. What it implements is essentially a pure set of flow organization rules, without involving any specific runtime environment. In particular, we can execute asynchronous Tasks without starting special thread pools, without relying on task queues, and without relying on a database.

NopTaskFlow is extremely powerful—virtually every design pattern in the logic orchestration domain can be implemented with NopTaskFlow—yet it has minimal external dependencies. We only introduce an external dependency locally when a feature is actually needed. For example, only when a TaskStep must use a database transaction do we introduce an AOP-like transaction mechanism via <decorator name="transactional" />, thereby adding a dependency on the underlying database transaction engine.

NopTaskFlow is well integrated with the NopIoC dependency injection container. You can directly use the NopIoC container to manage complex steps, or use the powerful Xpl template language to implement step abstractions and isolate various external information structures. In other words, NopTaskFlow focuses on how to efficiently organize and orchestrate business logic, whereas how to abstract business logic into a composable function form is not within the scope of what NopTaskFlow aims to solve. Function abstraction is an independent problem, addressed by general mechanisms such as the Xpl template language and the IoC dependency injection container.

Many logic orchestration engines prescribe special-purpose interfaces for integrating external REST services, invoking external scripts, etc. In NopTaskFlow, we do not design bespoke abstractions to accomplish business logic orchestration; instead, we leverage existing encapsulations that already achieve Minimal Information Expression.

For an introduction to Minimal Information Expression, see The Free Path of Business Development: How to Break Framework Constraints and Achieve True Framework Neutrality.

From a mathematical perspective, NopTaskFlow introduces only the necessary assumptions, performs reasoning at a highly abstract conceptual level, and can directly reuse other established abstract rules. Typical logic orchestration engines tend to implement special cases, rely on many unnecessary implementation details during reasoning, and require bespoke adaptation for each special case. Many traditional “standard practices” do not meet the Nop platform’s requirement of Minimal Information Expression. For example, if developing a web service function requires specifying a REST path, or if the same service function cannot be invoked via multiple modalities such as REST/GraphQL/gRPC/message queues/batch engines, then Minimal Information Expression has not been achieved.

II. Rich Structural Layers

NopTaskFlow’s structural layers are far richer than those of typical logic orchestration engines. Most engines provide only a simple abstraction comparable to a Function or Procedure, and often lack completeness and consistency in conceptual details—they basically do not reach the rigor of function abstraction in programming language design—and generally do not support complex nested organizational relationships or secondary abstraction capabilities.

The basic logical organizational unit in NopTaskFlow is the TaskStep, whose definition is essentially an enhanced function:

  1. TaskStep is stateless by design, with explicit inputs and outputs, both of which have strict data types and schema constraints. Many logic orchestration engines design steps as object types, using member variables to implement inputs and outputs, which increases the difficulty of compilation optimization and dynamic model updates. Some also introduce global ThreadLocal context variables, creating unnecessary complexity for asynchronous and concurrent processing.

  2. TaskStep has an internal variable scope, and TaskSteps can form a stack structure, creating a stack-like scope chain. Typical engines only have global scope and step-local scope, lacking control mechanisms for parent-child scope relationships.

  3. TaskStep supports the concept of decorators. Many common features, such as call timeouts and retry policies, can be implemented via TaskStep decorators. This is similar to AOP mechanisms in general programming languages, and can further enhance the function abstraction provided by TaskStep. Most logic orchestration engines lack such a universal aspect enhancement mechanism.

  4. TaskStep supports coroutine-like suspension (interrupt) and resumption (continue) capabilities, enabling failure retries and integrating TCC transactions.

  5. Leveraging the Nop platform’s built-in metaprogramming capabilities allows for macro-like compile-time processing. The Nop platform’s metaprogramming executes at the DSL structural level rather than at the AST level, which is more flexible in form and enables seamless embedding across multiple DSL styles.

For more on metaprogramming, see Metaprogramming in Low-Code Platforms

In NopTaskFlow, we can encapsulate common functionality at multiple layers and choose the leanest abstraction at the most appropriate granularity.

III. Multiple Representations

I’ve noticed that quite a few objections to NopTaskFlow arise simply because it uses XML. It’s 2024—are people still using XML, this “outdated relic”? But such a view of technology is superficial. The Nop platform emphasizes technology-neutral information expression: the same information can have multiple representations, and these different representations can be freely converted.

In the Nop platform, XML, JSON, and YAML support automatic bidirectional conversion. For example, we can define logic orchestration using a task.yaml file:

xmlns:x: /nop/schema/xdsl.xdef
x:schema: /nop/schema/task/task.xdef
steps:
    - type: sequential
      name: test
      steps:
          - type: xpl
            name: step1
            source: >
                return "OK1";
          - type: xpl
            name: step2
            inputs:
                - name: result
                  source: RESULT
            source: >
                return result == "OK1" ? "OK" : "FAIL";
Enter fullscreen mode Exit fullscreen mode

The YAML configuration above is equivalent to the following XML configuration:

<task x:schema="/nop/schema/task/task.xdef" xmlns:x="/nop/schema/xdsl.xdef">
    <steps>
        <sequential name="test">
            <steps>
                <xpl name="step1">
                    <source>
                        return "OK1";
                    </source>
                </xpl>

                <xpl name="step2">
                    <input name="result">
                        <source>RESULT</source>
                    </input>
                    <source>
                        return result == "OK1" ? "OK" : "FAIL";
                    </source>
                </xpl>
            </steps>
        </sequential>
    </steps>
</task>
Enter fullscreen mode Exit fullscreen mode

When defining logic with complex nested structures—especially when metaprogramming is involved—the XML form is often more advantageous than YAML. For an analysis of XML vs JSON pros and cons, see Why the Nop Platform Insists on XML Instead of JSON or YAML

Furthermore, in the Nop platform, visualization is also treated as a representation of information structure (visual representation vs textual representation). Therefore, it attempts to establish a set of automatic inference mechanisms, starting from field-level visual representation <=> textual representation automatic conversions, and then automatically deriving form-level and page-level conversion relationships. This way, a visual designer for NopTaskFlow can be obtained automatically, without writing a specialized visual designer specifically for NopTaskFlow.

IV. Reversible Computation

NopTaskFlow is a concrete instance within the DSL forest defined by the Nop platform. Its implementation makes extensive use of the infrastructure provided by the Nop platform’s XLang language, thus naturally satisfying the principles of Reversible Computation and natively supporting the Delta customization mechanism.

On the Nop platform, all XDSLs share common characteristics, and with the help of the XDef meta-modeling language, their structural semantics can be unified and seamlessly fused. The decomposition pattern implemented by the Nop platform can be expressed as the following formulas:

App = G<DSL1> + G<DSL2> + G<DSL3> + Delta
App ~ [DSL1, DSL2, DSL3, Delta]
Enter fullscreen mode Exit fullscreen mode

Each DSL can be regarded as a feature-decomposition dimension, and the entire application can be regarded as composed of a feature vector plus Delta.

For further introduction to XDSL, see XDSL: A General-Purpose Domain-Specific Language Design

Top comments (0)