如果您在诸如敏捷或XP的进化方法中达到设计死胡同,该怎么办?


11

当我阅读马丁·福勒(Martin Fowler)著名的博客文章《设计死了吗?,我得到的惊人印象之一是,鉴于在敏捷方法论和极限编程中,设计和编程都是进化的,总有一些地方需要重构。

当程序员的水平很好并且他们了解设计的含义并且没有犯严重错误时,代码可能会继续发展。但是,在正常情况下,在这种情况下的地面现实是什么?

通常情况下,产品会进行重大开发,而当需求发生重大变化时,这是否不是我们想要多大的期望就不能修改基本设计方面的约束呢?(而不会丢弃大部分代码)。在设计和要求方面的任何进一步改进方面,人们不太可能走到尽头吗?

我不是在这里提倡任何非敏捷实践,但我想向实践敏捷,迭代或进化发展方法的人们了解他们的真实经验。

你有没有遇到这样的死胡同?您如何避免或逃脱了它?还是有措施确保设计在发展过程中保持清洁和灵活?

Answers:


17

我刚刚读了您发布的文章链接,我不得不说Fowler提出了一些非常好的观点,他说了很多话,多年来我一直在与我们的团队一起提倡。

海事组织,如果您进行任何体面的设计,则不应陷入困境。我一直认为软件是由构建块组成的。我仍然相信一些前期设计,但主要目标不是设计整个产品,而是提供总体架构/方向,以便您的团队可以形象化我们正在努力的共同构想。如果您有一堆立方体和三角形的零件,那么在您开始将零件拍在一起之前,先勾勒出城堡的组装方式会很有帮助。

由于我来自OO领域,因此对我来说,每个块都是一个类,并且该块的表面积是公共接口(外部或派生类可见的)。如果您遵循良好的SOLID原则,则将确保每个块都非常简单并具有直观的公共界面。回到我的类比,您想确保代码仅创建简单的形状。每当创建太复杂的类(许多函数,许多变量)时,您都会创建形状,这些形状在需求变化时很难重用。

我同意福勒的观点,因为进化设计的最大风险/挑战是您将设计决策留给编码时间,并且您希望每个开发人员都能做出这些决策。如果您没有适当的反馈机制,则系统可能会在这里崩溃。每当需要新功能时,非常容易找到需要扩展的功能,在其中添加某种条件,然后在该功能内添加一堆代码,这非常诱人。有时,这可能就是所有需要的东西,但这也是(IMO)导致死胡同组件的最常见惯例。这与进化设计无关。这就是所谓的“无设计”。

只要您花时间退一步说,等一下,该类已经有15个成员变量,让我提取其中的6个成员变量并放入自己的独立类中,您的软件将非常轻便重量轻,灵活且可重复使用的构建基块。当然,如果PM出现并改变了您对产品的要求的一半,您可能必须将一些积木拿出来,放回架子上并绘制一些新的积木(就像建造城堡时一样,您可能不会使用全部您的气瓶)。但是到那时,这只是做生意的一部分。需求已更改,并且通过保持代码灵活和模块化,您应该能够更改产品以使其与新的业务方向保持一致。

我相信,这种不断发展的设计方法可以适用于工程师的各个水平。就个人而言,我从事软件工作已经很长时间了,在我们的团队转向敏捷方法论之前,我负责几乎没有任何质量检查就将开发PC的几个主要组件直接运送给客户。同时,这些组件始终保持灵活性和可维护性。

我只是想说我认为自己在设计软件方面相对不错。同时,如果您要我写一份100页的设计文档,将其交给编码人员,并希望它能起作用,那么我可能无法用纸袋设计自己。在开始工作时,有时会绘制一些类似于UML的图(非常简化,而不是完整的语言),但是当我开始编码时,我将在需要的基础上进行重构,而最终的代码将永远不会像我最初绘制的那样。即使我花了一个月或两个月的时间来思考每个小细节,我也无法想象其他人能够使用我的图表并开发出可靠的软件,而无需在编码时修改设计。

