设计模式会皱眉吗?


135

我与从事此业务20年的一位高级开发人员进行了讨论。他在安大略省以撰写博客而闻名。

他告诉我的事情很奇怪:他说,有一段代码是一场噩梦,因为它是从一本教科书中编写的,并不说明现实世界。将新字段添加到UI /数据库/数据层需要2-3个小时,而在他的代码中则需要30分钟。

另一件事是,他避免使用设计模式,因为大多数程序员都不了解它们,并且从维护的角度来看它们也不是很好。

还有一种想法是,加拿大的大多数Web开发人员都希望其数据模型继承自Data Layer类,而不是保持隔离状态。我问他:“将模型与数据层分开不是行业标准吗?” 他有时说,但是这里的大多数人不愿意这样做,因为这工作太多。

听起来他之所以不使用最佳实践进行编码,是因为这是一场维护噩梦,很少有员工了解(除了我自己),如果您需要在几天内推出新功能或新领域,工作起来会很慢。时间。

考虑到Stack Overflow主要鼓励人们遵循行业标准,听到这样的意见真是太奇怪了。我们是否被迫在几天之内不断推出新的领域和功能,以至于无法推断出足够灵活的坚实模式呢?这似乎是我从中了解的要点。

您如何看待这些陈述?



67
我个人对任何被称为“最佳实践”(没有正当理由)的东西感到不安,因为它通常表示“我不知道为什么这是一个好主意,但我还是希望您这样做;结束讨论”
理查德·廷格

34
行业标准,设计模式和最佳实践只是“某人说的东西在其上下文中可以更好地工作的条件,因此也应该在您自己的情况下。”®。您的高级开发人员的权利。
CptEric

86
这与敏捷无关。
Lightness Races in Orbit

68
“高级MVC开发人员”“设计模式很糟糕”的认知失调
Dan Pantry

Answers:


239

这是一个已经成功的人的话,而忽略了那些试图告诉他该用他不理解的模式行话的人的话。

设计模式和最佳实践不是一回事。 有些人认为自己是现实,并驱使知道自己在干什么的人发疯。即使他们不知道他们在做什么的正确名称。

设计模式在命名之前就已经存在。我们给他们起了个名字,使他们的交谈变得容易。具有名称的模式不会使其成为一件好事。它使它成为可识别的东西。

这个人可能使用的是您从未听说过的模式。很好,直到您需要与他谈谈如何完成工作。他要么必须学习如何与您交谈,要么您将不得不学习如何与他交谈。与谁是“正确的”无关。


12
需注意的是,当今大多数人使用“设计模式”一词时,通常是指“ 四人帮”
罗伯特·哈维

35
是的,我喜欢使用英语,这对我来说很有意义。不知道为什么法国人需要这么长时间才能采用它。直到他们做到为止,我将继续学习有关该度量标准的知识。
candied_orange

6
可能不是他不了解,也可能是他确实了解了,但他知道并不是所有情况都适用于所有情况。
whatsisname

148
“具有名称的模式并不能使它成为一件好事。它会使它成为可识别的事物。” 噢,我的天哪,这是我所听过的问题的最好总结:D
轻轨赛

7
@JanDoggen之所以称为(反)模式,是因为它们也是软件开发中的常见模式(其中一些是与设计相关的模式)。
JAB

96

您和您的朋友描述的许多设计模式实际上只是针对编程语言缺陷的解决方法。使用更具表现力的编程语言,这些设计模式的大部分需求都消失了。

由于需要良好的设计模式来适应许多可能的使用场景,因此它们往往设计过度。过度设计的代码会产生成本:您必须阅读它,了解它的作用,并了解它在整个软件系统的上下文中如何工作。因此,与其他任何软件开发技术一样,您必须对照使用该技术的成本来评估该技术,并确定收益是否超出成本。

