You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

191 lines
22 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 11亦敌亦友Low Code与Pro Code混合使用怎样实现
你好,我是陈旭。今天我们来聊聊低代码平台中的纯代码,理一理这对欢喜冤家的恩怨情仇。
一般的低代码平台,总爱宣传自己开发过程需要编码的地方是多么多么少,甚至已经消灭了所有代码。久而久之,不免给人一种感觉,如果低代码平台上还有代码的存在,就会显得很失败。低代码是新欢,纯代码是旧爱,有了新欢,抛弃旧爱,这样可不好。
其实,把低代码平台上的纯编码开发模式视为洪水猛兽,大可不必。编码有编码的优势,毕竟可视化不是低代码的目的,高效率才是。如果高低代码的结合使用可以提升开发效率,哪怕是只能在特定条件下提升效率,那都可以纳入低代码平台的能力范围。
## 为啥还要编码?
最开始,我们思考一个问题,既然可视化开发是低代码平台的特色和卖点,那为啥低代码平台还要提供纯编码入口呢?
你还记得[第3讲](https://time.geekbang.org/column/article/496043)中我描绘的天花板级别的低代码平台吗?其中一条标准和低代码平台的用户有关。天花板级别的低代码平台需要能**支持各种技能水平的人同时使用**。
也就是说,高技能水平的开发者也是低代码平台的目标用户。在这部分用户专业领域范围内的内容,他们更想要采用直接编码的开发模式。除开对这个人群来说,直接编码与可视化开发模式相比的效率因素,一个可能的原因是他们需要有职业获得感,以及出自人性深处的那种“不羁放纵爱自由”的叛逆心理。
我们前面说过可视化模式凝聚了各路专家的经验这个经验约束了你必须先这样做然后再那样做才能获得更好的效率和更优质的App。从另一个角度看就是强制规定了我们开发的套路你只能这么做。这对于领域小白来说当然是很舒服的只要照做就能得到最优解。但高技能水平者往往有自己的见解期望按照自己的思路来实现给他们一个代码编辑功能让他们自由发挥是更好的解决方法。
当然,不见得所有的低代码平台都要做到天花板上去,那发展中,甚至是刚起步的低代码平台,是否就没有纯编码开发的要求了呢?
当然不是。如果说天花板低代码平台的编码模式是锦上添花,为满足一部分人的需要而开放的能力,**但对发展中的低代码平台来说,则是刚需,某些时候甚至是雪中送炭**。发展中的低代码平台由于可视化开发能力不完善,难免出现搞不定的情况,这种情况往往就需要纯编码模式来兜底。
即使在低代码平台成熟之后使用纯代码作为一种兜底策略依然是一种非常好的选择。因为任何事情都逃脱不了二八原则低代码的可视化模式再好也只能适用于80%的场景。剩余的那20%边边角角的场景如果硬上可视化模式反而可能吃力不讨好所以我们把那剩下的20%的场景留给纯代码来兜底,是一种很明智的选择。
因此,无论是在发展中的低代码平台还是已经比较成熟的低代码平台,可视化模式和纯代码模式的混合开发,都是有很明确的需要的。
说到采用纯代码方式来实现兜底策略我在这里自爆一点我们低代码平台Awade的黑料。我在[第7讲](https://time.geekbang.org/column/article/499824)中介绍了Awade的结构化代码生成法它有一个很重要特点就是可以生成和人类手写的代码相似的、人能读得懂的代码。多数低代码平台并不会考虑生成对人类友好的代码为啥Awade要这么做呢
这是因为在MVP的初期我们内部对Awade提供的可视化模式的端到端交付能力还心存疑虑我们也不确定它能不能搞得定。于是心想如果人能读得懂、改得了Awade生成的代码那万一开发哪个App时Awade搞不定起码我们还能把代码导出来手工继续完成剩余部分不至于烂尾。
后来的事实证明我们的担心完全是多余的Awade提供的可视化模式可以很好地应对各种App的开发需要。即使如此它能生成对人友好的代码的特性并没有浪费这个特性让Awade可以实现高低代码模式的无缝切换这一点我们等会儿还会再说。
## 高低代码如何混合开发?
要注意,在我自爆的黑料中,我们原本打算使用的可视化模式搞不定时就人工接着搞的方式,实际上也是一种高低代码结合的方式(高代码指的也就是纯代码)。只不过,这是一种很无奈的、很被动的混合方式,甚至可以说是一块遮羞布。
那么,低代码平台如何优雅地实现高低代码混合开发呢?
在前面几讲中,我已经多次提到,低代码平台的开发过程是有代码参与的,代码是低代码平台的副产品,所以在低代码平台上能否实现高低代码混合开发,从来就不是一个问题。真正的问题在于**要不要开放纯代码接口**,这一点我们前面已经给出结论了。另一个问题是**如何实现混合开发**,这正是我们现在要讨论的问题。
形形色色的表达式是高低代码混合最常见的一种方式了,因为这是可视化模式的主要盲区。表达式的作用,往往就是作为一个小功能点,而如果我们用可视化模式实现一个真假表达式这样的小功能点,就像是拿大炮打蚊子,性价比极低。
可视化模式更适用于实现连续性的、复杂的逻辑。一个实际的App会包含许多这样的大块逻辑并且这些大块逻辑之间充满了缝隙需要使用表达式来“粘连”在一起。比如下面这个场景就是一个很好的例证
![图片](https://static001.geekbang.org/resource/image/4b/ca/4b8a44ed119b3346a36ebb9af2188dca.png?wh=1025x367)
这个图展示的是用可视化方式编排一个逻辑判断的功能。我们都知道,逻辑判断功能最关键的一个点是要判断真假,但是用可视化方式来编排出真假的结果,却并不容易。因此,这个例子中,我们直接就让应用开发人员填写一个表达式,这个表达式将用于计算出这个条件的真或假。这个例子给出的混合方式非常自然,即使是没有多少开发经验的应用,也能很快掌握。
还是同一个例子,我们来看看采用纯可视化的方式是如何来完成真假判断的:
![图片](https://static001.geekbang.org/resource/image/79/fa/79ca958f0ab12f1b5efd60b6644b92fa.png?wh=771x319)
这张图是在判断一个数组是否为空即长度是否为0可以看到纯可视化方式在这里就显得啰嗦一些了这样的一个表单最终只生成了 array.length == 0 这样一个表达式。
那么常见的表达式还有哪些呢?除了真假表达式外,还有三目运算、正则表达式、求值表达式、逻辑运算、数值计算等,很多,我就不一一列举了。
这些表达式都很适合与可视化模式混合使用,不仅可以作为可视化模式的有用补充,在生成代码时,往往还起到直接表达业务逻辑的关键作用。表达式与可视化混用是如此常见,以至于如果我不指出来,你也许都不会注意到这也是一种混用场景。
也许你会反驳:表达式不算是高代码。那接下来,我们就来说说有点“代码含量”的情形:代码块。
可视化编程是可视化模式中最难做好的一个功能点。在上一讲中,我给出了一种通过形象化的方式来表达和编排程序逻辑的方法,但是那种方式主要是给程序编程能力很弱的人使用的,一般能写点代码的人会更乐意直接编码。
我认为,**代码块就是可视化编程功能中实现高低代码混合的最好方式**。我这里说的代码块指的是若干行完整代码组成的、有特定功能的程序块一个函数可以包含一个或者多个代码块。比如下面这个示例图中就包含了3个代码块
![图片](https://static001.geekbang.org/resource/image/91/5a/91aff06137f5c8a52549a15820910c5a.png?wh=696x437)
在一个完整逻辑流程中,可视化逻辑块和代码块可以按需地交织混合在一起,如下图:
![](https://static001.geekbang.org/resource/image/8a/yy/8aa21cdyy1e37a55c46b62561693d8yy.jpg?wh=1207x358)
图中橙色块就是纯代码块,其他块则是可视化逻辑块。这种混合方式完全是由应用开发人员按需编排出来的:有可能是开发人员觉得某个功能使用可视化块效率更高;也有可能是他不知道如何写出符合预期的代码块,而不得不用可视化块;还有可能是没有合适的可视化块,而不得不使用代码块顶替;甚至有可能随编排时的心情状况随机挑选了一种方式。总之,可视化编排器需要能支持这样一种高低代码混合的方式。
也许你还要反驳:代码块的“代码含量”依然不足,不能算作高低代码混合。
那接下来我们就说说纯度达到24K的高低代码混合方式。表达式也好代码块也罢都是在可视化模式为主导的开发流程中使用少量代码作为辅助的方式也难怪会被质疑这样的方式不是纯编码。
那“代码含量”纯度为24K的开发方式是啥呢总不能和我前面自爆的Awad黑料一样把App整个工程的代码都生出来让应用开发导入到VSCode这样的IDE继续完成剩余的开发吧
揭开谜底之前我先介绍一下我为切分App工程代码设定的粒度**模块**。一个完整的App工程由多个模块组成
![](https://static001.geekbang.org/resource/image/13/c2/130fdf5d868dd43b658e87e274376dc2.png?wh=1664x974)
你可以从这张示意图中看到:
* 一个App工程至少包含一个模块也就是图中最中间的启动模块启动模块有且只有一个
* 模块有多种不同的类型而且各类型模块的数量按照App所需创建
* 模块是App工程的唯一一种粒度。
其实还有几点要注意,不过这几点与这讲内容关系不大,所以我没有画到这张示意图上,但作为模块的重要知识,我们略微扩展一下:
* 模块之间可以相互引用,一个模块可以引用多个其他模块,也可以被多个模块引用;
* 启动模块由框架直接引用;
* 模块是实现SPA单页面应用、应用自定义组件等的重要入口。
为了减少App开发的学习成本我吝啬地只用了模块这一种粒度它承载了切分App工程、实现App代码复用、做各种关键功能入口的职能。关于模块如何做到如此复杂的职能、但又以极轻量的面貌展示在App开发人员面前如果你觉得有需要详细说明可以在留言区留言有需要的话我会用专门一讲来介绍。
好了收回来。介绍了模块后不需要我多说你应该已经猜到了我所说的“代码含量”纯度为24K的开发方式就是按需将一个模块的开发方式从可视化方式切换为纯代码模式
![图片](https://static001.geekbang.org/resource/image/ac/e4/ac6372cafb4a83200f3eeb1876ff4ce4.gif?wh=1010x566)
上面动画演示了将当前模块的开发模式从可视化模式切换为纯编码模式的过程。通过这样的操作方式将一个模块彻底转为纯编码模式之后App开发人员就可以按照纯代码的方式继续完成这个模块剩余的开发工作了。
由于这里我生成的代码是基于Angular的因此App开发人员必须严格按照Angular的方式来编码。他可以按需创建新的Angular组件或者引用已有的组件来完成他剩余的开发工作。这是一种非常纯粹的编码开发模式了。
> 提示如果你熟悉Angular你会发现我这里提及的“模块”这个概念和Angular里的“组件”的概念是对等的。
特别需要注意的是,**切换成纯编码模式这个动作只影响当前模块**其他模块依然保持原有开发模式。并且通过纯编码开发的模块可以继续被其他模块引用它也可以继续引用已有的模块。也就是说从App整体来看它的开发模式就出现了高低代码混合的局面。
## 高低代码如何混合编译?
老生常谈,我再强调一遍,低代码平台的开发过程是有代码参与的。因此,如果低代码编译器能够生成对人类友好的代码的话(方法见[第7讲](https://time.geekbang.org/column/article/499824)),把一个模块切换为纯编码方式的难度并不大。难的是**如何实现高低代码混合编译,进而实现高低代码所见即所得的效果。**
接下来我们就来简要说说如何实现,限于篇幅,只能把思路说清楚,而无法给出代码级的指导,如果你实现过程碰到了什么问题,欢迎在留言区提问。
我在[第6讲](https://time.geekbang.org/column/article/498769)的“生成代码总体流程”的部分有提到如果低代码平台实时渲染视图采用的是直接法也就是直接生成浏览器能识别的代码并渲染出视图实现高低代码混合下的所见即所得效果就会非常麻烦。反之如果采用的是间接法即先生成某种MVVM框架下的代码再实时编译成浏览器能识别的代码并渲染视图的方式实现所见即所得则会简单许多。
![](https://static001.geekbang.org/resource/image/16/23/162393465827247f4485099a95537a23.png?wh=1406x1296 "间接法下从代码到视图的流程")
从实现的流程图上看,采用间接法时,高低代码混合模式的编译流程几乎是一致的,因此实现起来非常容易。这个流程图是以代码为视角来画,如果改从所见即所得效果的实现过程来看的话,这个图应该进一步细化为这样:
![](https://static001.geekbang.org/resource/image/88/6b/88b4844e03d0369c589120306fdc506b.png?wh=1112x1376)
这张图中指出了各个关键环节之间采用了哪个编译器来处理:
1. 编译开始于用户配置数据SVD使用低代码平台的编译器awadec将SVD编译成TypeSript代码
2. 如果是纯编码模式则不需要awadec的编译手工敲出来的就是TypeSript代码
3. 接下来使用tsc编译器将TypeSript代码编译成JavaScript代码
4. 再调用Angular或者其他MVVM框架的JiT编译器将JavaScript代码编译成组件描述符
5. 然后交给MVVM框架的渲染器它会生成DOM并驱动浏览器渲染成视图。
其中第3步将TypeSript代码编译成JavaScript代码的这个过程目前看只有你使用Angular才会有虽然Angular也支持JavaScript风格的API但官方不建议使用。因此我建议你采纳这个建议先生成TypeSript代码。
如果你选用的是React那虽然没有TypeSript转JavaScript这步但要多出将JSX转成JavaScript的步骤。如果你选用了Vue2就不用将TypeSript/JSX转JavaScript了但现在Vue3也拥抱了JSX又需要有这一步了。
之所以把这个过程写得这么详细主要是因为为达到所见即所得的效果代码从编译到视图实时渲染的全过程都有非常高的性能要求。因此建议你和我一样将整个编译过程全部前置到浏览器中完成。但这样做就需要摸索出如何在浏览器中完成这所有步骤的方法了。其中TypeSript转JavaScript的详细方法我整理成了一个PPT放在[这里](https://jigsaw-zte.gitee.io/how-to-architect-a-low-code-development-platform/%E5%9C%A8%E6%B5%8F%E8%A7%88%E5%99%A8%E4%B8%AD%E6%9E%84%E5%BB%BA%20TypeScript%20%E7%9A%84%20JiT%20%E7%BC%96%E8%AF%91%E6%9C%8D%E5%8A%A1.pdf)。你需要的话,可以参考。
而从JavaScript代码一路到浏览器视图渲染之间的步骤我这里就不详细展开了。这部分和MVVM框架选型有直接关系我用的Angular考虑到在国内Angular是小众因此我的经验不一定是你需要的。当然你也可以在留言区留言如果很多人都需要的话我可以专门找一讲来说清楚这部分的难度其实还挺高的。
这部分的最后,我直接回复一下一个我被问了无数次的问题:**一个模块被转为纯编码模式后,还能再回退到可视化模式吗?**
答:不可能!可视化编程总是要有一些条条框框来约束的,而一旦转为纯编码模式后,等于放飞了思维,人的思维有多复杂,就有可能写出多复杂的代码来。因此一旦冲出了可视化编程设定的条条框框,就再也收不回去了。
追问:**那有没有办法给出一些约束条件,在满足约束条件前提下可以再回退到可视化模式?**
答:目前我还没仔细去思考这个问题。如果给出很强的约束那当然是可以的,但人的行为是不可控的,因此不可能给出太强的约束条件,我们需要设定出一些对人类非常友好的、简洁的规则来。关键原因是,目前我们没有这样的需求,使用可视化模式+代码块已经可以完成绝大多数的开发需要。
## 如何提升编码体验?
编码体验是纯代码模式下一个绕不过去的话题,这个话题往往是你好不容易走通了高低代码混合模式后,欣喜若狂之时的一盆冷水。
从高低代码混合的功能来说编码体验不能算是一个问题但在实际编码过程中如果没有代码智能提醒、补齐、出错提醒、全局搜索、重构等功能想象一下这还算是在写代码吗现代的编码IDEIntelliJ/WebStorm/VSCode已经把纯代码开发开发人员的胃口给伺候得极其刁钻了。
在低代码平台上的高低代码混合开发即使在编辑一个表达式至少也就需要有智能提醒、补齐、出错提示了。如果使用了代码块的混合方式那么这方面的需求比较强烈了。到了模块级的纯编码那此时的编码体验的要求就基本和Web IDE甚至和Native IDE相似了。难道要求我们在低代码平台上做一个VSCode出来吗
怎么办?我们分成两种情况来讨论。表达式和代码块属于比较轻量混合,我们放一起讨论,而模块级的纯编码混合方式作为另一个情况单独讨论。
表达式和代码块对编码体验的要求其实已经不低了,但还没到非常极致的情况,因此只要有一个足够强大,扩展性足够强的编辑器,应该就可以应付。
这方面我走过一些弯路,过程直接跳过,我直接告诉你结果。我最终选择了[Monaco](https://microsoft.github.io/monaco-editor)这个开源编辑器即使你没听说过这个名字你也有可能已经是它的深度用户了它就是VSCode的底层编辑器。功能自不必说主要是扩展性极强可以玩出非常多的花样所以我们引入Monaco编辑器用于应对表达式和代码块场景的编码体验就完全足够了。
不过模块级的纯编码混合方式对编码体验的要求就非常高了基本和IDE在同一层级了。此时有两种可能的选择一是继续基于Monaco编辑器为它加上各种功能和扩展深入将它融入低代码平台。这样做的好处是集成度非常好低代码平台提供了一站式的开发体验。代价也是显而易见你需要投入大量的资源来扩展和定制Monaco编辑器把资源投入在这个方面是低代码平台所需的吗
另一个可能的选择是把球踢给某个IDE比如VSCode我们需要的功能这些IDE已经都有了而且做得已经足够好了我们只需要想办法利用这些IDE即可。
那如何做到平滑地复用呢插件任何现代IDE都支持插件。所以我们可以基于某个IDE做个插件用来从低代码平台过渡到Native IDE上。这个方式的成本比较低具有很高的可行性但缺点就是集成度不是很好。特别是在各个App开发人员的电脑上安装Native IDE和插件有可能会有一些不必要的困难。
## 总结
今天这讲,我们详细讨论了低代码平台式的高低代码混合开发模式,“代码含量”从低到高分别是表达式、代码块、模块级。总体来说,高低代码混合的开发方式是低代码平台上非常有必要的能力,特别是需要对表达式、代码块这两种混合方式提供良好的支持。无论低代码平台处于哪个发展阶段,刚起步也好,已经成熟也罢,我认为低代码平台对表达式和代码块的混合的支持都是必须的。
表达式和代码块这两种高代码开发方式,在低代码平台上的实现方式是相似的,都是以可视化的低代码开发流程为主。在可视化方式的不可达或者友好的位置,使用表达式或者代码块来填补,两种方式可以非常好、非常自然地融合在一起。而模块级的编码模式,则是彻底丢弃可视化模式,转为纯编码开发方式,尽管如此,在纯编码开发的模块也可以和可视化开发的模块混合使用。
在完成了高低代码融合之后编码体验是我们不得不面对的一个问题。好的编码体验可以提供更高的开发效率减少试错的次数和避免部分低级问题。但要获得好的编码体验并不容易虽然我们引入Monaco这样的编辑器可以利用其强大的基础功能和扩展能力来有效提升编码体验但是需要有一定的扩展的工作量。
我建议你使用Monaco编辑器来解决表达式和代码块的混合。而模块级的纯编码模式虽然Monaco编辑器也能搞得定但是扩展工作量会很大还不如牺牲一些集成度给VSCode等Native IDE做插件从而最大化利用这些Native IDE的已有能力。
虽然这讲到这里的篇幅已经非常大了,但是这个话题依然还有许多必要的内容没能讲到。包括:
* 高代码模式下如何处理存量代码?
* 如何扩展Monaco编辑
* 如何开发VSCode插件
* 如何处理好第三方依赖?
后续等有机会我们再翻出来说清楚这些内容。
## 思考题
你认为提供模块级的纯代码开发模式有多大的必要性?请结合你的场景聊聊你是怎么看的。
欢迎你在留言区写下你的想法下一讲我们将会来讨论App开发过程中数据配置的问题。我是陈旭我们下一讲再见。