代码生成是一项基本开发技能
代码生成是一项基本开发技能。
“给一个优秀开发者一个40小时的任务,他会花39小时写一个能在1小时内完成任务的程序。” – 未知
真的吗?这看起来有风险!
这看起来确实有风险,不是吗?你可能会得到一个半成品程序,而没有足够的时间来完成工作。有一些方法可以降低这种风险,但稍后会详细介绍。
为什么你甚至要费心去做呢?简单的数学告诉我们这样做并不更快(至少在上面的例子中是这样)。然而,经验告诉我们,总的来说,大多数工作都会重复。现在,以刚才的例子来说,如果它只重复一次,你就能赚取39小时的利润,因为你现在可以在1小时内完成工作。
显然,在现实世界中事情并非如此。自动化一个过程通常比手动完成工作花费更长的时间。事实上,当你想要自动化某事时,这通常意味着你必须先手动做至少一次,这样你才知道你在自动化什么。
但你不太可能只重复一个过程一次。很多时候,任务会执行很多次,然后自动化才变得值得投入精力。让我们来看一个当前的例子。
常见案例
正如有些人可能知道的,我正在开发一款具有Silverlight UI和WCF服务层的业务应用程序(尽管在这种情况下使用的技术并不重要)。编写大多数业务应用程序的一部分是编写代表模型的业务对象,以及编写从数据库检索数据的逻辑,无论是直接检索还是通过某种ORM。
另一部分是编写大量的“表单”,如果你愿意这么称呼的话,用于输入数据。通常,这些表单遵循一个通用模式。这两部分,业务对象和表单,都包含了大量手动重复的工作。有些代码可以移入通用的父类,但大多数代码的性质不允许泛化。这就是自动化发挥作用的地方。在这种情况下,如果你也能生成代码,为什么还要自己写那么多代码呢?
当我们刚开始这个应用程序时,我们就着手进行一些代码生成。不幸的是,我们中的大多数人并没有太多代码生成方面的经验,因此做出了错误的选择(使用StringBuilder进行C#生成不是好办法,Code DOM也是如此)。在我们的代码生成引擎的初始版本之后,我们被迫花所有时间来向客户发布第一个版本,因此任何形式的自动化工作都成为不可能的预期结果。
那么,你是一名优秀开发者吗?
我们都会在某个时候陷入这个陷阱。我知道我曾好几次这样。你让截止日期给你太大的压力,或者你回到你过去天真的想法,说这只是演示代码,不会最终进入生产环境。无论原因是什么,我们最终都会时不时地打破自己的规则。
别误会我的意思,这并不会让你成为一个糟糕的开发者。事实上,这表明你专注于如何为客户提供价值,这对于一个好开发者来说是关键。此外,时不时地打破这些规则也能让我们警醒,为什么它们一开始就是规则。
然而,我们有时也应该停下来,回顾一下我们正在做的事情。就我而言,我发现我们应该在提高开发流程效率方面投入更多努力。这意味着要使更多代码通用,重构现有通用代码以更好地满足我们的需求,并生成更多代码。
生成代码,一项艰巨的任务?
对某些开发者来说,生成代码可能看起来是一项艰巨的任务。别担心。这是一件好事,因为你不会在没有深思熟虑的情况下就一头扎进去。从我们的例子中可以看到,让一个开发者想:“哦,这很容易。我只需要一个StringBuilder然后输出大量的*.cs文件”是远远不够理想的。
实际上,代码生成的第一步**不是**编写代码生成过程。一切都始于元数据。如果你没有任何东西来作为你的代码生成过程的基础,那你又怎么能生成代码呢?
在业务应用程序的情况下,你的数据模型通常可以为你提供一些元数据。事实上,我们最初是使用一个存储过程,它从SQL Server中的数据模型中提取元数据,然后将其放入另一个数据库。然后我们从这些数据生成源代码。
元数据的另一个来源可能实际上来自将数据输入应用程序的人。我们也使用它,以便我们的功能专家能够为我们提供信息来生成GUI中的表单。
一旦你以某种形式拥有了元数据,你就可以编写你的生成过程了。实际上,这部分并不一定很难。最终,它只是从数据创建文本,而大多数Web开发者多年来一直在做这件事。主要问题是集成你的过程与你的IDE。这时T4就派上用场了。
正如有些人可能知道的,T4已经在Visual Studio中用于生成源代码。它还提供了一个简单的按钮来触发你解决方案中所有T4模板的执行。这显然比添加由外部程序生成的文件的要容易得多。
至于编辑这些模板,Visual Studio并没有内置标准支持(默认情况下它被视为文本,所以没有IntelliSense)。如果你是认真的T4用户,你应该看看Tangible。他们有一个T4编辑器,集成在Visual Studio中,有免费版和功能更丰富的专业版。两者都提供IntelliSense和高亮显示,但免费版仅支持有限的命名空间和程序集。你可以在这里找到它们:here。
但是风险呢?
我明白你的顾虑。开始做这件事可能会让人害怕。诀窍在于从小处着手,然后不断扩展你的代码生成过程以支持越来越多的场景。这样,你就可以迭代地进行代码生成,并且经常有一个可用的最终结果。这降低了风险,因为你可以在任何时候决定不再扩展代码生成过程,而是手动扩展生成的代码。
此外,在生成任何代码之前,你应该至少编写并测试它一次,以确保你知道代码的结构以及需要哪些元数据才能生成它。这样,你也知道最终会得到能够工作的代码。
结论
我希望你能认识到代码生成的潜力,以及它如何真正提高你的工作效率。我可以凭经验告诉你,即使你需要构建大量重复的工作,它也能让软件开发更有趣。有了正确的工具,我相信任何开发团队都可以从自动化工作中受益。