关于体系结构:如何在仍然忠于敏捷的同时避免技术债务,即:避免违反YAGNI和避免BDUF?

关于体系结构:如何在仍然忠于敏捷的同时避免技术债务,即:避免违反YAGNI和避免BDUF?

How do you avoid Technical Debt while still keep true to Agile, i.e.: avoiding violation of YAGNI and avoiding BDUF?

通过马丁·福勒,通过史蒂夫·麦康奈尔获得技术债务

通过维基百科的YAGNI(您将不需要它)

BDUF(前期大设计),通过维基百科

更新:为澄清这个问题,我想我也可以这样陈述并保持我的意思:

"作为敏捷实践者,您如何在每次迭代中的"快速和肮脏"(试图遵守YAGNI时无意冒技术债务风险)和过度设计(BDUF)之间找到正确的平衡?"


看来,如果您坚持"计划,做,适应;计划,做,适应"敏捷思想(迭代,迭代评论),则默认情况下会避免这些事情。 BDUF与敏捷估算和计划的想法恰恰相反,如果您真的很敏捷,就不会自动成为BDUF。

发布和迭代计划会议的目的是确保您为该迭代将最有价值的功能添加到项目中。如果您牢记这一点,则可以免费避免使用YAGNI。

我强烈建议Mike Cohn撰写有关敏捷规划的书:

  • 用户故事已应用
  • 敏捷评估与规划
  • 更新:在您澄清了在一次迭代中避免使用YAGNI和BDUF之后...

    BDUF ...如果在开始进行这项工作之前,我觉得没有明确定义某个功能,那么我将创建一个小的"功能"或故事来说明所需工作的设计类型部分。这样一来,较小的故事可能会有一个故事点估计值,而不是真实特征的估计值是5。这样一来,设计便随时间进入了较小的故事中,您将被迫着手进入该要素本身。

    为了避免违反YAGNI,我将努力弄清楚客户对迭代中某个功能的期望。只做与客户期望相对应的工作。如果您认为应该添加一些额外的功能,请为其创建一个新功能,然后将其添加到待完成的工作中。然后,您会说服客户看到它的好处;就像客户会要求在某个特定时间点完成某项功能一样。


    您似乎在说" YAGNI"意味着"快速而肮脏"。我没有看到。

    作为敏捷程序员,我练习测试驱动的开发,代码审查和持续集成。

    • 作为一个过程,测试驱动开发(TDD)是避免YAGNI的好方法。只是"可能有用"的代码往往未经测试且很难测试。
    • TDD在很大程度上也消除了对BDUF的强迫:当您的过程是从坐下来开始做一些真正能带来价值的事情时,您就不能沉迷于BDUF。
    • TDD,作为一种设计实践,意味着大型设计将随着您对问题的经验积累而出现,并重构实际代码。
    • 持续集成意味着您可以设计过程,以便可以随时发布产品。这意味着您有一个集成的质量流程,该流程试图防止主线质量下降。

    以我的经验,技术债务的主要形式是:

    • 自动化测试套件未涵盖的代码。除了非常难以测试的非常本地化的组件外,不要允许这种情况发生。未经测试的代码是损坏的代码。
    • 违反编码标准的丑陋代码。不允许这种情况发生。这就是为什么需要在持续集成过程中进行代码审查的原因之一。
    • 气味和需要重构的代码和测试可以更容易地修改或理解。这是技术债务的良性形式。利用您的经验来知道何时积累和何时还款。

    不知道这是否回答了您的问题,但是我很乐于编写。

    Troy DeMonbreun commented:

    No, that wasn't my point..."quick and dirty" = (unintentionally risking Technical Debt while attempting to adhere to YAGNI"). That does not mean YAGNI is only quick and dirty. The phrase"quick and dirty" is what I used to quote Martin Fowler in his description of Technical Debt

    避免使用YAGNI是说吻的另一种方式。 YAGNI增加了技术债务。在避免使用YAGNI和保持较低的技术债务之间没有张力。

    我想我可能仍会遗漏您的问题。


    几周前,根据您在HanselMinutes上完成的定义,对技术债务进行了有趣的讨论。该节目的基本原理是,如果您重新定义"完成"以提高感知的速度,那么您将积累技术债务。必然的结果是,如果您对"完成"的定义不正确,那么很可能会获得一份清单清单,无论设计方法如何,都需要在发行前完成。


    在我工作的地方,我相信我们避免债务的方法是快速循环整个周期,即向最终用户展示功能并获得表明应该推动测试的信号,或者拒绝说出问题所在给出更新的要求。通过在迭代中重复执行此操作,可以通过尝试这种方式找到有关用户所需内容的许多更改。

    关键点是尝试做用户想要做的事情,因为做更多的事情违反了YAGNI并引入了BDUF,而一遍又一遍地完善需求的想法是敏捷的核心。


    只需执行最简单的方法即可。我同意Ayende所说的敏捷性的关键是"经常运输"。像这样的定期发布周期将意味着BDUF没有时间,并且还将阻止开发人员违反YAGNI。


    XP的"传统"答案是重构与自动化单元测试相结合。

    但这从哲学上来说是一个非常有趣的问题。我认为您无需避免技术债务,只需将其保持在可管理的水平即可。史蒂夫·麦康奈尔(Steve McConnell)的文章在此方面取得了不错的成绩-类比起作用的原因是,只要您接受成本和风险,在公司中积累财务债务是正常且可以接受的-技术债务也可以。

    也许答案本身也在于YAGNI的原理。您将不需要还清技术债务,直到您这样做为止,那时您就是在进行重构。当您在带有技术债务的系统区域中进行大量工作时,请看一下重新设计对短期差异有多大影响。如果足够值得,那就还清。麦康奈尔提出的维持债务清单的建议将帮助您知道何时进行此考虑。

    我不认为这有绝对的答案-像许多事情一样,这是根据您在每种特定情况下的经验,直觉和分析所做出的判断。


    我发现罗伯特·马丁(Robert Martin)的测试驱动开发
    (TDD)方法有助于解决这些问题。

    为什么?

    • 您只需要编写足够的代码即可通过下一个测试。
    • 我认为可测试的代码更干净。
    • 设计必须纳入测试中,以帮助保持设计重点。
    • 当您必须进行更改(重构)时,您就有可以依靠的测试

    无论何时编写测试(之前或之后),我都会写作
    该测试可以帮助您做出实际的决定。例如,我们选择设计A或B是因为
    A更具可测试性。


    问题实际上可能是更高层次的:管理层和产品所有者关注的是截止日期,而不是开发人员自己。

    在我的最后一个工作岗位上,我从事旧代码的工作,但与使用(据说)敏捷和TDD开发全新代码的人们进行了联系。

    现在,TDD应该是红色-绿色-重构:编写失败的测试,进行最少的测试以通过测试,然后重新编写代码以使其更具可维护性,同时确保测试仍然通过测试。

    但是…进展是通过实施用户故事的速度(即添加新功能的速度)来衡量的。重构的原因是它没有添加任何新功能。是的,这非常重要,但是并不会立即向产品所有者显示新功能或与之相关的测试代码行。

    随着最后期限的临近,加班已成为标准,因此有动机在重构部分跳过。执行此操作的次数越多,获得用户故事的速度就越快,这似乎是管理层关心的问题。

    现在,这确实导致了技术上的负担,因为在很多情况下,要完成下一个用户故事,事实证明有必要返回并重构(实际上是重写)前一组用户故事的代码。管理层对此非常恼火,因为从他们的角度看,所讨论的用户故事与以前的故事似乎并没有什么不同,那么为什么对此的估计要长10倍呢?

    (同样,游戏理论方面也存在一个丑陋的方面。如果您或您的团队认真地进行重构,但这并不能阻止您被另一组没有的团队清理干净。当然,那支其他团队看起来更好,因为他们在相同的时间内完成了更多的用户案例。)

    我的意思是,如果做得好,TDD不会导致技术债务。但是要正确完成,必须有更高层次的真正支持。


    当然,对于任何给定的项目,敏捷都会使您的TD降低吗?

    您正在实施客户想要的内容(即得到他们的反馈),这使TD降至最低,


    这就是为什么编写轻松的"学术论文"谈论敏捷开发如何好,什么是"最佳实践"等等总是容易的。

    这就是为什么您会发现许多组成新软件工程技术的"合适的工程师"的原因。

    流程很重要,保持最佳实践很酷,但比起其他任何事情,常识都可以推动设计流程。软件是人们开发的,因此YAGNI实际上应该是:

    我可能不需要,但也许会,因为在我的具体业务/公司/部门中确实发生了此事,或者我将需要它,但我只是没有时间,没有那么快又肮脏的黑客来赚钱并保持工作,否则我可能会需要它,而稍后进行重构将是麻烦的,这比现在从头开始花费十倍的钱多了,我现在有时间。

    因此,请使用您的常识,信任它或信任为您工作的人们的常识。不要将所有学术论文都当作事实来证明,经验是最好的老师,并且您的公司应该根据自己的经验和时间来改进自己的方式或做事。

    编辑:顺便说一句,TDD与您正在构建测试的YAGNI相反,甚至不知道您是否需要它们。认真地,不要听学者的话!!没有神奇的方式来生产软件。


    推荐阅读