站在Serverless肩头,思考下一代云研发架构模式

本文转载自公众号“Phodal”,希望给云架构从业者们一点新思考。

机缘巧合之下,我了解到 Nocalhost 工具 —— 一个云原生的云开发环境工具。就个人而言,看到这个工具的第一眼我是非常兴奋的。终于,我的云研发理论体系(《云研发:研发即代码》)又迎来一个历史时刻。

简单来说,Nocalhost 只是做了一件简单的事情,把本地的开发环境放在了云端。但是呢,结合最近非常火热的无代码/低代码开发,又或者是各类的代码生成,以及我和同事正在设计的 Datum 语言(原 Charj),顿时间我领悟到了一种新的、未来的、下一代的架构模式。尽管,理论体系还不是非常完善,但是我暂时称之为 Water。原因是形将不重要,代码不再需要形了。

Water 编码架构,即人类编程的产出不再是编程语言这一类型的字符串,编程时只是这种架构模式在 UI 上的呈现,其最终的存储的形式则是:一系列的代码的中间形式,如 AST、HIR、MIR 等。而代码不再被操作系统及文件系统束缚,它们可以交由更小粒度的架构因素控制,即函数。代码不再需要以文件的方式存储,系统的架构不再是按目录划分的分层架构。

太长不读版:GitHub:https://github.com/phodal/water

第一个版本架构图

站在Serverless肩头,思考下一代云研发架构模式

实时开发环境:即开发环境由 AST 呈现的编辑器/IDE + 浏览器组成。

语言无关编辑器

  • 呈现。接收通用 AST,以编程语言的方式重现代码
  • 交互编辑。与人类进行交互
  • 语言无关。以任意语言展示和编辑

数据传输:二进制中间 AST

云环境:由云原生 Dev 云 + 架构引擎 + 语言数据库组成。

架构引擎

  • 操作系统无关。脱离操作系统的文件和文件夹进行架构规划
  • 自动化架构。自动语义规划架构
  • 类-图数据库展示(TBC)。

编程语言数据库(TBD)

云原生 Dev 云

  • Dev Online。云原生的本地开发环境,即开发即部署
  • Prod Readly。随时可部署 + 上线

引子 1:无代码与云研发

代码的复杂度,同力一样不会消失,也不会凭空产生,它总是从一种形式转为另一种形式。

2019 年,因为中台的火爆 + Serverless 的崛起,我写了一篇很长的文章在介绍如何设计《无代码编程》。在这两年的时光里,出现了越来越多的所谓的『低代码平台』,但是它们并非是我所想的类型,缺少关键性的 DSL 抽象。不过呢,无代码系统架构的设计和本文的主题并没有太大的关系。但是呢,它们掀起了开发人员对于云端开发的浪潮。

云设计。如 BeeArt 将大量的设计工作搬到了云端来完成。

云 IDE。如 VSCode Remote、Eclipse Theia,它们可以将新的应用部署到远程开发。

云开发环境。如 Nocalhost,它们可以解决存量系统的云端开发问题。

……

不过,这里我们要举一个反面例子:『云主机』,这中远程开发模式可不是云研发。从本地 IDE 到云 IDE,本地设计软件上云等等的一系列效率工具的云迁移,它将使得我们在未来在云上(浏览器端)完成整个研发。而对于我们这些开发人员来说,重要的不是结果,而是如何去实现这样一个架构。

引子 2:代码架构与操作系统

分层架构就是建文件夹。

接着,我们来说一些更有意思的事情,代码存在的形式。在现今的软件开发中,我们以目录作为边界来设计分层架构,以文件作为代码的载体。而这种形式存在的一个主要原因是,我们开发时依赖于操作系统的存储:文件系统。对于文件系统而言,文件和树形目录的抽象逻辑概念便是人类所能接受的概念。

分层架构 vs 模块 vs 包

