想象一下,您 90% 的工作只是在一个非常庞大、非常损坏的网站上对问题进行分类。想象一下,这个网站是用你所见过的最紧密耦合、最不内聚的 PHP 代码编写的,这种代码类型会将原始开发人员添加到你的“一见钟情”列表中。想象一下,这个 Web 应用程序由 4 个非常不同的部分(1 个商业部分、2 个“重新利用”和 1 个定制部分)和一大堆虚拟胶带和垫片组成。想象一下,它包含一种编程实践,其中网站的主要组件实际上依赖于无法正常工作的东西,而修复这些损坏的东西通常会破坏其他东西。想象一下,您从太多糟糕的经历中了解到,更改网站中看似无害的部分,例如将“名称”字段拆分为两个单独的“第一”和“最后”字段,会使网站瘫痪并需要数小时回滚、合并和补丁。想象一下,多年来一直恳求客户放弃代码并重新开始,但却遇到了企业级的绝望和绞尽脑汁。然后想象一下获得 ASAP/EMERGENCY 票来实现在任何其他网站上需要 4 小时的新功能,但您对这个网站了解得更好,所以您报价 40 小时,然后按此收费并收取 80 小时的费用,但这没关系,因为客户习惯了他们的网站。
以下是您还应该想象的其他一些事情:
想象一下,是否值得尝试达到中等水平的测试覆盖率?或者你是否应该,在这个想象的场景中,继续尽你所能用你得到的东西,希望,祈祷,甚至牺牲,客户会同意重写这些日子,然后你就可以开始写作了测试?
附录
自从你们中的许多人提出以来:我已经接近了在我必须约会的每一次机会中重写的可能性。与我一起工作的营销人员知道他们的代码是垃圾,他们知道这是他们最初选择的“最低出价”公司的错。我可能已经超越了我作为承包商的界限,指出他们花了一大笔钱在我身上为这个网站提供临终关怀,而且通过从头开始重新开发,他们会很快看到投资返回率。我也说过我拒绝按原样重写网站,因为它并没有真正做到他们想要它做的事情。计划是重写 BDD 风格,但将所有关键玩家集中在一个地方很难,我仍然不确定他们是否知道自己需要什么。无论如何,我完全希望这是一个非常大的项目。
感谢到目前为止的所有反馈!
最佳答案
一段时间内您可能无法获得全面报道。但是您可以为您实现的新代码/功能编写测试。从小做起。不要试图一次完成所有事情。
也许“Working effectively with Legacy Code”这本书值得一读?
我也建议观看 this presentation from Uncle Bob其中涉及这种情况以及如何使用“渐进式扩展”将糟糕的代码库转换为良好的代码库
首先找到任何自包含函数。除了传入的参数之外不引用任何内容的函数。将它们移动并组织到辅助类中。这可能只是暂时的,因为许多人以后会在不同的类(class)结束,但这将有助于识别一些重复的代码,并开始组织起来。然后,看看这些是如何使用的,根据这些使用编写测试。拍拍自己的背。您现在已经开始使您的代码可维护。
InfoQ 刚刚发布了另一篇文章 How To Do Large Scale Refactoring这就是这类事情,还有另一篇名为 Refactor or Rewrite? 的旧文章并且有像 Mikado Method 这样的技术你必须意识到你不能总是一步一步地做出你想要的 Action ,你必须做出其他 Action 来设置和实现你的目标。
关于php - 是否值得尝试为世界上最紧密耦合的站点编写测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3549243/
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
我正在用Ruby编写一个简单的程序来检查域列表是否被占用。基本上它循环遍历列表,并使用以下函数进行检查。require'rubygems'require'whois'defcheck_domain(domain)c=Whois::Client.newc.query("google.com").available?end程序不断出错(即使我在google.com中进行硬编码),并打印以下消息。鉴于该程序非常简单,我已经没有什么想法了-有什么建议吗?/Library/Ruby/Gems/1.8/gems/whois-2.0.2/lib/whois/server/adapters/base.
我想用ruby编写一个小的命令行实用程序并将其作为gem分发。我知道安装后,Guard、Sass和Thor等某些gem可以从命令行自行运行。为了让gem像二进制文件一样可用,我需要在我的gemspec中指定什么。 最佳答案 Gem::Specification.newdo|s|...s.executable='name_of_executable'...endhttp://docs.rubygems.org/read/chapter/20 关于ruby-在Ruby中编写命令行实用程序
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。
我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere
这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife
Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/
我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test