安利一下我们的项目 dddappp,一个“真”去中心化应用低代码开发平台

这是我们 项目的 deck

我们做的是什么:

Our main project is called “dddappp”, which stands for Domain-Driven DAPP low-code Platform.

However, the “model-driven development” approach we used in this project is not only applicable to decentralized application development. In fact, we’ve been using the same approach to drive the development of traditional enterprise software and Internet applications since 2016.

Kindly note: we’re not making a “no-code” app for end-users, we’re building a low-code platform for developers.

Let me explain a bit more here: there is a consensus (de facto standard) in the industry on what the core features of a Low-Code platform should have. The bottom line is that they must take a “model-driven” development approach. For our discussion of this, see here.

我们想要解决什么问题,以及我们用什么方法去解决问题:

Efficiency in the development of software, especially complex software, has always been a big issue.

We have invented a very expressive DSL for domain modeling called DDDML. Using it, it is not only possible to accurately describe our knowledge of domains, but it is also easy to map these models to software implementation code.

Compared to other competitors, our DSL is much closer to the problem domain and to natural language, which enables it to have great combinability with AI.

我们的项目为何是独一无二的:

Our project is likely the only Dapp low-code development platform that takes a model-driven approach. Why? We’ll provide a brief analysis of this in the attached deck file. The analysis will show that our project is unique. Our project has also received grants from Sui Foundation and Rooch Network. We have already implemented MVPs based on three different Move platforms, Aptos, Sui, and Rooch. We have received very positive and responsive feedback from the Move community developers about our project.