在所有其他条件相同的情况下,代码越少越好。 我已经遍历了分层体系结构,在这些体系结构中,您实际上必须在多个项目中进行三到六跳才能找到任何有趣的代码,也就是说,这些代码实际上可以完成除增加开销之外的其他事情

众所周知的软件模式应该为您提供通用的词汇表,您可以通过这些词汇表交流设计策略。不幸的是,许多软件开发人员对软件模式词汇不够了解,无法正确地将其应用于编程问题。没有经验的开发人员将这些模式视为专家的权限之内。他们希望被视为专家,因此他们在准备就绪之前就尝试过早学习和应用模式。相反,他们真正应该做的是首先专注于学习编程的基础知识,然后尝试解决每种模式都能解决的问题。如果他们这样做,他们将处于更好的位置,可以正确地理解和应用模式。


19
好吧,这是与您在问题中描述的问题不同的问题。我现在工作的商店生动地证明了您可以敏捷并且仍然具有非常干净,精益的代码,易于维护,但是,这不是大多数Java商店中常见的企业级,多层的东西,并且相当其方法是“非标准的”。我们没有一年以“企业”方式构建应用程序。
罗伯特·哈维

34
@ Igneous01:请注意,从未有任何实际经验的教授认为“好”的东西可能与试图赚钱的企业认为“好”的东西完全不同。
罗伯特·哈维

8
“不幸的是,许多软件开发人员对软件模式词汇不够了解,无法正确地将其应用于编程问题。” 简而言之,这就是我。=)我见过的名字少数,我有一个非常困难的时候,看上一个真正执行起来。我可能已经编写了一些代码块,可以将其分类为实现模式,但是我肯定无法告诉您哪些代码。我开始认为模式比实际可解密的代码重要得多,并且需求更改仅影响几个代码位置。
jpmc26 '16

35
尽管我会以“用更少的代码总会更好”为由来作麻烦,因为我知道它会导致看起来像疯子的代码,但我会热情地同意“模式可变性”的观点。不要抱怨我的代码很烂,因为您无法在教科书中找到它。有很多非常好的理由来称呼我的代码废话,但这不是其中之一。
candied_orange

23
“实际上可以完成除增加开销之外的事情的代码”-我认为企业软件的目标是应该没有实际上可以完成任何事情的代码。该软件可能具有的任何实际行为,要么应该是分层设计的新兴属性,要么应该由将代码视为数据的业务规则进行表驱动。我只是在开玩笑的50%。
史蒂夫·杰索普

86

Stackoverflow.SE和Programmers.SE大多鼓励人们遵循SOLID等最佳实践,而不是行业标准。不管您相信与否,事实上的行业标准通常是“泥潭”架构-认真地讲。

但是要直接回答您的问题:设计模式的问题与继承的问题类似-许多平庸的开发人员过度使用它们,这存在创建过度设计,难以维护的代码的一定风险。但是,这样做的答案肯定不是完全避免或禁止使用设计模式(或继承),答案是学会在有意义的情况下(仅限于此)使用这些工具。这完全独立于“敏捷”与否。


我认为您的陈述“设计模式的问题与继承的问题类似-许多平庸的开发人员过度使用它们”的特殊性是不必要的……在编码的所有方面,开发人员可能没有适当地使用某些东西的知识经常会滥用它,并编写次优代码。一般而言,这可以被视为发展的公理。
杰里米·霍洛瓦克斯

1
@JeremyHolovacs:不完全是。我看到的问题是,即使是受过良好教育的开发人员也会过度使用它们。我经常看到解决方案,在这些解决方案中,经验丰富的开发人员试图将问题塞入“某种程度上”适合但并非很好的模式。
布朗