如果你熟悉 Java 语言的话,你会发现操作系统限制了 Java 语言的软件架构。一个主要的特征就是包,即目录即是包, com.phodal.water 对应了 com/phodal/water。而到了今天我们习惯了使用目录这种机制来进行包管理。如在最近几年开始流行开来的整洁架构,它是一种圆环型(or 洋葱式)架构,它就受限于目录的影响,使得系统最后的实现并不是那么直观。

(ps:由于篇幅所限,这里就不展示作更详细的介绍了。)

如果你对于整洁架构又或者是分层架构不是非常了解,那么你可以参考我之前相关的文章和开源项目:

  • 《整洁前端架构》

https://github.com/phodal/clean-frontend

  • Layer Architecture

https://github.com/phodal/layer-architecture

文件 vs 类

在 Unix/Linux 系统中,一切皆文件。

对于编程语言来说,我们常用的好习惯是:一个类只在一个文件里。尽管对于 Java 以外的语言来说,并非如此,但是这样实现易读、易维护。与此同时,我们也习惯于将相似的行为构建在同一个类中,即富血模型。因此,在那本开源电子书《系统重构与迁移指南》,我一直在说服人们这样去做。

过去,我们一直局限于文件的规则。所以,让我们考虑一下问题,如果我们可以脱离操作系统呢?如果说,我们不带用文件来约束类,那么就不需要这一类规则。

引子 3:代码的中间表示

为了实现上面的一系列概念,我们需要重新设计整个系统,其中的一个关键部分就是:代码的中间表示。如果你熟悉编译原理的话,也就懂了,只有给人的时候,才会以编程语言的形式出现。

开发态

对于我们来说,只要我们看到的是易于阅读的代码,它是中文的、英文的,又或者是甲骨文都不重要。反正,我们写的代码是给自己看的,这些字符最后会经过层层转换为特殊的格式。

而在 IDE 与编辑器里,为了实现对于编程语言的高亮、智能感知等的支持,需要重新实现语言的类 AST 解析。如 VSCode 里的 LSP,Intellij IDEA 中的 PSI,Textmate/VSCode 中的 textmate 高亮语法等等。

所以,让我们思考一个问题,如果我们是以类 AST 的形式存储的话,那么我们就不需要实现这一类解析。它们只需要在展示的时候,将其转换为人类所熟悉的编程语言即可。

编译态/运行态

在和同事一起设计 Datum(原 Charj,更名为 Datum)语言的半年期间,我分析了市面上主流的一些语言的中间表示,如 Python 和 JVM 的 bytecode,Rust 的 MIR 等等。它们就是各种中间表示,但是相差并不是非常多,原理也是类似的。它们都是由上一步的 AST 转换而来的,以接近底层的方式重新设计。

这一个时候,还引发了一个更有意思的问题:如果某部分代码没有变更的话,那么我需要重新编译吗?既然某一个特定的部分没有办法,那么它就不会发生改变。

与此同时,一个更有意思的事情是,所有的修改只需要打个 patch 即可,应用再重新运行。

新代码架构:water

编程语言是写给人看的代码,写给机器运行的机器码。

基于上述的思想,我们可以设计新一代的代码架构:water。因为代码的形态已经不再重要了,用什么语言写也不再重要了,只需要一个统一的后端(编译器后端)即可。让我们先给出第一个版本的架构定义:

Water 编码架构,即人类编程的产出不再是编程语言这一类型的字符串,编程时只是这种架构模式在 UI 上的呈现,其最终的存储的形式则是:一系列的代码的中间形式,如 AST、HIR、MIR 等。而代码不再被操作系统及文件系统束缚,它们可以交由更小粒度的架构因素控制,即函数。代码不再需要以文件的方式存储,系统的架构不再是按目录划分的分层架构。

从上述的定义来看,它具备以下的特性:

