过度工程的具体症状

时间:2009-12-21 18:26:44

标签: architecture infrastructure

我最近发现自己处理了一个(内部)应用程序,我已经写给我公司喜欢雇用的两位候选人,以协助维护和添加次要功能。

这是我写的第一个“制作”应用程序,它有45k LOC,我花了将近两年的“独奏”开发。我还很年轻(18岁),从头开始编写应用程序,同时签约作为离开公司的前开发人员的替身。我没有经验设计这种大小的应用程序,我试图使用常见的架构和设计模式。

今天我知道我做了一些严肃的过度工程,例如使用断开连接的更改跟踪体系结构而不是所选ORM已实现的工作单元模式。我可能永远不会去“真正的”三层。

两位候选人都有10年以上的内部应用程序开发背景和相关平台。作为他们年龄的一半,没有经验,我尊重他们的意见。当我向他们解释应用程序架构时,评论的内容如下:

  • Jeez,没有人会付钱给我这样的事情,我必须把事情做好
  • 坚持框架的功能,不要使用花哨的库/技术
  • 不要包装框架代码。在团队中,每个人都会编写自己的包装代码。
  • 您使用的是.NET 3.5吗?好吧,我们正在使用2.0。
  • LINQ的东西给我带来了什么?所有这些查询组合和投影看起来都太复杂了。

现在我问自己:
我是architecture astronaut吗?我怎么知道我在建筑方面走得太远了?过度工程的常见症状有哪些?

17 个答案:

答案 0 :(得分:117)

  

什么是常见症状?   过度工程?

解决您没有的问题的代码。

答案 1 :(得分:25)

过度工程的一个非常强烈的警告标志是当所有事情都经历了如此多的间接时,很难找到实际实现某些具体的域级功能的代码片段。如果您发现大部分功能都做了很少的具体工作而只是调用其他虚拟功能,那么您可能会遇到问题。

答案 2 :(得分:18)

<强>无聊

Boredom是过度设计代码的良好前身。我承认,当我得到第一份工作时,我觉得这种情况未得到充分利用。我很无聊。当我感到无聊时,我写了代码。不只是任何代码 - CATHEDRALS OF CODE。

没有认真的,我对我的代码和抽象的精神描绘是一个巨大的塔楼,有金色的突出尖顶,玻璃状on玛瑙的扶壁,一个美丽的拱顶支撑着拱形圆顶,上面有漂亮的几何图案等等。

看到这些模式为我自己一起工作真是令人着迷,但回想起来,我对我留下的不敬虔的混乱感到十分羞愧。

如果您正在编写自己的框架和DSL代码,而不是在工作中减少刺激时间,那就停下来吧。阅读Wards Wiki或撰写an open source book的时间更长,或者您可能只想让管理层要求更多的工作。

答案 3 :(得分:11)

至于你是否是一名建筑宇航员的问题:如果你意识到让你领先于很多人的危险。你也不想走牛犊的路,听起来有些人已经成了硬梆梆的老人。

过度工程是优先级问题的结果,导致系统的某些部分受到过多关注。因此,过度工程化最明显的症状是,您可以看到系统其他部分因缺乏关注而受到伤害。

(由于复杂性增加以及在决定过度工程的哪些方面涉及的容易出错的推测,但作为评论,过度工程化也会使系统暴露于设计不良的风险增加的趋势指出,这不会自动跟随。)

答案 4 :(得分:11)

编写自己的框架

可能的是,有人已经做到了。更重要的是,他们已经做到了比以往任何时候都好1000倍。更重要的是,无论他们做了什么,可能已经是行业标准,因此学习这项技术将使你在其他工作中更具竞争力。

在我工作的最后一家公司,一名程序员在他的大部分任期内独自完成了他的项目。他写了一篇该公司比较受欢迎的应用程序,被广泛认为是团队中最好的 - 但在我看来,他有一种讨厌的习惯,就是从头开始编写他需要的东西。

他写了自己的依赖注入框架,他自己的ORM,一个单元测试框架(莫名其妙地,看起来和行为非常类似于NUnit - 他为什么不使用NUnit?),一个用于创建工厂的框架对象(我称之为“factory factory”。)

请注意,代码实际上非常出色,但重点是什么?

撰写更好的核心库

在我现在的公司,程序员似乎总是编写无用的代码来复制已经存在于.NET框架中的功能。

