代码生成是不是很糟糕?

时间:2009-04-02 15:42:18

标签: nhibernate code-generation

这是一个主观问题。

最近我一直在努力学习NHibernate。它的问题至少是2倍:

  1. 映射需要手动编码的xml文件
  2. 需要手动编码的实体类
  3. 虽然NHibernate是一个很棒的框架,但是需要编写映射文件并创建模仿数据库表的实体类,这些都是痛苦的。有一些工具可以缓解这个问题,例如Castle ActiveRecord或NHibernate Fluent。

    但是,尽管这些工具可以减少代码重复问题,但仍然需要编写一些重复代码,或者必须添加一些装饰属性。我现在正在尝试一些代码生成工具,它允许我直接从数据库生成映射文件和实体类。对我来说,这是一项更省力的任务。

    您怎么看?

20 个答案:

答案 0 :(得分:33)

一般来说,您不希望在生成代码之后对其进行编辑(特别是如果代码生成器的输入很复杂和/或可能会更改)。

我发现使用代码生成作为构建过程的一部分通常是可以的(因此生成的代码永远不会受版本控制)。

我对“一次性”代码生成(生成代码,然后手动调整和扩展)的经验是,它是痛苦的根源。如果您想要返回并更改生成代码的数据,您几乎总是必须手动合并自定义更改...

答案 1 :(得分:10)

正确完成代码生成是一件好事,但是经常做错了。

IMO,代码生成器必须足够智能,以处理对生成的代码的更改。回到.NET 1.0天,即使是闪亮的新Visual Studio .NET代码生成器也可以做到这一点 - 在合理范围内。使用.NET 2.0,我们获得了部分类,使其更加简单。

然而,仍然有一些发电机无法工作多次。

我的“良好”代码生成规则:

  • 应在生成代码的IDE中生成代码。没有第三方可执行文件。通常,这是一个Visual Studio插件,但此规则也适用于其他语言。
  • 生成的代码应提供清晰易用的扩展功能。
  • 生成的代码应该对开发人员不可见。
    • 换句话说,开发人员应该只使用设计器来修改生成的代码。

答案 2 :(得分:4)

这是一把双刃剑。一方面,它可以节省大量时间。当你将它指向一个WSDL文件时,看看VS生成的存根的大小 - 我不想每次想要使用新的Web服务时都要对其进行编码。

另一方面,正如您所指出的,您几乎总是需要巧妙地调整生成的代码,如果您不确切知道自己在做什么,可能会导致错误,因为生成的代码可能是相当迷宫。所以,我想我的答案是:在依赖它之前先熟悉代码生成器发出的内容。

答案 3 :(得分:4)

拉里·沃尔(Perl的创造者)说,三个主要的美德是懒惰,急躁和傲慢,并且每个都有好的和坏的版本。

在尝试自动化无聊和无创作品时,你正在举例说明懒惰(好方法)。对你有好处。

我会尽量确保我不必调整生成的代码,如果可能的话,可能通过提供钩子来添加自定义。

答案 4 :(得分:3)

我绝对没有反对生成不需要修改的代码:这就是编译器所做的: - )

使用工具来保存你本来会做的打字,也没关系。在最简单的层面上,IDE的函数名称自动完成是“代码生成”。

当您生成一些相当复杂的代码,然后手动进行实质性更改,然后想要使用最新版本的代码生成器重复它时,可能会出现问题。通常,很难解开您的更改并将其应用于新版本。 diff3(或者你的源代码控制确实合并)可能工作,但远远不能保证提供帮助。

当您对开源代码进行重大更改时也是如此 - 如果您无法将您的职责封装到单独的文件中,只需对基础进行最小的更改,那么每次新版本下游时都会出现一堆容易出错的错误苦苦挣扎在你的手上。所以想一想 - 你的项目依赖于你没有写的来源。如果您有可能想要对该代码进行更改,则必须正确隔离它。

经验法则是,自动完成的任何事情都应该是可重复的。如果需要将生成的内容转换为您想要的内容,则代码生成是不可重复的。

答案 5 :(得分:2)

如果您在某种程度上没有在开发中使用代码生成,那么您所做的工作比您应该做的更多。正确使用代码生成将提高代码质量,使项目更易于维护,并帮助您以更少的错误更快地交付解决方案。