45
  1. 设计模式只是用于传达思想的名称。我经常发现自己做的事情后来被发现有名字。因此,与“非设计模式方式”相反,没有“设计模式方式”。

  2. 设计模式是准则。作为一切,它们每个都有优点和缺点。关键不是要学习模式并将其应用到适合的位置,而是要了解模式的概念,模式的优点和缺点,并利用它来获得解决问题的灵感。

  3. 如果有足够的理由,则可以忽略所有最佳实践和准则。有效的原因包括开发时间和对应用程序的期望。例如,我知道对值进行硬编码(愚蠢的示例)是不好的,但是对于概念验证而言,优势可能超过成本(在这种情况下,主要是开发时间)。但是,如果做出这样的决定,则可能事与愿违,有时可能需要重构。


5
RE:是的,是的,是的-我发明了模板样式。我只是没有先做。或诸如此类。
格林(Grimm The Opiner)

29

为了给汤加个比喻,设计模式是Microsoft Office帮助程序Clippy。“您似乎对很多东西都做同样的事情。我可以通过向您提供Iterator或Visitor来帮助您吗?”

正确记录这些模式将表明何时以与以前多次相同的方式进行操作很有用,第一次尝试时会犯哪些错误,以及找到了避免这些错误的常见方法。因此,您阅读了设计模式(或从内存中查看了它),然后继续进行工作。您无法做的是使用Clippy和向导。

经验不足的人可能会犯错误并编写不考虑现实的代码,这是当他们认为他们的设计模式列表是解决软件问题的所有可能方法的完整列表,并尝试通过将设计链接在一起来设计代码时直到完成。在野外观察到的另一种较差的策略是,在设计模式“是最佳实践”的基础上,将设计模式塞入并非真正适合的情况。不,对于实际解决的问题,这可能不是最佳实践,但对于无法解决的问题或仅在存在更简单的解决方案时仅引入不必要的复杂性来解决的问题,这当然不是最佳实践。

当然,也有可能某人基于YAGNI避免使用某种模式,然后意识到他们确实需要这种模式并摸索正常的解决方案。这通常(但不总是)比从一开始就实现需求更糟糕,这就是为什么即使在敏捷开发中,如果没有尽早发现可完全预测的需求也会令人沮丧。我不能成为唯一一个对Java最初拒绝通用容器过于复杂而感到惊讶的C ++程序员,后来又将它们重新绑定。

因此,原则上避免编写Iterator几乎是一个错误,因为您希望避免使用设计模式。

将新字段添加到UI /数据库/数据层需要2-3个小时,而在他的代码中则需要30分钟。

您真的不能对此提出异议:按照这个指标,他的设计要比其他设计好得多。不管是因为他避免了设计模式还是值得怀疑的,但我认为这更有可能是因为他在设计时考虑了正确的“现实世界”问题,并且由于经验的优势,他的工作比仅仅拥有一本教科书的人更好。崇高的理想。

因此,他认识到任何需要您在代码中触摸很多不同点以添加字段的模式都是对工作不利的模式,“使添加字段变得容易”,并且他没有使用这些模式。分层体系结构确实在这方面可能会遭受损失,并且使用设计模式而不意识到其缺点是错误的。

与此相反,在他的设计中编写新的UI需要花费多长时间,而在分层体系结构中则需要花费多长时间呢?如果该项目要求他在固定数据模型上不断构建和部署新的UI,而不是不断添加字段,那么希望他会为此设计。还是一样。但是,尽管有其所有好处,可悲的是说“我们在做敏捷”并不意味着您永远不必进行其他折衷!

从设计模式菜单中进行选择肯定会阻止您思考最重要的问题。但是,在识别出您正在编写“访客”并将其记录或命名为“访客”以帮助读者快速获得它的过程中,并没有多大碍事。由于高级开发人员给出的原因写“这是一个访客” 而不是正确地记录它是一个可怕的错误-程序员不会理解。即使是知道访问者是什么的程序员也需要更多的信息,而不仅仅是“这是访问者”。


5
“设计模式是Clippy的Microsoft Office帮助程序”今晚我将做噩梦。
MetalMikester's

“没有经验的人会出错的地方是(当他们)尝试通过将设计模式链接在一起直到完成为止来设计代码。” 听见。我希望我能给予多个支持。:)
Quuxplusone