除其他外,他们写道:

  • ASP.NET网络表单中表单身份验证的活动目录框架 - 由于ASP.NET内置了此功能,因此无法理解。
  • 网站的热插拔主题和皮肤 - 也是莫名其妙的,因为代码功能不如内置的ASP.NET主题,并且需要1000%的膨胀。
  • 他们莫名其妙地编写了自己的类型化数据集和数据适配器。这些对象提供的功能少于VS将为您自动生成的类型化数据集,同时需要比NHibernate域对象更多的样板代码。

要么他们不太了解框架,要么他们认为这是非常不合适的。

我只能想到很少的例子,重新实现的库比原始库更好(参见Jane Street Core LibraryC5 Generic Collections for .NETa real currency class),但可能性是,你不会写一个更好的标准库。

答案 5 :(得分:10)

对于大多数内部业务应用程序,您的大多数代码应该关注实现业务问题,而不是与业务无关的技术问题(例如“断开连接的更改跟踪架构”)。当前可用的框架非常成熟,支持最常见的用例。如果您正在发明新技术或(在业务应用程序开发的上下文中)只是为了包装而包装其他现有的框架或库,那么您可能做错了。理想情况下,您构建的每个体系结构都应该可追溯到某些业务需求。保持简单。

答案 6 :(得分:9)

恕我直言,你得到的关于你的应用程序的大部分评论都不是关于过度工程的,因为过度工程不是关于技术。这是关于建筑。可以在合理的时间内学习和理解新技术。理解过度设计的应用程序通常要困难得多,有时甚至是不可能的。这使得第2,4和5点无效。第一点并不真正有效,因为你显然因为编写应用程序而得到了报酬,如果它有效,你就没有问题了。

这是我的“快速测试”,以确定应用趋势是否过度设计:

  • “一切”的包装:包装很有用,但很容易过度。检查您是否只包装真正需要包装的东西。 (我基本上把自己的包装纸包裹一次。我知道我在说什么;-)。)
  • 重新发明轮子:经典。这很常见,你已经提到过了。您是否实现了某些功能,因为需要想要的?你的框架做了什么,其他可用的库没有?
  • “感觉”过度设计:这是最重要的一点,但也是最难看的。看看你的代码,看看哪些部分感觉过于复杂。问自己,然后是否有更简单的方法来实现它以及为什么你没有选择这种方式。如果你得不到好的答案,那么这部分可能就过度设计了。

这些只是我用于我的应用程序的快速提示。它们不能保证是“过度工程检测”的全部和最终结果。

答案 7 :(得分:9)

当一个同事的电脑飞过你的头脑,因为他们花了最后6个小时尝试并且未能使用你荒谬的框架出现一个怪异的对话框,那就是一个非常具体的症状。

答案 8 :(得分:8)

在查看过度设计的内容时,会想到避免使用YAGNIDRYKISS。如果有许多部分似乎已部分完成,并且许多部分代码似乎都有,“如果发生这种情况怎么办?如果发生这种情况怎么办?”感觉到,这将是另一个观点。忽略good principles of OO designSOLID principles将是另一个需要注意的问题。如果你认为你已经编写了完美的代码,那将是另一个麻烦的迹象,因为任何人写一些无法以这种或那种方式改进的东西是极其罕见的。

IMO,请注意,有些人可能过分批评您的工作,因为任何代码库的一部分都可能涉及到人们喜欢某种方式的事情,例如关于方法,测试和变量的命名约定。就是那样子。现在,您可能需要弄清楚的是如何处理人员,例如conflictpersuasion/influence,这些工具可以提供帮助。

答案 9 :(得分:6)

为您的应用提供内在功能的插件

让我们面对现实,可插拔的架构只是该死的性感和写作的乐趣。然而,这是你需要问自己的另一个领域,“我真的需要这样做吗?”。

如果您不需要对应用程序进行临时添加,请不要指望任何人编写第三方扩展,并且您的应用程序范围相当明确,您不需要可插拔架构。

您不应该编写插件来支持应用中的内在功能。假设您正在编写一个Paint程序;您可能支持以多种格式保存文件的插件,但您不需要可插拔的撤消管理器或文件浏览对话框。

答案 10 :(得分:5)

你不是建筑宇航员。 LINQ非常简单,基本且有用。 .NET 3.5也是如此。

与此同时,你是团队中的新手,即使他们喜欢你所做的事,也会得到一些罗纹。

用一粒盐把它全部拿走。接受他们的批评,点头,然后和他们一起喝啤酒。

如果他们要求你改变它,那么你的评论就是“jeez ..我知道我做错了,但它确实有效,改变就太麻烦了。”

