是否值得尝试为世界上最紧密耦合的网站编写测试?

Chr*_*oom 30 php testing cohesion tightly-coupled-code

想象一下,90%的工作仅仅是为了在一个非常庞大,非常破碎的网站上分类问题.想象一下,这个网站是用你所见过的最紧密耦合,最不具有凝聚力的PHP代码编写的,这种代码类型可以将原始开发人员添加到你的"一瞥"栏目中.想象一下,这个Web应用程序由4个非常不同的部分组成(1个商业,2个"重新定位",1个自定义)和一堆垃圾虚拟胶带和垫片.想象一下,它包含了一种编程实践,其中网站的主要组件实际上依赖于不正常工作的东西,修复这些破碎的东西通常会破坏其他东西.想象一下,你从太多糟糕的经历中知道改变一个看似无害的网站部分,比如拆分"名字" 字段分为两个单独的"第一"和"最后"字段,将使网站瘫痪,需要数小时的回滚,合并和补丁.想象一下,多年来恳求客户抛弃代码并重新开始,但遭遇企业级绝望和手工绞尽脑汁.然后想象获得ASAP/EMERGENCY门票以实现新功能,在任何其他网站上需要4个小时,但你对这个网站有更好的了解,所以你引用了40个小时,然后直接吹了80个小时,但它没关系,因为客户端用于他们的网站.想象一下,多年来恳求客户抛弃代码并重新开始,但遭遇企业级绝望和手工绞尽脑汁.然后想象获得ASAP/EMERGENCY门票以实现新功能,在任何其他网站上需要4个小时,但你对这个网站有更好的了解,所以你引用了40个小时,然后直接吹了80个小时,但它没关系,因为客户端用于他们的网站.想象一下,多年来恳求客户抛弃代码并重新开始,但遭遇企业级绝望和手工绞尽脑汁.然后想象获得ASAP/EMERGENCY门票以实现新功能,在任何其他网站上需要4个小时,但你对这个网站有更好的了解,所以你引用了40个小时,然后直接吹了80个小时,但它没关系,因为客户端用于他们的网站.

以下是您还应该想象的其他一些事情:

  • 现在没有任何测试
  • googleteen有不同的登录层.有些客户实际上有3个不同的帐户用于网站的不同部分
  • 当我说"紧耦合"时,我的意思是include/require语句的循环可能会像凯尔特结一样映射出来
  • 当我说"最不具凝聚力"时,我的意思是某些东西有点像MVC,但它不是真正的MVC.在某些情况下,您可能需要几个小时才能找到URI A如何映射到文件B.
  • 用户界面写得像"突兀","无法访问"是当时的流行语

想象一下,甚至值得尝试达到中等水平的测试覆盖率?或者,在这个想象的情景中,你应该继续尽你最大的努力,你已经给予了什么,并希望,祈祷,甚至牺牲,客户将同意重写其中一天,然后你就可以开始写作了测试?

附录

因为你们中的许多人提出了这个问题:我已经接触过每次机会重新写作的可能性.与我合作的营销人员知道他们的代码是垃圾,他们知道这是他们最初使用的"最低出价"公司的错.作为承包商,我可能已经超越了我的界限,指出他们花了我一大笔钱给我这个网站提供临终关怀服务,而且从头开始重新开发他们会很快看到投资回报率.我还说我拒绝按原样重写网站,因为它实际上并没有按照他们的意愿去做.计划是重写它的BDD风格,但让所有关键球员都在一个地方很难,我仍然不确定他们知道他们需要什么.无论如何,我完全希望这是一个非常大的项目.

感谢到目前为止的所有反馈!

Caf*_*eek 12

一段时间后,您可能无法完全覆盖.但是您可以为您实现的新代码/功能编写测试.从小处开始.不要试图一次完成所有事情.

或许" 有效地使用遗留代码 " 这本书值得一读?

编辑

我还建议观看Bob叔叔的演讲,该演讲涉及这个场景,以及如何使用"Progressive Widening"将糟糕的代码库转换为好的代码库.

编辑2

首先找到任何自包含的函数.除了传入的参数之外不引用任何内容的函数.将它们移动并组织成辅助类.这可能只是暂时的,因为许多人最终会在不同的类中结束,但这将有助于识别一些重复的代码,并开始组织事情.然后,看看如何使用它们,根据这些用途编写测试.并拍拍自己的背部.您现在已经开始使代码可维护.

编辑3

