先祝大家新年好
原文见:Code Generation FAQ
注:本文翻译未经过任何许可,仅用作学习,请勿用作商业用途
代码生成是什么?
代码生成是使用程序生成代码的一种技术。这些程序包括从很小的帮助性质的脚本,到创建大量完整应用程序中的业务逻辑模型。对于代码生成应用软件,并没有一种固定的模式,可以使用命令行或者GUI,它们可以创建一种或多种程序语言的代码,可以多次创建代码。没有固定的输入和输出。代码生成的共同的特点就是生成器的输出是代码,这些代码是可以通过手工编写来完成的。
代码生成有哪些好处?
代码生成技术的带来的好处可以总结为四个方面:
1. 质量:通过代码生成器生成的代码的质量是由用来生成目标代码的代码和模版的质量决定的,当这些代码和模版的质量提高时,重新生成的代码的质量基于此也会提升。
2. 一致性:由代码生成器生成的代码有很强的一致性,变量命名,方法命名,类命名都通过相同的方式创建。这些使得生成的代码便于使用和分层。
3. 生产力:当代码生成器第一次运行的时候,对于代码生成技术的这一好处是很容易认识到的。你从输入一些对输出代码的设计中所需的输入开始,几乎就在同时,你得到了你的设计所实现的代码。无论怎样,真正的高效率就在你运行生成器来创建基于设计的代码时就开始了。你有几次看见一个项目的需求没有变化过?这就是基于变化的需求生成代码的能力。
4. 抽象:一些生成器基于目标代码的抽象模型来创建代码。比如:你可以创建一个sql Schema 和数据访问层代码,从xml中定义数据库中的表,字段,关系和查询。这种抽象的价值在于生成器可以重新定位以创建其他平台上的代码。这意味着你的业务逻辑和规则拥有了可移植性。而你不必为不同的平台编写代码。
对于代码生成,为什么会有正反两种观点
正面的一个观点就是代码生成在短期内提供了很多的好出。“神”经常会在工程完全理解了代码生成对他们所面对的问题的益处的时候。就象面向对象来到时的‘a-ha’一样。这样很容易造成一种“找到了银弹”的想法,但是时间不久,就在不同的方向上出现了错误。代码生成应当用在合适的地方。
相反的,有一些工程师被代码生成刺痛了。他们或者使用着生成器,或者使用着生成的代码,而这些代码正在慢慢的腐化,或者他们开发的生成器并没有实际应用起来。不管什么原因,一些工程师确实不喜欢代码生成。
代码生成的工作流程是怎样的?
根本的软件开发流程就是:写代码-编译-测试。我们写下一些代码,然后编译(如果需要的话),然后测试,如果需要变更就重复这个周期。代码生成的流程依赖于使用主动的或被动的代码生成。主动代码生成器创建的代码,你可以不再编辑它们,或者你可以编辑特定的部分使其看起来就象是生成的一样。被动代码生成器一次创建代码,然后你自己来编写核心的内容。
被动代码生成的工作周期就是:运行生成器,然后对生成的代码遵循编写代码-编译-测试的流程。
对于主动代码生成器,你先运行生成器,然后编译,测试输出。在这一点上,如果你在生成的代码中发现问题,你可以修改模版或者改变生成器的输入来重新生成。如果问题是出现的手写代码部分,再遵循编写-编译-测试的流程。
什么是主动和被动生成器?
主动生成器创建的代码你可以不用修改或者只修改那些在再生成周期内依然是安全的特定的标记部分。主动生成器的目的在于对于不同的输入产生相同的输出。
被动生成器一次创建代码,然后交给你去维护以使代码可以长时间运行。
被动生成器在开始的阶段是高效的。但是主动生成的益处-代码维护和可以修改模版中的bug,在被动生成中丧失了。
什么东西使用生成器生成?
代码生成器可以用在很多不同类型的应用软件开发中。最常用的在数据库访问和用户界面上。
最多的是用在数据库访问方面,因为数据访问的代码是重复性非常高的。另外,生成数据访问层为提供了技术平台的可移植性和平台可移植的益处提供了标准。
用户界面编码也有很大的重复性,所以它也成为生成器的通常的目标。另外,一个用户界面生成器也可以提供多方面的实现,比如针对同一份定义,生成胖客户端和瘦客户端。
生成器的下面是什么?
象许多种技术一样,代码生成也有正反两面,在你实现类似工具的同时,你应当确定已经掌握了这些要点。
1. 文档和训练:你需要代码生成器的文档,来解释生成器是怎样工作的,怎样来维护它,你还需要教会项目组的其他人生成器的价值所在和怎样使用。
2. 维护:在你的工作流程中添加一个生成器,就是在为你的应用环境添加一个新的工具,这意味着你将在这个工具的生命周期内发布和维护它。
3. 复杂性:依赖于项目和生成器本身的复杂性,你得到一个巴洛克式设计的生成工具。也许这是一个有挑战性的问题,可以说最好的生成器经常是很简单的,可以把几天的工作简化成几小时的宏。因此复杂性并不是生成器的必须的考量因素。
理解生成器什么时候该用,什么时候不该用很重要。代码生成不能替代面向对象设计。
生成器的种类有哪些?
对应用程序分类是困难的,特别是代码生成器的多样性。一种区分的方法是观察生成器的输入和输出。在输入端你可以使用代码作为输入,或者一个设计所描绘的一个抽象。在输出端,你可以根据一些条件创建输入,或者设计部分实现的新的代码。或者设计的完全实现的代码且需求不会扩展。
基于这样的输入和输出,我们可以得到一些生成器的模型:
1. Code munger:Code munger读入代码作为输入,然后创建新的代码作为输出,这些新代码可以部分的或者完全的依赖于生成器的设计,Xdoclet,从JavaDoc的代码中的嵌入式注释创建EJB的支持Beans,就是Code munger的一个例子。
2. 内联代码增强器:这种模型读入代码作为输入,以输入代码作为基础创建新代码,但是有一部分代码基于原始代码的设计扩展而来,嵌入式sql语言,比如Pro*C,就是内联代码增强器的例子。SQL是用C代码写的,生成器从实现了命令和查询的C代码中的sql扩展,创建C代码。
3. 混合代码生成器:这种模型使用代码作为输入,然后使用输入代码为基础创建新代码,但是返回输出代码到输入的文件中。向导经常就作为混合代码生成器来实现。代码中嵌入的特别的注释,来定义生成器添加新代码的范围。
4. 局部代码生成器:局部代码生成器使用一个抽象的定义来作为输入,然后创建输出代码,用户自己使用子类化来作扩展,以完整实现设计。
5. 层生成器:这种类型的生成器从一个抽象的设计创建完整的输出代码集。这种代码意味着使用“as-is”,不作任何扩展。这是目前开源和商业生成器最普遍的形式。
对于代码生成,开发者最关心哪些
开发者对象代码生成这类新的技术和工具有很多关注点。一些恐惧,担心和怀疑。还有一些合理的担心归咎于当前或先前对于技术的经验。我们希望在下面几个方面有更多关注:
1. 代码生成想作的太多了:市场上很多代码生成器都是Tier Generators(层生成器),这意味着它们被设计用来从一个代码抽象模型创建大量的代码。生成这么多的代码需要被迫学习许多工具和输出代码。但是,这并不是唯一的一种生成器。除过一些小的方面,有许多小的生成器可以提供相同的益处。你可以创建自己的生成器来适应自己的要求。因为大多数目标更广泛的商业化的生成器并不意味着比小的,有特定目标的生成器项目有更高的可用性。
2. 代码生成不能在现有代码基础上工作:这确实是个问题。层生成器趋向于为项目生成新的代码,主要是因为这样更容易命中目标。在现有框架下进行编写代码的工作意味着大规模的修改。用来创建代码的模版适应它们来达到现有的标准。有一种工具,比如Codify,可以在现有代码和新代码情况下很好的工作。
3. 输出代码的质量很差:生成代码维护着质量的一致性级别。这个级别可以从坏到好,依赖于代码的质量和用来创建代码的模版。理想状态下,质量很好,但是如果不是,仍然有一致性的好处。手写的代码的质量在项目进行期间趋向于不同,但是整体在提高。但是经常不是这种情况。邱吉尔被一个女人攻击:“邱吉尔!你是个酒鬼!”。他回答说:“也许我是个酒鬼,但是你很丑,明天我会清醒,但是你依然很丑”。这样的情况也出现在代码生成器上。代码生成器可以被编辑来创建一致的,好的代码。但是人们采用手工的方式一直编写着不一致的代码。
4. 代码生成会吃掉我的工作:如果你的工作包含编写大量的代码。不妨尝试下自动过程,你也许是对的。但是我们中的很多人进入这个行业是因为喜爱创建有趣的,可以帮助人们的程序。代码生成帮助你更快的创建程序。所以对很多人来说代码生成带来了很多机遇。
5. 代码生成太复杂了:生成器关注于它所要创建的代码的复杂性和生成关系的复杂性。它们可以很复杂,但是生成器的输出比起一个灵活的运行时库里的函数化的代码来说,经常是很容易调试和维护的。尽管这样没错,但是生成器的复杂度还时要注意的,不论是开发期间还是部署期间。. “you aren’t going to need it” (YAGNI)的原则要严格的用于生成器的设计和实现。
6. 你不能生成X技术:任何文本文件都是可生成的。所以没有什么不可能。一个问题就创建一个生成器和手写代码之间的投入产出的对比。举个例子:生成器自己可以被生成,但是我假想它是复杂的项目
7. 生成器是很好的起点,但是他们从不维护:这是非常合理的相法。有许多次我看到生成的代码被手工改动。“DO NOT EDIT”的注释依然存在于代码中,很久都没人理会。的确,这只能通过长期对开发者培训如何维护生成的代码来解决。但是也有一些实践的观点,就是从来不在代码管理系统中保留生成的代码。代码生成是创建程序过程中的活跃部分。保证代码从来没有手工修改过,而且生成器经常维护或者丢弃。
代码生成和CASE工具有怎样的关系?
CASE工具,在80年代末和90年代初被夸大为“程序员的终结”。分析师可以使用可视化工具定义业务逻辑,而且生成器可以创建所有的程序代码。在这方面,这些声音更象是MDA,为那些时下流行的平台,象J2EE,.NET,编译UML到代码。代码生成的边界和CASE工具的核心落在了同一个地方。使用生成器从抽象的定义创建应用程序。
代码生成的不同在于它是一种自下向上的,来减轻编码工作量的方法。开发者为自己编写工具来使他们的工作更简单,CASE工具是自上向下的,它们企图使用工具替代受过训练的开发者。这是两者在某些方面,但更是最根本的不同。