语言无关。因为存储的形态是 AST 形式的 DSL,所以开发人员可以用任意的语言开发。如 A 使用 Java 语言开发,B 使用 JavaScript 语言开发,它们在存储时将可以转换为统一的 AST。而 B 程序员在自己的编辑器上使用的是呈现语言,所以 B 看到的 A 写的代码可以是 JavaScript,而不再需要是 Java 语言。再理于 Java 程序员 A,A 使用的是 Java,它可以选择的呈现语言是 Java,所以哪怕一个 C 程序员选了 Golang,它也将看到的是 Java 的呈现。(PS:当然了,这只是理论上,还有诸多的问题有待解决。)

细粒度权限管理。现今的代码管理机制之下,对于开发者权限的管理是以代码库为单位的。但是在新的架构模式之下,它可以控制到函数的级别。主要是由于代码已经变为了数据,开发人员只编写模型和行为。它还能实现再更细的粒度上,结合我司大佬提出的 Typeflow 的思想,就可以控制到函数的粒度进行权限管理。即特定的开发人员,只拥有修改某一特定业务代码集权限。

自动化架构。经典的架构机制依赖于文件夹的定义,相似行为和功能的代码以文件夹(也称之为包)的形式统一。而当我们消除了架构中文件和文件夹的概念之后,每个模型及其行为以新的形式存在。试想一下在图数据库中,我们如何去表示数据及其关系,那么它就可以不断自动地优化架构,如基于聚类算法实现自动包定义。

一切皆数据。在 Unix/Linux 系统中,一切都是文件。而到了云时,一切都是数据。尽管,从某种意义上来说,文件也是数据的一种。代码本身也是数据。

其它一些有意思的内容:

语言数据库。当我们把编程语言转换为数据之后,我们面临地挑战有两个:数据的形式以及如何存储?即使在 5G 的场景之下,我们也需要考虑一下 4G 网络传输的问题,那么传输的介质可能是某种二进制形式的包,如 Android 里的 dex 包的形式,并带有其它丰富的信息。

编辑态优先。脱离了语言的限制之后,这种架构模式之下,我们还要考虑的一大因素是:编辑器/IDE 上的呈现与交互。我们需要实现快速其的编辑与反馈,因此编辑态优先。

还有其它一些有意思东西,我们可以想象一下。

超越 Serverless

于是乎,我们能联想到另外一个有意思的概念是 Serverless。

Serverless 架构是指大量依赖第三方服务(也叫做后端即服务,即“BaaS”)或暂存容器中运行的自定义代码(函数即服务,即“FaaS”)的应用程序,函数是无服务器架构中抽象语言运行时的最小单位。在这种架构中,我们并不看重运行一个函数需要多少 CPU 或 RAM 或任何其他资源,而是更看重运行函数所需的时间,我们也只为这些函数的运行时间付费。—— 《Serverless 架构应用开发指南》

而我们整个新架构的部署模式与 Serverless 是非常相近的,而我们系统还是一个完整的整体,可以不依赖于大量的线上服务。由于编译与开发一体,我们完成开发的同时,便完成了部署。从某种意义上来说,water 架构会比 Serverless 更快,还更适合于复杂架构应用。

PS:我将会用一篇新的文章来介绍这种模式。

模型-行为-分离

行为是围绕模型而构建的,在整个的机制之下,代码已经不再受模型的限制。接着,我们要解决的总是就是数据库的问题。

现今,我们的编程语言受限于模型,而模型受数据库影响。在这个情况下,如果我们不依赖于模型,那么我们需要设计一种新的机制,以让我们脱离数据库的束缚 —— 那大概只能发明一种新的数据库了。

回过头来看,数据库本身也是一种数据。那么,从现有的论文里去寻找一种更好的数据模式,也就变成了一件非常有意思的事。

其他

关于这个新的架构模式,我还在研究和思考中,未来依旧有很大的不确定性。但是,它真的非常好玩。

欢迎打开钉钉App,扫描下方二维码,到“ECS交流群”钉钉群讨论和研究 ↓↓↓
站在Serverless肩头,思考下一代云研发架构模式

上一篇:数据中心在支持5G的世界中的角色不断演变


下一篇:精通Spring Boot —— 第十五篇:使用@ControllerAdvice处理异常