我也希望我对最后一段有多个投票。设计模式是编程的词汇:如果您拥有大量词汇,那么您将是一个更好,更清晰的作家。我可以告诉大家一个工厂生成器,当我看到他们,但我没有从阅读设计模式的书籍,任何比我更学会了如何讲一个峭壁虚张声势通过阅读一本英语词典。
Quuxplusone

20

您的同事似乎患有NIH综合征(“此处未发明”)。

他的代码可以使添加新字段更加容易:但是这种短期的速度并没有说明代码的可维护性和可移植性。我会给他带来疑问的好处:如果现有的代码不正确地遵循教科书或在错误的上下文中遵循了正确的配方,则可能确实构成了错误的结构。

避免设计模式确实令人惊讶。在我过去的30年编码和管理编码人员的工作中,设计模式有助于对本能地完成的事情进行措辞,从而帮助他们更快地理解其意图,优势,不便,风险,机会和相关模式。设计模式被证明是掌握复杂性的真正加速器!

  • 也许您的同事确实比我们大多数人聪明得多,并且他可以负担重塑模式的开销,而不会明显降低生产率?

  • “程序员不理解设计模式”的说法听起来像“我无法真正解释自己在做什么”。或“我不想争论自己的设计”。我真的认为,模式化可以利用整体理解,并且可以让较少的高级同事分享宝贵的意见。但是,也许您的高级同事希望避免这种情况。

在大多数企业应用程序中,分层方法已被证明优于其他体系结构。世界一流的领先套件围绕这一理念构建,并且在性能上优于手工建筑。马丁·福勒(Martin Fowler)在他的优秀著作《企业体系结构模式》中介绍了这种方法。哦! 再次抱歉:这是关于经过验证的模式的;在您同事的NIH观点中没有机会;-)


NIH综合征,有趣,我以前从未听说过。显然,这是大多数北美雇主面临的如何管理员工的问题!
支付

@pay我不确定这是否仅限于北美;-)总是很想寻求我们过去已经使用的解决方案并取得了一些成功。这是舒适区。但是,人们应该始终保持开放的态度,与富有挑战性的同事进行新想法和建设性对话。毕竟,“ 您一个人旅行得更快,但一起走得更远。
Christophe

16

许多人错过的一个关键见解是软件设计是上下文相关的。存在它是为了达到业务目标,并且不同的目标可能需要不同的方法。换句话说,即使总是有最佳设计,也没有永远是最佳的设计。

设计模式是解决标准问题的标准解决方案。但是,如果您没有遇到问题,则解决该问题很费力。

瀑布式设计与敏捷软件设计之间的主要区别在于制定设计决策。在瀑布图中,我们收集所有需求,确定所需的设计模式,然后才开始编码。在敏捷架构中,我们遵循YAGNI原则将设计决策推迟到最后一个负责任的时刻,届时我们将尽可能多地了解选择。

也就是说,在瀑布式设计中,如果在实际需要时敏捷地预期了它们的需求,则倾向于应用设计模式。结果,敏捷项目倾向于较少地应用设计模式,因为并非所有预期需求都是实际的。


1
为+1 Design patterns are standard solutions to standard problems。我有点失望,没有在更合适的答案中看到这一点。因此,这首先需要确定您的问题是否正在与标准问题相吻合,而且通常情况下,它们会让人满意。
Walfrat'9

8

设计模式并不是真正的设计模式,因为它们规定了要做的事情。设计模式之所以是设计模式,是因为它们描述了以前所做的事情。一些开发人员或某些开发人员设计了一种方法,可以很好地完成特定任务,并且能够将其应用于具有相似结果的相似情况。仅此而已。许多模式具有固有的优点和缺点,并且受过教育的开发人员应评估技术和业务需求,以确定适合的模式。