有了很好的时机,InfoQ刚发布了另一篇文章" 如何进行大规模重构",这是另类,另一篇较旧的文章称为Refactor或Rewrite?还有像Mikado方法这样的技术,你必须意识到你不能总是在一步中完成你想要的移动,你必须做出其他动作来设置并实现你的目标.

  • +1,这是一本处理这种情况的好书.对于这种特殊情况,我建议编写特征测试,编写一个失败的测试用例,观察系统当前的行为方式,并改变测试以传递行为.您没有测试系统是否正常运行,但至少您正在测试修改某些内容时系统的行为是否会发生变化. (6认同)
  • @ Chrisbloom7,我绝对建议您查看旧版代码书.它概述了一些相对低风险的技术,可用于破坏依赖关系并获取测试代码.这需要一种非常务实的方法,并且自由地承认一些重构非常难看.目标是让事情得到测试,以便在您改进代码以实现新功能时安全可靠地进行更重要的重构.你必须要爱上一本名为"我的应用程序没有结构"的章节. (2认同)

Jos*_*h K 11

绝对不.

如果你说多件事依赖其他特别不起作用的东西那你怎么能开始测试呢?

我个人会说废弃它并重新开始.四小时功能需要80?我希望这是夸大其词.你必须要头痛.

我会从一个非常坚定的建议开始重新编写代码库.有时候必须把令人烦恼的客户告诉他们.有多少其他开发人员将使用破碎的基础?制作一些漂亮的成本/效益图表.

通过各种方式为编写的代码编写测试.不要忽视这一点.我说我不会尝试在现有代码库上编写测试.

  • 我稍微不同意......对于一个简单的应用程序,确定它更便宜,从而开始重新开始.但在现实世界中,经济和人员压力可能会阻止干净的重写(因为他们仍然必须保持当前的应用程序,直到它准备好).我同意最好重新开始,但实际上并非在所有情况下都是如此(因此,为什么重构可能是一个明智的选择,特别是如果应用程序很大的话)... (3认同)
  • @Josh K,*"但我不会尝试为现有代码编写测试."*,为什么不呢?有什么更好的方法来记录行为,并使其可测试,可维护,代码?我现在正在中型系统上做这件事,这是一个完全彻底的混乱.重复的代码,1000行和1000行死代码,以及大量不良代码实践,使其成为维护和非常错误的噩梦.当我完成后,它最终几乎是重写.但这个过程不是从头开始的.这是一系列测试,重构,测试,重构...直到应用程序正常运行,并且可维护......通过测试! (2认同)

Ski*_*ick 7

搏一搏

编写测试可以让你重构.如果你在足够高的水平上编写测试,你可能会设法做到这一点,这样你就可以重构,而不必每次都重新编写测试.

在网站的一小部分(我知道你不能完全隔离任何部分,但你仍然可以锁定部分)是最不值得的.

也许为自己设定一个时间预算(由你来决定什么是实惠的/值得的),然后进行一些测试和一些重构.如果不能解决问题,请回滚.如果是,继续.

祝好运!


Dav*_*ulp 6

首先,如果您的客户使用的估算值是实际需要的一半,请修正您的估算值!很高兴客户对"估计已关闭"感到满意 - 但重要的是让您的估算更符合实际需要的工作量.没有它,客户会同意进行重大重构 - 更不用说重写了.因此,通过估算得到一些正确的历史,然后转向重新设计项目.

至于写测试.对于您所描述的内容而言,这比绿地项目更为重要.在每一段代码中,您都会问自己是否可以将应该存在的行为与那里的行为分开.以应有的方式编写代码(使用测试),然后添加一个抽象层,使其成为当前的样式(并进行测试!).你会觉得你加入了这个烂摊子,你会 - 但慢慢地,随着时间的推移,测试会让你对这些方面充满信心.

如果它就像我一直在处理的那样,那就是将一个方法拉到一个帮助类中并将其修补回现有代码的顺序,几乎不值得 - 但它确实每次都能得到回报你必须再次触摸系统的那一部分.就像他们说的那样 - "让它比你发现它更好",每次你回到它时你都会开始找到更好的形状.测试是让它比你发现它更好的最佳方法.

但严重的是,要让客户对您的估算准确性充满信心,他们才能对您处理返工的能力充满信心.


irc*_*ell 5

绝对写测试.特别是在紧耦合环境中,测试将变得更加重要(因为由于紧耦合,一个区域中的错误修复会严重影响其他区域).

现在,意识到这可能不是一项微不足道的任务.为了编写测试,您需要修改代码以使其可测试.要修改代码,您需要进行测试.所以你陷入了依赖循环......

但是,看看潜在的好处.这应该告诉你它是否真的值得.

如果你真的开始,那就从小做起.挑选一块看起来松散耦合的小块,并测试一下.然后找一些不那么纠结的东西.首先测试所有最松散的碎片(低垂的果实).然后,一旦你到达非常紧凑的部分,你会感觉更舒服,并且(希望)对你真正需要做的事情有更多的了解.

请记住,您不需要100%的覆盖率来获得收益.每个测试都增加意义......