另一方面,目前在我的团队中(现在很敏捷,我完全支持),我们有几个人是从嵌入式领域加入我们的,在过去的15年中,他们只做过C语言。显然,我为一些初步的计划和布置课程提供了帮助,但是我还确保定期进行代码审查和集思广益,以讨论SOLID和设计原理的应用。他们确实产生了一些意大利面条式的代码,这使我有些畏缩,但在我稍加推敲的情况下,他们开始重构已经产生的内容,有趣的是,其中一个人几天后又回到我身边说,我讨厌可以这么说,但是将代码移出后,它看起来更具可读性和可理解性。死胡同。点我 我想做的是,即使是对OO完全陌生的人,只要他有一位经验丰富的导师,也可以产生一些体面的代码,以提醒他“进化设计”与“无设计”是不一样的。甚至他的一些“更复杂”的类也不是那么可怕,因为每个类都没有那么多的责任(即没有那么多的代码),所以如果一个类“死胡同”,最糟糕的情况就变得更糟了。扔掉它,并编写一个具有相同公共接口的替换类(到目前为止,我写过的任何东西都从未见过这种偶然性的需要,而且我每周进行两次代码审查)。

最后一点,我也是设计文档的坚定支持者(至少对于我目前团队的业务状况而言),但是我们的设计文档的主要目标是组织内存,因此实际文档是在代码生成后编写的,重构。在进行编码之前,我们通常会经历一个快速(有时不是那么快)的设计阶段,在该阶段我们在餐巾纸/ mspaint / visio上绘制类的草图,我总是提醒人们,这一阶段产生的是遵循的道路,而不是蓝图,并且在他们开始编码时,任何没有意义的东西都应该改变。即使有这些提醒,新手还是会尝试将适合自己的代码放回到原始设计中,即使对他们来说感觉也不自然。这通常在代码审查中浮出水面。

堂,我写了很多东西 对于那个很抱歉。


1
+1每个字都值得。我确实遇到了您所描述的这些情况,并且在截止日期之后,请他们从我认为是设计常识的内容中进一步清理(读取重构)。但是人们经常会重复发现相同的问题-为什么我又要做同样的事情?我想现在我有了答案-如果您需要更快的上市时间,并允许设计发展,那么重构并不是对您以前的过错的补偿,而实际上是合法的事情。
Dipan Mehta

是的,您写了很多,但这是一件好事。非常喜欢阅读它:)。
Radu Murzea 2012年

11

我会说“设计死胡同”现象与敏捷方法正交。我的意思是说有可能做瀑布,花很多时间在(不好的)设计上。然后花很多时间实施它,却发现自己陷入了死胡同。

如果有的话,敏捷方法应该可以帮助您及早发现做出错误设计选择的机会。这样做的原因是您的待办事项应该首先完成最高客户价值的项目,并且您应该专注于交付有用的软件增量。如果您的设计允许您提供高价值和实用性,那么它已经对某些事情有所帮助:-)相反,在瀑布般的情况下,您可能会有一个糟糕的设计,在这种情况下,您可能多年都找不到这种设计了任何价值和实用性-您所拥有的只是它是一个好的设计的幻觉。正如他们所说,证明在布丁中。

不利的一面是,即使在敏捷方法中,对系统设计的可行愿景也很重要,因为该系统驱动决策在迭代之间进行。我认为Ken Schwabber说过类似的话,如果您有一个可怕的开发人员团队,他们将不断迭代地产生糟糕的软件。敏捷只是意味着不要花很多时间在前,因为在开始实施之前,您在学习或想象中会受到限制(并且需求也会发生变化)。但是,在某些情况下,您必须先做一些工作(例如研究),然后再去做。

您如何避免死胡同?

