美文网首页程序员
谈谈代码生成

谈谈代码生成

作者: 玩家翁伟 | 来源:发表于2018-07-02 16:19 被阅读76次

    代码生成

    作为程序员,我的理想之一是使用代码去生成代码。

    代码生成可以用于很多场景,其中应用最广泛的,应该是ORM

    ORM

    ORM - Object Relational Mapping,即把程序语言中的对象,映射到关系型数据库的结构上。

    对象属性、表结构都是有清晰的定义;相互之间的映射是可以有固定的规则;如果手动逐个对象、属性写这些映射规则的话,会相当繁琐。

    一般可以使用反射,在程序运行时去判断对象以及属性,然后对映射做不同的处理;但也可以使用代码生成来实现。

    相对于使用反射,我会更喜欢代码生成的方式,因为:

    • 更加容易debug
    • 编译器提供更多的检查
    • 运行性能更好

    IDL

    生成代码的时候,一般也会需要引入一个IDL,即Interface Definition Language,对需要处理的对象结构进行严格的定义描述,然后编译器读取这样的IDL后,再进行输出。

    json、yaml等格式也可以作为IDL使用,但我一般会使用其它更加严格的语言,比方说thriftprotobuf;因为:

    • 不用自己再去发明一套语法
    • 有更多的周边工具可以使用

    使用了很多年thrift做为DSL,我并不使用thrift本身的序列化、远程调用功能,仅仅是借用thrift作为IDL的语法,然后使用现成的thrift parser去生成我需要的代码。

    thrift的开源parser有:python的ptsd,跟go的go-thrift等。

    近两年则慢慢切换为protobuf,主要是因为我发现使用protobuf作为IDL的话,连parser都不需要。

    protobuf的编译器protoc解析protobuf定义文件之后,会把解析结果,以protobuf消息的形式,传递给相应的语言插件,然后由插件再去完成具体的代码生成任务。

    因为protobuf本身支持的语言已经足够丰富,所有protobuf支持的语言都可以用来开发protoc插件;在这里,protoc就相当于一个跨语言支持的parser,它会把解析结果,通过标准输入、输出传递给插件。

    这就带来很大的一个便利性,之前我使用thrift作为IDL的时候,很可能需要go、前端工程师再去掌握python,然后写代码生成的代码。

    使用protobuf的话,go / typescript都可以用来实现插件,分别实现自己熟悉语言的代码生成即可。

    代码生成

    代码生成,需要工程师提高一个抽象层次去考虑自己的代码;以web开发作为比较的话,原本是直接写html就好了,可以直接从html的角度去思考;但引入jsp、PHP甚至是react这样的等“模板”后,就需要隔开一个层次去思考。

    这样“隔开一层”,对于web开发者可能会比较习惯;但对于后端等工程师,则往往会需要有一个适应的过程。

    在源代码内,使用字符串拼接可以做代码生成;但也可以使用模板。

    如果使用go语言开发,使用go内置的text/template库便相当顺手,go 1.6版就专门对此做了增强

    Java的话,则可以考虑stringtemplatefreemaker等 .Net则可以考虑T4等。

    注意,很多模板是针对html做了优化,它们可能特别适合html代码的生成,但用来生成源代码,则就非常不合适,比方说jaderazor等。

    DSL

    严格的说,thrift / protobuf等最多只适合对相对简单的结构、接口定义;而且,它们是对数据序列化做了考量,即需要给每个字段增加一个独立的序号。

    我们若只是用它们来做IDL,不需要考虑版本兼容等问题时,额外写这么个序号其实是不必要的,虽然也不算特别麻烦。

    (对于很多场景,其实使用yaml作为描述语言也是不错;几乎所有的语言也都会带有yaml的parser。)

    thrift / protobuf本身都有一定的可扩展能力,但再怎么扩展,也很难将其扩展成为用来描述领域业务的语言。

    groovy等脚本语言会是DSL更合适的选择。

    相关文章

      网友评论

        本文标题:谈谈代码生成

        本文链接:https://www.haomeiwen.com/subject/cweluftx.html