因此,除非您真正致力于编写100%的一次性代码,否则在一个用例到下一个用例中都没有可用的概念或实现,几乎可以肯定,您至少会使用某些设计模式。它们可能没有浮华的通用名称,例如“存储库”,“工作单元”甚至“ MVC”,但这并没有使它们“不是设计模式”。


6

我通常喜欢以使用GPS进行“导航”的方式来思考。当学习“最佳实践”和“设计模式”时,您将学习采用GPS导航路线。但是,当您知道该区域时,您通常会学到沿小路行驶会带您经过有问题的区域,从而使您更快和/或更好地到达那里。在处理这些事情时,它们几乎是一样的-经验使您能够解构工具箱并采取捷径。

学习设计模式和学习“最佳实践”意味着您可以了解背后的想法,以便可以在给定的情况下进行选择。由于现实生活中的情况通常比理论上的情况要复杂得多,因此您经常会遇到教科书中没有的限制和问题。客户/客户希望他们的产品快速且通常便宜。您需要使用遗留代码。您需要与第三方工具进行交互,这些工具很可能是黑匣子,效果不佳;和各种各样的事情。您的情况是特定的-最佳做法和模式更为通用。

SE之类的网站上的许多人会为您提供“最佳实践”答案和“设计模式”答案的一个主要原因是,因为他们在通用和抽象的解决方案中进行回答,因此有助于提供一种通用的语言来解决一种类型的问题。问题。并让您学习。

所以-不-在敏捷开发环境中不会皱眉设计模式;然而,开发很少是通用且抽象得足以完美地适合模式的,并且(经验丰富的)开发人员也知道这一点。


5

将新字段添加到UI /数据库/数据层需要2-3个小时,而在他的代码中则需要30分钟。

如果要“优化”设计,则需要说明要优化的内容。

例如,赛车是一种优化的车辆,而波音747也是一种优化的车辆,但是它们针对不同的要求进行了优化。

例如,“ MVC”模式的想法针对以下方面进行了优化:

  • 同一模型的不同视图(视图独立于模型)
  • 可以在集成之前分别开发每个层(例如由不同的团队)并分别进行测试(单元测试)
  • 等等

而他的代码可能正在针对其他方面进行优化,例如:

  • 最少的代码行
  • 一个人可以轻松进行会影响所有层的更改(因为根本没有真正不同的层)
  • 等等

模式描述始于对要解决的问题的描述。如果他认为不使用特定模式是“最佳实践”,那么(假设它不是一个愚蠢的模式,假设这是一个有时有用的模式),我想他没有/经历过该模式声称的特定问题解决,和/或他遇到了另一个(更大或更紧急,更具竞争性的)问题,而他正在尝试对此进行优化。


“根本没有真正不同的层”-或者,公平地说,是具有通过层传播的可接受的“默认行为”。例如,基于Web的SQL管理员应用程序是表示层,当数据库层更改时会自动更新自身。只是,除了有限的用途外,它们实际上并没有按照您希望呈现给用户的方式来呈现您的数据:-)半小时似乎难以置信地增加了一个新字段,这表明没有可用于设计的重要UI与新字段的连接,分层或其他方式。
史蒂夫·杰索普

4

设计模式是工具。像工具一样,有两种使用方法:正确的方法和错误的方法。例如,如果我给您一把螺丝起子和钉子,并要求您将两块木头连接在一起,您应该问我一把锤子。锤子用于钉子,螺丝刀用于螺钉。

通常,一种设计模式被宣传为“一种真实的方式”,通常仅在出现特定问题时才适用。初级开发人员在寻找新玩意时通常像孩子一样。他们想将这种设计模式应用于所有事物。只要他们最终了解到模式A适用于问题B,模式C适用于问题D,就没有内在的错。就像您不使用螺丝起子来钉钉子一样,您也不需要使用特殊的工具。模式仅仅是因为它存在;您使用模式,因为它是完成任务的最佳工具。