我主要是通过预测将来的需求来表示的。这是您对类似项目/产品有经验和熟悉的东西。这种预期的部分原因是可以帮助您进行良好的设计,因为您会问自己很多有关当前系统的“假设”问题。对我来说,这是至关重要的组成部分。当您已经知道自己在做什么时,诸如OO之类的技术只是在帮助您。

如果遇到死胡同,该怎么办?

一个“死胡同”与您在开发任何新颖的东西时遇到的其他技术障碍没有什么不同。首先要意识到的是,确实没有真正的“死胡同”迫使您完全退缩。至少到现在为止,您的学习是使您前进的动力,因此,工作没有浪费。当您陷入困境时,您会遇到问题。问题是需要更改哪些内容以满足新的(或旧的)需求,以及如何优化进行此更改。您现在要做的就是解决这个问题。值得庆幸的是,这是软件而不是软件,例如飞机设计,因为更改要容易得多。确定问题,解决问题==重构==软件工程。有时涉及很多工作...

如果您使用Scrum,则此更改自然应该来自用户故事(用户从此更改中得到什么?)。该过程将从一个故事开始,而当前的设计(oops)很难轻易地适应这个故事,然后与产品负责人就如何分解这个故事进行讨论。您将通过此更改继续应用敏捷原则。

我想到了一些来自OS领域的著名的大需求变更:

无论您以哪种方式看待它们,它们都需要大量工作。原始设计几乎可以肯定没有考虑到这种情况的发生(即,可移植性并不是一个很大的要求)。设计是否为OO也可能不是一个很大的因素。在一个好的设计中,平台的特定部分会有些隔离,工作会更容易。


实际上,Windows NT的早期版本实现了“硬件提取层”并支持DEC Apha和x86。由于没有人购买过基于DEC alpha的计算机,因此悄无声息。我可以想象这种“机器独立性”在当前版本中仍然以残余形式存在,因此ARM端口可能并不那么难。
James Anderson

3

我可以永久重构项目,也可以使用UML类图。我的意思是我按包创建一个或多个类图。每个图都保存在包的根目录中。每个UML分类器都有一个自己的ID,该ID映射到相关的Java ID。这意味着当我打开图表时,它会自动更新为最新的代码重构更改。我还可以在图形级别直接更改类图,并且可以立即重构所有项目。它工作得很好,但是它永远不会替代人类。我的UML类图也是我的代码的图形视图。不要像EMF eclipse那样混合代码和模型,这很重要,因为一旦重构完成,模型信息也会丢失。我从不使用模型驱动开发代码生成器,因为这没有用。我不

话虽如此,拥有100多个类图代表我的项目结构的所有细节,并且到处都有注释,这确实很有帮助。我只为项目创建类图,因为通常开发人员没有时间学习或使用其他图。类图也很好,因为它是自动更新的。只需反转一个程序包并添加注释,即可在代码后创建类图。它快速且始终准确,并且100%迭代。

请不要在模型驱动的开发(该模型是生成模型的代码)与通常使用UML作为图形表示以及从代码更新的UML类图之间进行混淆。如果进行多次迭代,那么只有UML同步代码对我有实际价值。

抱歉,这么长,但是我认为如果仅将UML类图用作项目的图形视图,我们应该给它第二次机会。这意味着UML涵盖了整个项目,并具有由代表整个项目的大型类图组成的单个模型。在一个拥有数百个视图的项目中拥有数百个小视图和每个视图的模型将是荒谬的:-)


1
+1显示邮政编码UML的想法!有趣的是,代码之后我们再也不会回到图表文件了!
Dipan Mehta

是的,这正是与UML相关的模型驱动开发的问题。您生成文档,然后对项目进行任何修改都不要使用它。通过模型和代码合并,我们可以使用UML并根据需要对其进行多次更改。
UML_GURU

3

由于设计不良,方向改变等原因,我的代码和其他代码陷入僵局。我还看到许多其他代码遇到此问题。最大的错误(至少对我来说似乎是一个错误)是立即放弃工作代码并重新实现所有功能的迫切愿望。