We have used our model-driven approach in the development of traditional applications (generating applications written primarily in Java or C#), as well as implementing MVPs based on three quite different Move platforms (generating Dapps with on- chain Move contracts and off-chain services), which is a testament to the adaptability of our dddappp project architecture.

团队成员:

I work solo, but I don’t let that stop me from being awesome. My team is me, myself and I.

I have more than 20 years of software development experience, DDD expert, DDDML creator, and author of the technical book “Deep into DDD: Driving Complex Software Development by DSL”.

The book was published in April 2021 and reprinted in September of the same year, receiving wide acclaim.

1 Like

先自问自答一番。

我们的项目被挑战最多的问题之一:AI 会把你们这样的“低代码”/“无代码”干死。(有的投资人连低代码和无代码都不做区分,直接用“无代码”来称呼我们要做的事情。)

我的回复:

目前生成式 AI 的兴起🔥,并没有导致复杂软件的开发流程发生大的变化。当然它可以改进某个开发环节的生产率。

马爸爸说:给我做个淘宝 App。

生成式 AI 是有可能生成 10 亿个候选的淘宝 App。

问题是:哪个是马爸爸想要的?马爸爸看得过来不?


我需要再次重复一下我在很多场合重复了无数遍的“陈腔滥调”:

  • “低代码”开发平台则是面向专业开发人员提供服务的。它们可以让开发人员利用模型驱动(这个特性是最根本的)、可视化界面、预定义组件、自动化流程等功能来构建更复杂和强大的应用。

  • “无代码”指的是一大类(没有统一标准的)面向“最终用户”(即非技术人员)的工具。它们可以让用户通过拖拽、选择、填空等简单的操作来创建一些简单应用,比如商品广告页、在线调查表、个人博客等。

我们认为(其实也是业界公认,特别是专业咨询机构对此有一致的认知),一个真正的低代码开发平台应该具备一些关键特性:

  • 模型驱动开发。这意味着开发人员可以使用一种更接近“业务”而非“技术”的“领域模型”来描述他们想要构建的应用。这样可以大大降低沟通成本和理解难度,提高协作效率。

  • (其他特性次之,这里先不谈)……

“低代码”体现的是开发软件——特别是开发“复杂”软件——所理应遵循的“正确”方法:我们应该先做领域(业务)分析,构建可以反映领域问题和大致解决方案的(概念)领域模型……

这个“领域模型”对(业务)问题的理解越深刻,对开发人员具备越高的“可实现性”,软件的整体开发效率就越高。

软件开发是“越到后面修改的成本越高”——这点不管你有没有 AI 的帮助都一样。我们很难第一次就得到“完美的”领域模型——往往需要反复迭代才能逼近,特别对于复杂软件更是如此。而“低代码”方法可以帮助你快速地迭代模型。

也就是说,“低代码”首先是一种软件开发的方法论。我们说低代码平台“应该具备的特性”,指的是这种方法论在实施工具方面的要求。

注意,我说的“模型驱动开发”,不是“模板驱动开发”。现在有些号称去中心化应用的“低代码”平台,采用的是“可配置的智能合约模板”方法,我个人认为这是一种投机取巧的方法。


我在一些活动的 Demo Day 里也反复回答过开发者这样的提问:

AI 是否可以取代“低代码”?

我反问:你认为 GitHub Coplilot 这样的 AI 工具多大程序地提升了你日常的开发效率?

开发者们一般回复是大约 20% 到 30%。

我说:相对我们 dddappp “10x 你的开发效率”的愿景,20% 到 30% 的提升实在是太微不足道——我们在现实中甚至见到过使用低代码方式开发某些“业务系统” 100x 开发效率的案例。

我们认为:目前 AI 技术的进步会为未来的人机交互方式带来革命,我们所熟悉的 GUI(图形用户界面)重要性也许会大大降低。开发人员使用的 IDE 可能也会出现巨大的变化,但是,软件开发的最大成本不是“编码”这个环节的人机交互。针对应用类型选择合适的开发方法,才是提升整体开发效率的关键。

“低代码”是开发(最少是部分类型的)应用的“正确”的方法——那个你应该装备的思想武器。它是“道”,不是“术”。AI 辅助开发是“术”。它们并不是矛盾对立的,是可以相互成就的。(见 deck 最后的部分。)

我们的项目被挑战最多的问题之二:你们这个东西能用来干什么(开发什么样的应用)?现在的智能合约都挺简单的,Web3 / 去中心化应用开发好像不需要低代码平台……

我们的回答:你们觉得不需要是因为以前没有这样的东西。我们的项目是前无来者、独一无二的。它当然不是“适合开发所有类型的应用”,但我们的 MVPs 已经(足以证明这样的方式)可以开发很多类型的应用。Deck 里面提到了一些例子。

所以,请先别急着下结论,体验过后再说。

比如,这是应一个做 Web3 开发者教育的客户的需求,开发的一个以教学为目的的“众筹”应用:GitHub - dddappp/sui-crowdfunding-example

README 里面记录了使用低代码方式的开发过程和测试方法。“快到吓死人”。当然,现在美中不足的是 DSL 的学习成本不能忽略。按照我们的设想,以后应该要有图形化的建模工具或者 AI 辅助建模,那就很完美了——而做这些工作并不难,只是需要一些资源。真正最难的事情,我们已经做完了(我们的 deck 做了分析)。

下面是另外一个教学项目,客户提出的需求寥寥几句:

Build a Simple Token Swap dApp using SUI Move

Overview: We’re creating a basic dApp to allow users to trade one cryptocurrency for another on the SUI blockchain. We need two main components: a smart contract and a simple frontend.

Requirements:

The token swap dApp contract should be straightforward, focusing only on the swapping feature. We don’t need the other DEX features

The smart contract code must include comments to explain how it works.

A basic frontend should be provided for users to interact with the dApp.


大家都知道,太“简单”的需求是很难做的,我的回复:

Let’s further clarify the requirements so that we can better determine the workload in the next step.

From the front-end, the dApp would look roughly like this:

  • First we would display a list of supported token pairs, TokenX-TokenY, TokenY-TokenZ and so on. Of course, at first, this list is empty.

  • Users can “initialize liquidity”. i.e. add a new swappable token pair TokenX-TokenY, by providing some amount of TokenX and TokenY.

  • Of course, after the token pair is initialized, users can continue to “add liquidity” to the token pair.

  • The front-end displays the current account’s share of liquidity in the current token pair where appropriate. Of course, at this point the user should already have connected a wallet.

  • The front-end has a place to show the “token reserves” in a token pair. That is, the amount of TokenX and TokenY are in the pair TokenX-TokenY.

  • For already supported token pair, e.g. TokenX-TokenY, user can “swap” TokenX for TokenY, or vice versa. Each swap transaction is charged 0.3% of the target token as a fee.

  • Users can "remove liquidity ". This means that by destroying their share of TokenX-TokenY liquidity, they can get a certain amount of TokenX and TokenY back.

  • The revenue that the user receives for providing liquidity comes from the fee and nothing else.

From a front-end UX perspective, the main features are those above.

The internal implementation of the smart contract will be kept as simple as possible, as long as it is sufficient to illustrate the basic principles of the DEX using the AMM model.


用中文简单来说,就是,让我们先厘清一下需求,是不是做成下面这样就可以:

  • 前端可以显示支持的币对列表。

  • 用户可以初始化流动性(创建新的可以 swap 的代币对)。

  • 用户可以添加流动性。

  • 前端可以显示当前账号所占的流动性份额。

  • 前端可以显示代币对中的代币储备。在 X-Y 币对中有多少代币 X 和代币 Y。

  • 提供兑换功能。代币 X 换成代币 Y,或者反过来也可以。每笔兑换收取换出代币的 0.3% 作为交易费。

  • 用户可以移除流动性。

  • 用户“提供流动性”获得的收益来自于手续费,没有其他。

以“教程”为目的,实现可以尽可能简单。


客户回复说:非常 OK,就是要像你说得这样。

我非常确信用现在的 dddappp 的 Sui Move 版本,可以做出这样的一个 DEX。

还有一个,全链游戏引擎,可能也是 dddappp 低代码平台很有希望可以挑战的方向。

这是一个全链游戏引擎项目 Obelisk。代码库比较新的提交在开发分支:dev。目前它会专注在 Sui Move 平台,以后计划扩展到其他 Move 平台,以及非 Move 生态的技术基础设施(比如 Solana、Gear 等)。目前它用来生成 Move 合约的逻辑主要在这里:packages/common/src/codegen/utils/renderMove

相对 dddappp 来说,目前已有的实现还是比较简单的。

它们用来生成代码的 schema 类似下面这样:

export const obeliskConfig = {
  name: 'constantinople',
  description: 'constantinople',
  systems: ['rpg_system'],
  schemas: {
    datauser: 'address',
    movable: 'bool',
    monster: 'u64',
    obstruction: 'bool',
    player: 'bool',
    owned_monsters: 'vector<address>',
    catch_result: {
      ephemeral: true,
      valueSchema: 'u8',
    },
    position: {
      valueSchema: {
        x: 'u64',
        y: 'u64',
      },
    },
    encounter: {
      valueSchema: {
        exists: 'bool',
        monster: 'address',
        catch_attempts: 'u64',
      },
    },
    encounter_trigger: 'bool',
    encounterable: 'bool',
    random_seed: {
      singleton: true,
      valueSchema: 'u64',
      init: 0,
    },
    map: {
      singleton: true,
      valueSchema: {
        width: 'u64',
        height: 'u64',
        terrain: 'vector<vector<u8>>',
      },
      init: {
        width: 32,
        height: 27,
        terrain: `vector[
            vector[0,0,0,0,0,0,80,80,80,80,80,80,80,0,0,0,0,0,0,0,0,0,0,80,80,80,80,80,80,80,80,80],
            //...
          ]`,
      },
    },
  },
} as ObeliskConfig;

我们的项目所采用的 DSL(DDDML)的规范,应该是 obelisk 目前具备的 schema(模型)描述能力的一个(大很多的)超集。

也就是说,现在 obelisk 给出的示例游戏项目中使用的模型的语义,如果改为用 DDDML 来描述,也是可以等价地表示出来的——不过,目前的 dddappp CLI 工具如果使用这些模型去生成 Sui Move 合约的话,生成代码的风格和 obelisk 的结果会有一些差异。

比如说,目前 dddappp 生成的代码,为每个“实体(聚合根)”会生成一个 Sui Move 对象的定义(有 key ability 的结构体,外部可以直接通过 objectID 访问);而现在 obelisk 生成的代码中,会为一个 schema 生成一个有 store ability 的结构体,然后这个 schema 的实例(状态)是保存在一个 Table 里的。

不过,只要把现在的 dddappp 工具改一下,增加一些“生成设置”选项,可以生成和 obelisk 一样风格的 Move 合约代码。

在 GitHub 这里,dddappp 用户下的 sui-swap-example,已经可以看到上面提到的 AMM DEX 教学项目的低代码实现版本(部分业务逻辑没有完全填充完,有些 xxx_logic.move 文件中有 todo 说明,但是已经可以 Sui Move Build 编译打包通过了。)

This sounds so awesome!

来更新一下 dddappp 最近的进展。:smile:


原版的 constantinople 是一个基于全链游戏引擎 obelisk 开发的运行在 Sui 上的小游戏。

我们这里尝试了使用 dddappp 低代码开发方式,实现这个游戏的 Aptos 版本,见 GitHub 用户 wubuku 的代码库 aptos-constantinople。(不好意思,好像回复带链接发不出来。有兴趣的可以按照提示去 GitHub 上找一下🙏。)

过程大致就像 README 里介绍的。模型文件写一下,生成代码,在两个文件里面填了下业务逻辑,开发就完成了。编译都可以通过。

这时候,碰到了一个现在工具还没有完美解决的问题:链上合约打包后,包的大小超过了 Aptos 的限制(60k)。这个问题在 Aptos 上开发稍微大点的应用都会碰到。

于是我手动拆了一下项目。把 Move 合约拆成了三个项目。先把这个问题绕过去了。这个手动拆分项目的过程在 README 里面我没有仔细写。(反正接下来我会改进工具解决掉,所以没有介绍的必要的。)

合约以及链下服务(Indexer)的测试过程写在 README 里面了。应该是没啥问题的。

接下来,就是看看怎么改进一下工具。思路是在模型文件里面声明一下模块之间的依赖,直接生成多个合约项目。


obelisk 最近拿到了 Sui 的 grant。其实现在全链游戏引擎做的事情,很多我们的低代码工具已经做过了。这些游戏引擎很大的一部分工作,是链上合约的生成,以及链下的 indexer 服务。我们都做掉了。而且,就模型的 schema 的完善程度来说,目前还完全不能和我们设计的 DSL(DDDML)相比。


这个游戏的数据模型 schema 文件我在上面的有展示。大家可以从它们的 GitHub 代码库中找到。

1 Like

搞定了 Aptos 合约项目拆分的问题。

现在,我们可以在模型文件里面声明“模块”(注意:这里说的模块不是 Move 语言里面的那个模块的概念,是指“领域模型”的模块,可以理解为对象的分组),然后自动生成多个 Move 合约项目。在 Aptos 上开发稍微大点的应用都会碰到包的大小限制的问题,所以对这个问题的解决方案还是很有意义的。

现在大家应该可以根据 README 复现整个游戏的合约和 Indexer 的开发和测试过程了。