模式的反面是反模式。一次又一次被证明是不好的事情,通常是在执行时间或内存方面。但是,模式和反模式对不了解它们为什么存在的开发人员都不利。开发人员喜欢认为他们所做的是新颖且富有创造力的,但在大多数情况下却不是。以前可能已经想到过。在他们之前的人们由于经验而创建了模式。

当然,初级开发人员似乎经常想出新的做旧事情的方法,有时这些方法会更好。但是,最终常常导致邓宁-克鲁格效应。开发人员仅了解足以编写功能程序的知识,但不了解自己的局限性。克服这一问题的唯一方法似乎是通过正面和负面的经验。他们不理会模式,因为他们相信自己是高级的,但实际上,不知道有10,000个开发人员已经使用了一种特定的设计,然后因为它确实很糟糕而将其丢弃。

在迅速适应不断变化的客户需求方面,Agile倾向于“以响应方式完成工作”。它既不支持设计模式也不鄙视它们。如果模式是最快,最可靠的方法,则开发人员应使用它。如果一个特定的模式比简单地“完成它”要花费更多的时间,那么使用不是模式的东西就可以了(当然,假设性能不会受到严重影响,等等)。如果找不到已知的模式,则优先设计自己的模式,而不是告诉客户“否”。客户,尤其是付费客户,通常是正确的。

任何声称模式是“道路”或声称模式是“存在的祸根”的人都是错误的。模式是工具,旨在应用于特定情况,并根据情况具有不同程度的成功。这是一个事实,与您是否选择MVC,是否使用数据传输对象等无关,这是事实。重要的是在相当短的时间内实现代码,这对于用户来说表现不错,并且没有逻辑错误。

通常,模式将允许一种连贯的设计形式,并且比忽略所有模式来表现更好,而倾向于编写100%的原始想法,但是您不能避免所有模式。例如,如果y = x + 5,您是否真的要编写y = x +(5 * 3 + 15/3)/ 4,只是为了避免写x + 5的模式?不你不是。您将要编写y = x + 5,然后继续下一个问题。

人们每天都在使用模式,这没关系。最重要的是拥有具有逻辑功能,很少崩溃且易于使用的代码。没有什么比这更重要了。


我认为需要注意的是,根据您对问题和领域的“当前”理解,您可以创建一个新的类或遵循一种适用于这种情况的模式,但是第二天客户希望您这样做对它们进行自定义,使其具有其他客户端在其版本中不希望使用的一些小方面。合并满足2打客户端需求并避免复制面食的代码库似乎是不可能完成的。我今天在重构旧的邮件合并过程时遇到了这个问题。
Igneous01'9

2

您不能“避免设计模式”,除非我想避免以相同的方式设计系统的任何两个部分(我不建议这样做,并且我怀疑您的高级开发人员正在这样做)。他可能的意思是“避免仅仅因为坚持设计模式而盲目使用设计”。考虑自己在做什么绝对是一种“最佳实践”,应该有一所大学可以教书;可悲的是,这似乎没有发生。


2

设计模式与敏捷实践并不对立。与敏捷实践相对应的是,为了使用设计模式而使用设计模式,这是应届毕业生和学生之间的普遍做法,是按照“我们将如何使用工厂模式解决此问题”的思路进行思考。

敏捷意味着选择最适合工作的工具,而不是试图根据所选工具来调整工作形状。
这就是所有常识性开发实践的基础(尽管您当然常常必须做出让步,因为您可以选择的工具通常受公司标准,许可限制(例如GPL和某些其他开源工具的限制)限制不能使用,尤其是在构建用于转售的软件时)之类的东西。

您的同事/朋友可能反对您的代码,不是因为它本身使用了设计模式,而是因为它是一种人工构造,旨在在其他设计会更好时显示特定模式的使用(尽管通常是主观的,我已经(并且毫无疑问,很多人)已经看到了很多例子,其中强迫使用特定的设计模式会导致丑陋,难以维护以及效率很低的代码。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.