我以似乎运作良好的相同方式处理了每种情况:

  • 确定当前设计为何不起作用
  • 提出新的设计过渡计划
  • 标记将不再使用的代码
  • 仅实现我对新设计的需求,以便满足当前的需求
  • 删除新代码使过时的代码

费用:

  • 由于同时在代码库中进行了2种实现,因此更加复杂
  • 每个功能/错误修复的总成本比假设良好的用例和测试进行完整的重新设计/重新实现要多

好处:

  • 风险至少降低一个数量级,因为您仍然拥有旧的有效设计/代码
  • 不需要完全重新设计的任何1到n-1功能,可以更快地推向市场
  • 如果产品/代码在完成完整的重新设计之前就已消失,那么您将节省开发时间差
  • 迭代方法及其中的所有好处

2

大约一两个月前,我们的当前项目由于采用SCRUM开发风格的一些糟糕的设计决策(并且在一处缺乏太多设计)而陷入了困境。

我们的解决方案(我认为是SCRUM的标准解决方案)是将整个sprint(约2周)专门用于重构。在这段时间内没有添加任何新功能,但是我们能够考虑当前的代码库,并为我们的工作设计一个更好的系统。

我们现在已经越过了这个障碍,并且再次增加了新功能。


这是另一个巨大的摩擦。在交付第一个版本之后,必须与客户说-我们现在正在构建相同的功能-并不是什么新功能!您可以多久和一次(如果有的话)告诉客户?甚至你怎么解释?
Dipan Mehta

您有两个基本选择,要么首先您简单地说出一个简单的事实-尽管您所拥有的东西一团糟,并且需要进行整理才能继续前进;其次您表示正在建立基础架构以支持正在进行的开发(的确如此,但为了更好一点,它被旋转了。您可以通过说这两种方式来总结这两个问题,为了交付功能,我们招致了技术债务,现在需要偿还。
Murph

@Dipan Mehta:好吧,假设一位顾客想要一栋两层楼的房子。您设计并交付它。然后,他们希望再增加四层。您说,很好,我必须花时间来使当前建筑物更坚固,以便容纳另外四层。因此,如果原始计划仅包括两层,对于客户而言,我认为这不应该是问题。如果从一开始就计划建造六层楼,是的,告诉客户可能是个问题。
乔治

@DipanMehta我们也很幸运,因为客户不一定了解这个项目。这是他们目前使用的产品的升级版,预计到今年年底才能完成。因此,他们甚至都不需要知道重构的延迟;)(负责大多数设计决策的经理在内部)
Izkata

2

限制设计更改成本的关键是使代码尽可能保持DRY。这会将大多数应用程序代码推向一个非常高的层次,其中大多数代码直接表达了意图,而相对较少的指定机制。如果这样做,那么设计决策将在代码中使用最小的表达式,并且设计更改将具有最小的成本。


2

避免设计死胡同的关键是尽早识别需要更改的设计,然后进行更改。最大的问题不是通过不断发展设计,而是拒绝发展设计直到它成为一个大问题。

例如,Netflix具有配置文件功能,其中不同的家庭成员可以向同一计划计费,但有单独的队列。几年前,他们宣布必须取消该功能,因为只有大约10%的用户使用了该功能,但是由于实施上的黑手,它正在消耗大量的维护工作。一阵骚动之后,他们忍住了子弹,并进行了昂贵的重新设计以保留这些客户。

我敢肯定有些工程师在首次添加该功能时就认识到了次优的设计。如果他们那时改变了它,那将不会有什么大不了的。


1

是不是弗雷德·布鲁克斯(Fred Brooks)说了“计划丢掉第一个”的话?不要为此感到沮丧,在尝试尽早进行所有设计的项目中也会出现死胡同的设计。重新设计在所有类型的开发中都会发生,无论是因为它从一开始就是不可行的设计(最后20%的设计被掩盖了“细节中的魔鬼”),或者是因为客户改变了他们的关注重点。不需要真正的警钟,不要太担心。

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.