我为什么要使用代码生成器

Nig*_*ker 28 language-agnostic code-generation

我最近遇到过这个话题,无法理解为什么需要它们.

你能解释为什么我应该在我的项目中使用它们以及它们如何能够缓解我的生活.

例子很棒,从那里我可以了解更多这个话题.

Nea*_*eal 20

至少你从正确的角度构思了这个问题=)

使用代码生成器的通常原因是生产力和一致性,因为他们认为解决一致且重复的问题是在其上投入更多代码.我认为,无论何时考虑代码生成,请查看为什么要生成代码,看看是否可以通过其他方式解决问题.

一个典型的例子就是数据访问; 您可以生成250个类(架构中的每个表1个),有效地创建表网关解决方案,或者您可以构建更像域模型的东西,并使用NHibernate/ActiveRecord/LightSpeed/[pick your orm]来映射富域模型到数据库.

虽然手动滚动解决方案和ORM都是有效的代码生成器,但主要区别在于生成代码时.使用ORM,它是在运行时发生的隐式步骤,因此它本质上是单向的.手动解决方案需要明确的步骤来在开发期间生成代码,以及生成的类在某些时候需要自定义的可能性,因此在重新生成代码时会产生问题.在开发过程中必须发生的明确步骤会在开发过程中引入摩擦,并且经常导致违反DRY的代码(尽管有些人认为生成的代码永远不会违反DRY).

宣传代码生成的另一个原因来自MDA/MDE世界(模型驱动架构/工程).我不会在这方面投入太多资金,而是提供一些表达不好的论点,我只是想选择其他人 - http://www.infoq.com/articles/8-reasons-why- MDE失败.

IMHO代码生成是一个非常狭窄的问题集中的唯一解决方案,无论何时你考虑它,你应该再看看你想要解决的真正问题,看看是否有更好的解决方案.

真正提高生产力的一种代码生成是"微代码生成",其中宏和模板的使用允许开发人员直接在IDE中生成新代码并通过占位符选项卡/键入(例如,命名空间/类名等) .这种代码生成是resharper的一个特性,我每天都在大量使用它.在大多数大规模代码生成失败的情况下微代生成受益的原因是生成的代码不会绑定到必须保持同步的任何其他资源,因此一旦生成代码,它就像所有其他代码一样解决方案.

@John
在进行大爆炸开发时,经常会看到将"基本类"从IDE创建到xml/dsl中 - 一个典型的例子是开发人员尝试将数据库反向工程为域模型.除非代码生成器写得很好,否则它只会给开发人员带来额外的负担,因为每次他们需要更新域模型时,他们要么必须上下文切换并更新xml/dsl,要么他们必须扩展域模型然后将这些更改移植回xml/dsl(有效地完成两次工作).

有一些代码生成器在这个空间中工作得非常好(LightSpeed设计器是我能想到的唯一一个),它可以作为设计界面的引擎,但通常这些代码生成器会生成无法维护的糟糕代码(例如winforms/webforms设计表面,EF1设计表面)因此可以快速消除从使用代码生成器获得的任何生产力优势.

  • @Neal:我没有提出争论,我问了一个你没有回答的问题.我也没有说过DB中的codegen.代码gen可能来自XML或您的域模型的其他表示. (3认同)
  • @Neal:我不知道你使用了什么糟糕的代码生成工具,但没有理由让它们变得不灵活.重复的代码结构是生成代码的完美理由,假设类之间的差异可以被分解为声明性数据. (3认同)
  • 您的域模型是否没有重复代码?真?您不为每个字符串属性使用相同的代码? (2认同)
  • @John - 不确定你在这里得到什么,你的论点缺乏实质内容.@Michael-我只模拟我需要的东西,如果我需要一个大型域名,我会对其进行建模,但存储问题不应该泄漏到域关注点,这就是当你从db中编码时发生的事情.NH + FNH(或ConfORM)允许您在代码中表达模型和映射,并且当与约定优于配置相结合时,它是一种非常强大的方法.NH确实允许生成DDL来创建数据库,这是代码(SQL)生成的少数"适当"案例之一. (2认同)
  • @Neal:我没有发表这样的一揽子声明.我一直在声明代码生成对于从域模型(在XML或某些DSL中)创建基本类很有价值.然后,您可以使用域逻辑扩展域类,但创建类的基本结构是一个机械过程,并且可以机械地执行. (2认同)
  • @Neal:我想我不知道为什么你没有可以直接从你的域模型生成代码的工具.即使有必要将域模型转换为XML或其他格式,整个过程也应该是相当自动的. (2认同)
  • @Neal:很高兴我们到底了.我不会说你在使用建模.我从来没有听说过一个代码模型 - 你有一个使用"模型"这个词的参考吗?正如我所理解的那样,模型和代码意味着具有不同的抽象层次. (2认同)