答案 11 :(得分:3)

尝试评估您是否已采取措施尽量减少代码预期寿命期间的工作。这包括维护和开发。

在代码生命周期中,请记住代码的生命周期与应用程序的生命周期不同。最好先写一个快速原型,然后在更好地理解域之后重新设计/重构。在这种情况下,生命周期很短,所以保持简单。

此外,不同的应用程序需要不同的工程设计。如果失败,这个应用程序是否会耗费生命?即它是机械心脏控制器,还是航天飞机导航火箭的控制器?或者它是无聊青少年的联系人列表?

答案 12 :(得分:3)

在更通用和更高级别的方法上,

I feel that when there's a gap between the complexity of the problem and
the complexity of the solution, then you have a clear case of overengineering. 

实现这一目标的方法有哪些? 解决你没有的问题,看到问题更加复杂,将来做太多预测,建立过于通用的东西,等等。

答案 13 :(得分:2)

您是否在合理的时间范围内实施了项目?它现在正在运作吗?如果是这样,你可能会放松一点,因为过度工程的最大问题之一就是从来没有真正做过任何有用的事情。

你们谈过的那些人也可能有一些好的建议,但这并不意味着你需要把他们所说的一切都当成福音。例如,在新项目中使用最新版本的.NET并不会让我担心。他们真的在抱怨这个吗?

答案 14 :(得分:2)

其中一半是老人(我在他们的联盟中)坚持他们所熟知的久经考验的蒸汽机。另一半是真的,但并没有真正告诉你任何新的东西。

除此之外,Jeff Sternal的答案很棒。

答案 15 :(得分:0)

作为一个专业开发软件24年的人,我只能说这个问题 - 在特定问题所需的抽象层次上调用 - 是最难的部分我的日常设计&amp;编程工作。

在&#34; old&#34;天,工程不足很普遍,这导致了所有结构化的方法和实践。现在,似乎我们走了另一条道路。没有简单的答案,有时候你只会知道你是否在后见之明;或者

我曾经有过多次事后的经历,我对自己说:&#34;我希望我没有让这么多事情变得复杂,而且#34;如果我只是听了在我脑后的小声音,并使它在这里变得更通用了#34;。

我还没有提出打电话的绝对规则......

我怀疑我很容易过度工程,所以我将这张照片设为我的电脑壁纸

答案 16 :(得分:0)

有点想提供不同的观点,但我认为这个术语应该被删除并用更合适的描述代替。它给工程学带来了耻辱。这应该是关于简单性,可维护性和实用性的,当很多被描述为&#34;过度工程&#34;具有完全相反的品质(好像工程设计太多,或者认真对待它,应该产生最复杂的解决方案)。例如,通常会看到过度工程和不良测试程序之间的关联(至少我经常看到这两者是相辅相成的),以及工程中的哪种过剩会执行最少量的正式测试?

我说这是从我经常听到软件管理员和偶尔恐龙的观点来看,他们并不是那么精通SE的人会把这个术语推给那些试图降低系统维护成本或建议的人更健全的测试程序和安全标准。外行人认为任何一种严肃的注重声音工程,测试,而不是按照他们想要的冲刺式按扣式快速制作代码来进行过度工程&#34;过度工程&# 34。

有很多人真正认识到过度工程的真正气味&#34;但这个词至少可以说具有误导性。

至于症状,除了已经提供的优秀症状之外,对我来说,能够正确评估和重新评估你面前的工作是一个盲点。程序员可以在他们的想象中建立世界,被高耸的概念所迷住和吸收。虽然这是一种无聊和通用的答案,但这可能导致不再看到实际问题和优先事项的危险。概念化过于深入的是经常发展一个关于我们面前的问题,使问题过于复杂,与现实失去联系以及实际用户端需求的盲点。对我而言,最值得关注的症状是心理学。

围绕生产的各种职业都容易受到这种基本趋势的影响,在这种趋势中,由于过于沉迷于概念而无法解决实际和眼前的问题(例如电影导演)。对于一般的编程,一种打击它的方法是在概念化到n度之前更快地支持简单性,简单性,实用性,编码(在我们深深爱上任何想法之前,给我们更多时间重新评估)。人们不能错过这些理想,但关键是要避免发展阻碍我们正确评估自己工作的盲点。一个过度设计的代码库并不会在一夜之间发生 - 它需要花费大量专门的工作才能产生它,而对我而言,最大的可预防问题不是远见相关,而是经常发展正确的后见之明。晚。