谈论代码生成,我们在谈什么

对于代码生成技术,我们希望他能帮我们解决什么问题?

1. 一些逻辑简单的机械式代码,比如大量的get/set(getter/setter)代码
2. 一些稍微复杂的套路式的代码,比如符合某个框架标准的数据库的增删改查代码
3. 同时我们希望生成的代码是没有bug的
4. 不仅希望他能代替我们劳动,而且要求他劳动效率很高,即要快速地生成代码。

最容易生成的就是类似get/set这样的机械式代码。然后是套路式的代码,只要你能手工写一遍,再把它制作成模板也不会很难。

这里需要补充说明一下,对于有数据库操作的软件而言,业务(即业务逻辑,下同)往往由增删改查组成,但增删改查却不是业务,可能带有些业务的“味道”,业务是包含增删改查在内的多种操作的有机组合。

下面我们来谈谈对代码生成器的期望。

高质量

我们希望是无论生成简单还是生成复杂代码,或者从简单到复杂的发展过程,自始至终的生成的代码都没有bug。但是只要是人写的代码,就很难没bug。模板也是一种代码。怎么办?模板具有大量重复使用的特点,所以,一旦模板有bug容易被发现,一旦修复了某个bug,就意味着以后使用这个模板生成的代码都不再有这个bug。这一点跟不使用生成器,手工写代码是不一样的。手工写代码,这次修复了一个bug,难保下次写同类代码不再出相同的bug。唯有借助代码生成,才能无限的逼近零bug。

高效率

相对于手工写代码,机器写代码的速度是飞快的。人平均一秒钟写不了一行代码,机器一秒钟轻轻松松写100行,甚至更多。显然,代码生成能极大地提高软件的生产效率。

模板与非模版

代码生成技术大体上可以分成模板与非模板两大类。他们共同的特点都是要解决死代码和活代码的组织问题,或者说是固定的代码与变化的代码的如何正确地编织在一起,这个问题。比如,这样的模板

print("hello $(name)")

此模板死的部分就是打印功能和字符常量hello,活的部分就是hello后面那个名字。

它可以生成这样的代码

 print("hello billy") 或者 print("hello world") 

在它的外层还可以加个循环从而生成多条print语句。还可以加条件,从而根据条件决定要不要生成某些语句。将数据和模版通过模板引擎的处理,生成目标代码,这个就是基于模板的代码生成的基本套路。

 

为了协调好死代码与活代码,让死代码能表达任意内容,而不会被误认为其中有活的内容。同时模板还要直观、易懂易用。于是形成了各种有效的固定套路,即是模板引擎。所谓模板引擎就是规定了死代码与活代码的边界,并能将死与活组装成目标文档(代码)的一套固化的方法。它通常包括两部分:模板的语法和解析器。我知道的知名的模板引擎有 velocity,razor,T4,各种动态网页也是模板引擎,比如ASP,JSP,PHP,ASP.NET MVC等。其中ASP.NET MVC用的是razor引擎,ASP用的是T4引擎(是吧?)。

而代码生成器有my generation,my generator,easy code等。

 

如今绝大部分的代码生成器都是基于模板的方式工作,像上面提到的三个代码生成器都是。以至于很多人误以为代码生成必然是使用模板的。基于模板的代码生成器,具有简单易上手、出成果快等优点。但要生成复杂的代码,困难比较大。

 

一些复杂的功能,往往需要修改引擎才能支持。更复杂的功能,则需要外建更复杂的扩展机制,或者是另一套引擎配合才能做到。总结,基于模板的代码生成,面对复杂问题时,容易遇到能力的天花板。

 

基于非模板的引擎暂时还没有一个统一的名字。我知道的一种模式是,用特定方式表示的数据结构和流程,再加上一些预先定好的规则进行推理,最终生成代码。除了最终生成的代码是字符串之外,中途都是各种各样的数据结构,唯独没有模板。这种工作方式,更接近于程序员写代码时的思考方式。

 

 

还有一种可能的形态也是用于生成复杂的代码。就是在基于非模板的基础上,在局部范围引入模板。

展望未来

假设我们已经能够生成get/set,已经能够生成数据库的增删改查代码。我们还想要生成什么?我们得换一个视角来看待软件源代码。一个软件的全部源代码,可以看作是包含了从机械式代码到核心业务逻辑代码之间的多个层次。通俗地讲,机械式的代码是最笨的代码,核心业务代码是最聪明的代码。一个软件的全部源代码是各种不同聪明程度的代码的有机组合。

 

 

在代码生成器看来,整个软件的代码可以划分为两部分:能生成的代码和不能生成的代码。越是机械式的越容易生成,越是核心业务逻辑往往意味着代码的变化多端,就越难生成。而代码生成器自身的发展使命就是不断的增大能生成的代码范围,一点一点地把原本不能生成的代码,变成能生成的代码。最终的目标是实现100%的代码都可以生成,即生成一个软件的全部源代码,甚至包括配置文件、部署脚本等辅导文件。

 

生成代码的复杂度,比被生成代码的复杂度,大约高一个数量级。而复杂的代码手写已经很困难了,为什么还要追求生成?原因就是前面提到的质量和效率。

posted @ 2022-03-31 23:58  BillySir  阅读(75)  评论(0编辑  收藏  举报