我编写了3个代码生成器,但目前我使用的是Code Smith。有时我使用NETTiers模板。有时我会使用自己的。

我真的不在乎你使用哪种发生器。 CodeBreeze,CodeSmith,LLBLGen,xslt文件等......

得到一个,学习它,爱它。

每个项目我已经使用了10年或更长时间,包括一些生成的代码。

从这里开始: < http://www.dotnetrocks.com/default.aspx?showNum=63>

< http://www.dotnetrocks.com/default.aspx?showNum=304>

< http://www.dnrtv.com/default.aspx?showNum=77>

< http://www.dnrtv.com/default.aspx?showNum=133>

< http://www.nettiers.org/Home.ashx>

要跑。享受。

答案 6 :(得分:2)

只要您了解正在生成的内容或何时使用自定义内容替换默认值(代码为例),代码生成就可以了 例如。这是 MyGeneration
生成的nhibernate映射的一部分 为什么会有

  

IsChanged

属性

/// <summary>
/// Returns whether or not the object has changed its values.
/// </summary>
Public virtual bool IsChanged { get; private set; }

会改变吗?,这会改变什么时候?当它发生变化时会发生什么。

手工制作的nhibernate实体类很可能只有列属性和构造函数。

这些都是您将遇到的所有情景,特别是在企业世界中,有数百名程序员从事项目工作,平庸是生活中的事实。

另一个问题是控制粒度,特别是当它是构建的一部分时,一天你意识到它应该被微调。

幸运的是,像.net这样的框架允许部分类,扩展方法等帮助你处理这种情况。

答案 7 :(得分:1)

在我看来,使用代码生成开始你的努力是好的。当您需要修改生成的代码以处理特殊情况时,或者当您发现生成的代码不是它应该是什么时,问题就出现了,那么根据您的团队,找到处理生成的代码的人可能会很困难。我最近做了一个项目,代码是由一个人生成的,他用自己的魔法来做到这一点......他最终成了瓶颈,所以最后我们停止了代码生成,事情变得相当顺利

答案 8 :(得分:1)

构建时代码生成不好因为:

  • 维护起来比较困难 - 一个看项目的新程序员可能会浪费一周的时间来理解实际生成的代码;

  • 它需要生成完整的构建,并且在开发环境中,您不希望经常进行完整构建;

  • 当生成的代码中发生异常时,您会被卡住;

  • 它需要额外的(通常是复杂的)SCM设置才能忽略它;

  • 即使你想要也不能修改它,因为它会在下一个版本中被覆盖;

  • 更改生成代码的定义可能会破坏代码库,但直到稍后才能找到(也就是说,在破坏代码时你可能会愉快地开发)。

答案 9 :(得分:1)

我每天都使用代码生成器。它大大减少了编写应用程序枯燥乏味的部分所需的时间。

我强烈建议使用Ruby作为代码生成器工具。我从Ruby生成C ++和C#代码。代码生成器的输入是一个简单的内部DSL。

答案 10 :(得分:1)

我同意大多数评论家的观点,即代码生成既不好也不邪恶。我已经看到生成的代码是痛苦的重要来源,也是解决手头问题的实用解决方案。

但在你的情况下,我肯定会查看Fluent NHibernate的一个特殊功能:自动映射!更多信息here

设置完成后,您可以通过编写实体类来创建自动映射到数据库的持久类。这是正确的方法 - 在数据库中定义您的域模型有点蠢(至少如果您可以避免它)。

我的2美分,至少。

答案 11 :(得分:1)

代码生成器可以为您节省宝贵的时间,但请记住,如果您开始生成大量代码,这也意味着您的代码不是DRY,这意味着需要大量重复。这可能会给代码维护带来问题,并降低代码的优雅性。

如果您发现自己生成了大量重复的代码块或类似代码,请尝试找到更好的方法,例如类工厂/运行时代码生成。写作需要更长的时间,但它更有趣,更优雅。使维护更容易。

最后,如果您可以自由选择语言,可以尝试使用ruby的ActiveRecord(A rails包),DataMapper或Sequel。它们都是优秀的ORM,需要最少的配置。

答案 12 :(得分:1)

如果没有代码生成,我们几乎无法运行。它无处不在。

