Pragmatic Programmer提倡使用代码生成器。您是否在项目中创建代码生成器?如果是,你用它们做什么?
26 回答
在“实用程序员”中,Hunt 和 Thomas 区分了被动代码生成器和主动代码生成器。
被动生成器运行一次,然后编辑结果。
活动生成器会根据需要运行,您永远不应该编辑结果,因为它会被替换。
IMO,后者更有价值,因为它们接近 DRY(不要重复自己)原则。
如果您的程序的输入信息可以分为两部分,很少更改的部分(A)(如元数据或 DSL),以及每次程序运行时不同的部分(B)(实时输入) ,您可以编写一个仅将 A 作为输入的生成器程序,并编写一个仅将 B 作为输入的 ad-hoc 程序。(另一个名称是部分评估。)
生成器程序更简单,因为它只需要遍历输入 A,而不是 A 和 B。此外,它不必很快,因为它不经常运行,也不必关心内存泄漏。
ad-hoc 程序更快,因为它不必费力地处理几乎总是相同的输入 (A)。它更简单,因为它只需要对输入 B 做出决定,而不是 A 和 B。
生成的 ad-hoc 程序具有很强的可读性是一个好主意,这样您就可以更容易地找到其中的任何错误。一旦你从生成器中删除了错误,它们就永远消失了。
在我参与的一个项目中,一个团队设计了一个复杂的数据库应用程序,其设计规范为 2 英寸厚,实施计划很长,而且对性能充满了担忧。通过编写代码生成器,两个人在三个月内完成了这项工作,源代码清单(C 语言)大约有半英寸厚,生成的代码速度很快,不成问题。临时程序每周重新生成一次,成本微不足道。
因此,当您可以使用它时,主动代码生成是双赢的。而且,我认为这正是编译器所做的事情并非偶然。
如果在没有正确论证的情况下广泛使用代码生成器,则会降低代码的可理解性并降低可维护性(顺便说一下,动态 SQL 也是如此)。就我个人而言,我将它与一些 ORM 工具一起使用,因为它们在这里的使用最为明显,有时用于诸如搜索器-解析器算法和语法分析器之类的东西,这些东西最近不是为了“手动”维护而设计的。干杯。
在硬件设计中,在“堆栈”的多个级别上执行此操作是相当普遍的做法。例如,我编写了一个代码生成器来为 DMA 引擎和交叉开关的各种宽度、拓扑和结构发出 Verilog,因为表达这种参数化所需的结构在综合和仿真工具流程中还不成熟。
为可以通过算法表达和生成的非常规则的事物(如 SRAM、缓存和寄存器文件结构)发出逻辑模型一直到布局数据也是例行公事。
我还花了相当多的时间编写一个代码生成器,它可以获取片上系统上所有寄存器的 XML 描述,并发出 HTML(是的,是的,我知道 XSLT,我刚刚发现发出它以编程方式更省时)、Verilog、SystemVerilog、C、Assembly 等。该数据的“视图”供不同团队(前端和后端 ASIC 设计、固件、文档等)使用(和通过这个单一的 XML“代码库”使它们保持一致)。这算不算?
人们还喜欢编写代码生成器,例如对非常常见的事物(如有限状态机)进行简洁描述,并机械地输出更冗长的命令式语言代码以有效地实现它们(例如转换表和遍历代码)。
我们使用代码生成器来生成数据实体类、数据库对象(如触发器、存储过程)、服务代理等。在任何你看到大量重复代码遵循模式和涉及大量手动工作的地方,代码生成器都可以提供帮助。但是,您不应该过多地使用它,以至于可维护性是一种痛苦。如果您想重新生成它们,也会出现一些问题。
Visual Studio、Codesmith 等工具为大多数常见任务提供了自己的模板,并使此过程更容易。但是,很容易自行推出。
创建一个从规范生成代码的代码生成器通常很有用——通常是具有常规表格规则的代码生成器。它减少了通过拼写错误或遗漏引入错误的机会。
是的,我为 AAA 协议 Diameter (RFC 3588) 开发了自己的代码生成器。它可以为从描述直径应用程序语法的 XML 文件读取的直径消息生成结构和 Api。
这大大缩短了开发完整直径接口(如SH/CX/RO等)的时间。
在我看来,一种好的编程语言不需要代码生成器,因为自省和运行时代码生成将成为语言的一部分,例如在 python 元类和新模块等中。
代码生成器通常会在长期使用中生成更多难以管理的代码。
但是,如果绝对必须使用代码生成器(我有时会使用 Eclipse VE 进行 Swing 开发),那么请确保您知道正在生成什么代码。相信我,您不会希望应用程序中出现您不熟悉的代码。
为项目编写自己的生成器效率不高。相反,请使用 T4、CodeSmith 和 Zontroy 等生成器。
T4 更复杂,您需要了解一门 .Net 编程语言。您必须逐行编写模板,并且必须自己完成数据关系操作。您可以通过 Visual Studio 使用它。
CodeSmith 是一个功能性工具,有很多模板可供使用。它基于 T4,编写自己的模板需要花费太多时间,就像在 T4 中一样。有试用版和商业版。
Zontroy 是一款具有用户友好用户界面的新工具。它有自己的模板语言,易于学习。有一个在线模板市场,并且正在发展。甚至您也可以提供模板并在市场上在线销售。它有免费版和商业版。即使是免费版本也足以完成一个中等规模的项目。
那里可能有很多代码生成器,但是我总是创建自己的代码生成器以使代码更易于理解并适合我们使用的框架和指南
我们为所有新代码使用生成器,以帮助确保遵循编码标准。
我们最近用CodeSmith替换了我们内部的 C++ 生成器。我们仍然必须为该工具创建模板,但不必自己维护该工具似乎是理想的。
我最近对生成器的需求是一个从硬件读取数据并最终将其发布到“仪表板”用户界面的项目。中间是几个数据点的模型、属性、演示者、事件、接口、标志等。我为几个数据点建立了框架,直到我对我可以接受这个设计感到满意。然后,在一些精心放置的注释的帮助下,我将“生成”放在了 Visual Studio 宏中,调整并清理了宏,将数据点添加到宏中的函数以调用生成 - 并节省了几个繁琐的小时(天?) 到底。
不要低估宏的力量:)
我现在也在尝试了解CodeRush自定义功能,以帮助我满足更多本地生成需求。如果您在生成代码块时需要即时决策,那么那里有强大的东西。
我有自己的代码生成器,可以针对 SQL 表运行。它生成用于访问数据、数据访问层和业务逻辑的 SQL 过程。它在标准化我的代码和命名约定方面创造了奇迹。因为它需要数据库表中的某些字段(例如 id 列和更新的 datetime 列),它也有助于标准化我的数据设计。
你要找几个?我创建了两个主要的和许多次要的。主要的第一个允许我生成程序 1500 行程序(给予或接受),这些程序具有很强的家族相似性,但与数据库中的不同表相协调 - 并且可以快速、可靠地完成。
代码生成器的缺点是,如果生成的代码中存在错误(因为模板包含错误),则需要进行大量修复。
但是,对于需要完成大量近乎重复的编码的语言或系统,一个好的(足够)代码生成器是一个福音(而且比“doggle”更像是一个福音)。
在嵌入式系统中,有时您需要闪存中的一大块二进制数据。例如,我有一个包含位图字体字形的文本文件并将其转换为 .cc/.h 文件对,声明有趣的常量(例如第一个字符、最后一个字符、字符宽度和高度),然后将实际数据为一个大的static const uint8_t[]
。
尝试在 C++ 本身中做这样的事情,因此字体数据将在编译时自动生成而无需第一次通过,这将是一种痛苦并且很可能难以辨认。手动编写 .o 文件是不可能的。拆开方格纸,手动编码为二进制,然后输入所有内容也是如此。
恕我直言,这种事情就是代码生成器的用途。永远不要忘记计算机为您工作,而不是相反。
顺便说一句,如果您使用生成器,请始终始终在每个生成的文件的开头和结尾都包含一些这样的行:
// This code was automatically generated from Font_foo.txt. DO NOT EDIT THIS FILE.
// If there's a bug, fix the font text file or the generator program, not this file.
是的,我不得不维持一些。CORBA 或其他一些对象通信风格的接口可能是我首先想到的一般事物。您有将要讨论的接口提供给您的对象定义,但您仍然必须在代码中构建这些对象。构建和运行代码生成器是一种相当常规的方法。这可能会变成一个相当冗长的编译,只是为了支持一些遗留的通信通道,而且由于有很大的趋势是在 CORBA 周围放置包装器以使其更简单,所以事情只会变得更糟。
通常,如果您有大量结构,或者只是需要使用快速变化的结构,但您无法处理通过元数据构建对象的性能损失,那么您需要编写代码生成器。
我想不出我们需要从头开始创建自己的代码生成器的任何项目,但是有几个我们使用了预先存在的生成器。(我已经使用 Antlr 和 Eclipse 建模框架在 Java 中为企业软件构建解析器和模型。)使用其他人编写的代码生成器的美妙之处在于作者往往是该领域的专家并且已经解决了问题我什至不知道它的存在。这节省了我的时间和挫败感。
因此,即使我可以编写解决手头问题的代码,我也可以更快地生成代码,并且很有可能它比我编写的任何代码都更少错误。
如果您不打算编写代码,您会对其他人生成的代码感到满意吗?
从长远来看,编写自己的代码或代码生成器是否更便宜?
我编写了一个代码生成器,它将构建 100 个类 (java),这些类 (java) 将以 DTD 或模式兼容的方式从数据库输出 XML 数据。代码生成通常是一次性的,然后代码将使用各种业务规则等进行智能处理。输出是针对一个相当迂腐的银行。
代码生成器是针对编程语言限制的解决方法。我个人更喜欢反射而不是代码生成器,但我同意代码生成器更灵活,并且在运行时生成的代码显然更快。我希望,未来的 C# 版本将包含某种 DSL 环境。
我使用的唯一代码生成器是 Web 服务解析器。我个人远离代码生成器,因为交接后新员工或单独团队的维护问题。
我编写自己的代码生成器,主要在 T-SQL 中,在构建过程中调用。
基于元模型数据,它们生成触发器、日志记录、C# const 声明、INSERT/UPDATE 语句、数据模型信息,以检查应用程序是否在预期的数据库模式上运行。
我仍然需要编写一个表单生成器来提高生产力、更多的规范和更少的编码;)
我创建了一些代码生成器。我有一个使用模板的 SQL 存储过程的被动代码生成器。这生成了我们 90% 的存储过程。
自从我们切换到实体框架后,我在 Visual Studio 中使用 T4(文本模板转换工具包)创建了一个活动代码生成器。我用它为我们的实体创建了基本的存储库部分类。工作得很好,节省了大量的编码。我还使用 T4 来装饰具有某些属性的实体类。
我使用EMF-Eclipse Modeling Framework提供的代码生成功能。
代码生成器在很多情况下都非常有用,尤其是在从一种格式映射到另一种格式时。我已经完成了 IDL 到 C++ 的代码生成器、数据库表到 OO 类型以及编组代码等等。
我认为作者试图说明的观点是,如果您是开发人员,您应该能够让计算机为您工作。生成代码只是自动化的一项显而易见的任务。
我曾经和一个人一起工作,他坚持要手动完成我们的 IDL 到 C++ 的映射。在项目开始时他能够跟上,因为我们其他人都在努力弄清楚该怎么做,但最终他成为了瓶颈。我在 Perl 中做了一个代码生成器,然后我们几乎可以在几分钟内完成他的“工作”。
请参阅我们基于程序转换的“通用”代码生成器。
我是架构师和关键实施者。值得注意的是,这个生成器的很大一部分是使用这个生成器生成的。
我们在项目中使用Telosys代码生成器:http ://www.telosys.org/
我们创建它是为了减少重复任务(如 CRUD 屏幕、文档等)的开发时间......
对我们来说最重要的是能够自定义生成器的模板,以便在必要时创建新的生成目标并自定义现有模板。这就是为什么我们还创建了一个模板编辑器(用于 Velocity .vm 文件)。它适用于 Java/Spring/AngularJS 代码生成器,并且可以适应其他目标(PHP、C#、Python 等)