mar*_*c_s 17

好吧,它是:

  • 你写了250个课程,几乎完全相同,但略有不同,例如进行数据访问; 花了你一个星期,这很无聊,容易出错,很烦人

要么:

  • 你投入30分钟来生成一个代码模板,并让一代引擎在另外30分钟内处理咕噜声

所以代码生成器为您提供:

  • 速度
  • 再现性
  • 错误少得多
  • 更多的空闲时间!:-)

优秀的例子:

  • Damien Guard的Linq-to-SQL T4模板在数据库模型中为每个类生成一个单独的文件,使用最佳的Visual Studio 2008秘密--T4模板

  • PLINQO - 同样的事情,但对于Codesmith的生成器

还有无数......

  • "你写了250个课程,几乎完全一样,但略有不同"我不禁想到,如果我发现自己处于这个位置,我会"做错了".在某个地方,我应该退后一步,试图弄清楚为什么我会如此重复自己并把事情做得更好(做一个父类,或者其他什么). (6认同)
  • @MGOwen:但继承并不总是有帮助.以这种方式分解公共代码并不总是可能的.考虑数据层的情况,其中表示两个实体的类之间的差异将包括每个实体的列集.你不能使用继承来解决这个问题. (5认同)

Fre*_*örk 6

任何时候你需要生成大量的重复样板代码,代码生成器就是你的工作.上次我使用代码生成器时是为项目创建自定义数据访问层,其中各种CRUD操作的框架是基于对象模型创建的.我没有对所有这些类进行手工编码,而是组建了一个模板驱动的代码生成器(使用StringTemplate)来为我创建它.该程序的优点是:

  • 它更快(生成了大量代码)
  • 我可以随心所欲地重新生成代码,以防我检测到错误(代码有时会在早期版本中出现错误)
  • 不容易出错; 当我们在生成的代码中出现错误时,无处不在意味着它更有可能被发现(并且,如前一点所述,很容易修复它并重新生成代码).


Max*_* E. 5

实际上,当您使用几乎任何编程语言时,您都在使用“代码生成器”(汇编代码或机器代码除外)。我经常编写 200 行的小脚本,这些脚本可以生成几千行 C 语言。还有软件您可以获得它有助于生成某些类型的代码(例如,yacc 和 lex 用于生成解析器以创建编程语言。)

这里的关键是将代码生成器的输入视为实际的源代码,并将其吐出的内容视为构建过程的一部分。在这种情况下,您正在使用更高级的语言编写,需要处理的实际代码行更少。

例如,这里有一个非常长且乏味的文件,是我在修改基于 Quake2 的游戏引擎 CRX 的过程中编写的(不是)。它从两个标头中获取所有 #define 常量的整数值,并将它们放入“cvars”(游戏内控制台的变量)。http:
//meliaserlow.dyndns.tv :8000/alienarena/lua_source/game /cvar_constants.c

这是在编译时生成该代码的简短 Bash 脚本:
http://meliaserlow.dyndns.tv :8000/alienarena/lua_source/autogen/constant_cvars.sh

现在,您更愿意维护哪一个?它们在描述方面是等效的,但其中一个要长得多,处理起来也更烦人。