如果没有代码生成,我们将手动设置宽微码字中的位,以便将事物连接到正确的总线。

你真正的我是,“我可以为自己的使用带来一些强大的力量吗?”

我要回答“当然,把自己打倒。只要记住1”,有强大的力量会带来很大的责任,2)只能善用它,永远不要用于邪恶。“

答案 13 :(得分:1)

不 - 为什么会这样?如果我能得到一个工具来为我做烦人的,无聊的代码 - 我可以在同一时间做更多有趣的事情!

马克

答案 14 :(得分:1)

我认为如果生成的代码与您手动编写的代码大致相同,那么请继续。

如果做得好,你几乎不需要在几个月后再回过头来调整它。在生成代码并进行一些调整之后,您将在该项目中找到平安:P

答案 15 :(得分:0)

我认为是否使用代码生成的问题取决于您的代码目标是什么。

您的数据访问层示例很好。您对NHibernate的问题是您必须自己生成域类。如果您的域类直接映射到数据库模式,那么这不是问题。但是,NHibernate在这种情况下的优势之一就是您可以定义自己的域类,并且它们不必精确映射到数据库层。这意味着您可以稍后调整数据库层,并且您必须更改的唯一代码是映射文件。如果你使用代码生成,你可能不得不调整更多的代码,并且调整并不总是像对映射文件的调整一样简单。

答案 16 :(得分:0)

有关生成的代码非常易于扩展的优秀示例,请查看Visual Studio SDK中的DSL Toolkit。一个用它来定义你自己的图形域特定语言(生成),并且可以通过部分类和覆盖来定制大部分行为。这是一个非常强大的组合。


两个注意事项:.NET在幕后完成了相当多的代码生成。正则表达式,XML转换和XML串行器代码是动态生成的。当然,ASP.NET的情况也是如此,我会惊讶地发现它的用法并不多于此(我正在考虑使用XAML)。

另外,我想明确说明DataSet Designer和“添加Web引用”和“添加服务引用”生成的类都是部分类。您可以完全保留生成的文件,并仍然扩展生成的类。有关此示例,请参阅Ways to Customize your ASMX Client Proxy的底部。

答案 17 :(得分:0)

我认为大多数在代码生成方面做出否定回答的人要么不是.NET开发人员,要么对代码生成一无所知。

使用.NET而不是其他平台会产生很大的不同,因为.NET已将构建内置到语言中,从而可以轻松扩充和扩展生成的代码。

我认为阅读本文的大多数.NET开发人员已经在使用代码生成,甚至没有意识到它,Entity Framework使用T4代码生成模板

https://msdn.microsoft.com/en-us/library/bb126445.aspx

为什么代码生成“好”?

您出于一个原因使用代码生成 - 桥接两个不同的应用程序层,通常在数据库和应用程序之间。通常,在应用程序中创建数据库模式抽象的任务是有条理的,而不是手动编码,最好生成这样的代码,因为生成代码可以确保一致性。

人们谈到了维护代码生成代码的难题,我谈到了维护手动创建的代码的难题,这些代码不一致地创建了数据库系统的抽象。在处理行为不一致的框架时,通常会产生错误。代码生成允许您基于跨多个实体的模式创建代码,这些代码是一致的。

在C#中生成框架的代码,确保您的模板使用部分类和部分方法......

https://msdn.microsoft.com/en-us/library/wa80x488.aspx

...允许您根据具体情况创建扩展和扩充生成的代码。这些结构存在于C#中,没有其他原因。

我为这两个代码生成存储库,实体和接口。我不会生成一个不使用代码生成的数据库系统。

答案 18 :(得分:-1)

没有。代码既不好也不邪恶。它只是一个工具。如果你使用得好,它可以节省你无法估量的时间。另一方面,如果你使用它很差,它最终会花费你不可估量的时间。

一个小小的问题,如果在oo环境中做代码生成,我建议你包装生成的类,如果你想从生成的类中扩展它们。

答案 19 :(得分:-1)

很多好的答案。

通过让程序编写程序来解决问题是一个好主意,但没有一个好主意不能被错误地使用。

我问代码生成器的基本问题是“我能理解它在做什么吗?” 如果我不这样做,那么它可能对我没有帮助。