Imagine that 90% of your job is merely to triage issues on a very massive, very broken website. Imagine that this website is written in the most tightly coupled, least cohesive PHP code you've ever seen, the type of code that would add the original developers to your "slap on sight" list. Imagine that this web application is made up of 4 very disparate parts (1 commercial, 2 "repurposed", and 1 custom) and a crap-ton of virtual duct tape and shims. Imagine that it contains the type of programming practices in which major components of the website actually rely on things NOT working properly, and fixing these broken things usually breaks other things. Imagine that you know from too many bad experiences that changing one seemingly innocuous part of the website, such as splitting a "name" field into two separate "first" and "last" fields, will bring the site to its knees and require hours of rollbacks, merges and patches. Imagine pleading with the customer for years to just ditch the code and start all over but being met with Enterprise-Grade despair and hand wringing. Then imagine getting ASAP/EMERGENCY tickets to implement new features that in any other web site would take 4 hours but you know better with this site so you quote 40 hours, then blow right by that and bill 80 hours, but it's OK because the client is used to that with their website.
想象一下,90%的工作仅仅是为了在一个非常庞大,非常破碎的网站上分类问题。想象一下,这个网站是用你所见过的最紧密耦合,最不具有凝聚力的PHP代码编写的,这种代码类型可以将原始开发人员添加到你的“slap on sight”列表中。想象一下,这个Web应用程序由4个非常不同的部分组成(1个商业,2个“重新定位”,1个自定义)和一堆垃圾虚拟胶带和垫片。想象一下,它包含了一种编程实践,其中网站的主要组件实际上依赖于不正常工作的东西,修复这些破碎的东西通常会破坏其他东西。想象一下,你从太多糟糕的经历中知道,改变一个看似无害的网站部分,比如将“名称”字段分成两个独立的“第一”和“最后”字段,将使网站瘫痪,需要数小时回滚,合并和补丁。想象一下,多年来恳求客户抛弃代码并重新开始,但遭遇企业级绝望和手工绞尽脑汁。然后想象获得ASAP / EMERGENCY门票来实现新功能,在任何其他网站上需要4个小时,但你对这个网站有更好的了解,所以你引用了40个小时,然后直接吹了80个小时,但它没关系,因为客户端习惯用他们的网站。
Here are some other things that you should also imagine:
以下是您还应该想象的其他一些事情:
- there are no tests at all right now
- 现在没有任何测试
- there are googleteen different layers of logins. Some customers actually have 3 different accounts for different sections of the website
- googleteen有不同的登录层。有些客户实际上有3个不同的帐户用于网站的不同部分
- when I say "tightly coupled", I mean the loops of include/require statements would probably map out like a celtic knot
- 当我说“紧耦合”时,我的意思是include / require语句的循环可能会像凯尔特结一样映射出来
- when I say "least cohesive" I mean some stuff is organized sort of like MVC, but it's not really MVC. In some cases it may take you several hours just to find out how URI A is mapped to file B
- 当我说“最不具凝聚力”时,我的意思是某些东西有点像MVC,但它并不是真正的MVC。在某些情况下,可能需要几个小时才能找出URI A如何映射到文件B.
- the UI was written like "obtrusive" and "inaccessible" were the buzzwords of the day
- 用户界面写得像“突兀”,“不可访问”是当时的流行语
Imagining all that, is it even worth trying to achieve even a moderate level of test coverage? Or should you, in this imaginary scenario, just keep doing the best you can with what you've been given and hoping, praying, maybe even sacrificing, that the client will agree to a rewrite one of these days and THEN you can start writing tests?
想象一下,甚至值得尝试达到中等水平的测试覆盖率?或者,在这个想象的情景中,你应该继续尽你最大的努力,你已经给予了什么,并希望,祈祷,甚至牺牲,客户将同意重写其中一天,然后你就可以开始写作了测试?
ADDENDUM
附录
Since many of you brought it up: I have approached the possibility of a re-write at every chance I've had to date. The marketing people I work with know that their code is crap, and they know it's the fault of the "lowest bid" firm they went with originally. I've probably overstepped my bounds as a contractor by pointing out that they spend a crap ton of money on me to provide hospice care for this site, and that by redeveloping it from scratch they would see an ROI very quickly. I've also said that I refuse to rewrite the site as-is, because it doesn't really do what they want it to do anyway. The plan is to rewrite it BDD style, but getting all the key players in one place is tough, and I'm still not sure they know what they need. In any case, I fully expect that to be A Very Big Project.
因为你们中的很多人提出了这个问题:我已经接触过每次机会重新写作的可能性。与我合作的营销人员知道他们的代码是废话,他们知道这是他们最初使用的“最低出价”公司的错。作为承包商,我可能已经超越了我的界限,指出他们花了一大笔钱给我这个网站提供临终关怀服务,而且从头开始重新开发他们会很快看到投资回报率。我还说我拒绝按原样重写网站,因为它实际上并没有真正按照他们的意愿去做。计划是重写BDD风格,但让所有关键人物都在一个地方很难,我仍然不确定他们知道他们需要什么。无论如何,我完全希望这是一个非常大的项目。
Thanks for all the feedback so far!
感谢到目前为止的所有反馈!
13 个解决方案
#1
12
You'll likely not get full coverage for some time. But you can write tests for new code/features you implement. Start small. Don't try to do everything all at once.
一段时间后,你可能无法完全覆盖。但是您可以为您实现的新代码/功能编写测试。从小处开始。不要试图一次完成所有事情。
And perhaps the book "Working effectively with Legacy Code" is worth a read?
或许“有效地使用遗留代码”一书值得一读?
Edit
I also would recommend watching this presentation from Uncle Bob which touches on this scenario and how to transform a bad code base, into a good one using "Progressive Widening"
我还建议观看Bob叔叔的演示文稿,该演示文稿涉及这个场景,以及如何使用“Progressive Widening”将糟糕的代码库转换为好的代码库。
Edit 2
Start by finding any self contained functions. Functions that don't reference anything but the arguments passed in. Move and organize them into helper classes. This is likely just temporary, as many will end up in different classes later, but this will help identify some duplicated code, and start getting things organized. Then, look at how these are used, write tests based on these uses. And pat yourself on the back. You've now started making your code maintainable.
首先找到任何自包含的函数。除了传入的参数之外不引用任何内容的函数。将它们移动并组织成辅助类。这可能只是暂时的,因为许多人最终会在不同的课程中结束,但这将有助于识别一些重复的代码,并开始组织事情。然后,看看如何使用它们,根据这些用途编写测试。并拍拍自己的背部。您现在已经开始使代码可维护。
Edit 3
With great timing InfoQ just posted another article How To Do Large Scale Refactoring which is specifically this sort of thing, and another, older article called Refactor or Rewrite? and there are techniques like the Mikado Method where you have to realize you can't always make the move you want in one step, you have to make other moves to setup and realize your goal.
有了很好的时机,InfoQ刚刚发布了另一篇文章“如何进行大规模重构”,这是另类,还有另一篇名为Refactor或Rewrite的旧文章?还有像Mikado方法这样的技术,你必须意识到你不能总是在一步中完成你想要的移动,你必须做出其他动作来设置并实现你的目标。
#2
11
Absolutely not.
If you say that multiple things rely on other things specifically not working then how can you even begin to test it?
如果你说多件事依赖于其他特别不起作用的东西那么你怎么能开始测试呢?
Personally I would say scrap it and start over. Four hour features that take 80? I hope this is an exaggeration. The headaches you must have.
就个人而言,我会说废弃它并重新开始。四小时功能需要80?我希望这是夸大其词。你必须要头痛。
I would start with a very firm proposal to re-write the code base. Hand-wringing clients must be told the blunt truth some times. How many other developers will work with a broken base? Make some pretty cost / benefit charts.
我会从一个非常坚定的建议开始重新编写代码库。有时候,必须让烦恼的客户被告知这个直言不讳的事实。有多少其他开发人员将使用破损的基础?制作一些漂亮的成本/效益图表。
By all means write tests for code you write. Don't neglect that. I'm saying I wouldn't try to write tests on the existing code base.
通过各种方式为您编写的代码编写测试。不要忽视这一点。我说我不会尝试在现有代码库上编写测试。
#3
7
Give it a go
Writing tests enables you to refactor. If you write your tests at a high-enough level, you might manage to make it so you can refactor without having to re-write the tests every time.
编写测试可以让你重构。如果你在足够高的水平上编写测试,你可能会设法做到这一点,这样你就可以重构而不必每次都重新编写测试。
It's a least worth a go, on a small part of the site (I know you won't be able to fully isolate any part, but you can still target part).
在网站的一小部分(我知道你不能完全隔离任何部分,但你仍然可以锁定部分)是最不值得的。
Maybe set yourself a time budget (it's down to you to work out what's affordable/worth it), then have a go with some tests and some refactorings. If it doesn't work out, roll back. If it does, carry on.
也许为自己设定一个时间预算(由你来决定什么是实惠的/值得的),然后去做一些测试和一些重构。如果不能解决问题,请回滚。如果确实如此,请继续。
Good luck!
祝你好运!
#4
6
First, if your customer is use to your estimates being half what it actually takes, fix your estimates! It is nice the customer is 'OK' with the estimates being off -- but it is critical you get your estimates more in line with effort actually needed. Without that, what customer would ever consent to a major refactoring -- let alone a rewrite. So get some history of being right with estimates, then move to rework the project.
首先,如果您的客户使用的估算值是实际需要的一半,请修正您的估算值!很高兴客户对“估计已关闭”感到“满意” - 但重要的是让您的估算更符合实际需要的工作量。没有它,客户会同意进行重大重构 - 更不用说重写了。因此,通过估算得到一些正确的历史,然后转向重新设计项目。
As for writing tests. That is even more vital for what you describe than for a green-field project. In every piece of code you touch ask yourself if it is possible to decouple the behavior that should be there from the behavior that is there. Write the code the way it should be (with tests) and then add a layer of abstraction to make it the way it currently is (and test that too!). You will feel like your adding to the mess, and you will be -- but slowly, over time, the tests will give you confidence in these areas.
至于写测试。对于你描述的内容而言,这比绿地项目更为重要。在你接触的每一段代码中,你都会问自己是否有可能将应该存在的行为与那里的行为分开。以应有的方式编写代码(使用测试),然后添加一个抽象层,使其成为当前的样式(并测试它!)。你会觉得你加入了这个烂摊子,你会 - 但慢慢地,随着时间的推移,这些测试会让你对这些方面充满信心。
If it's anything like what I've been dealing with, it will be on the order of pulling a single method out into a helper class and patching it back into the existing code, hardly seems worth it -- but it does pay off every time you have to touch that part of the system again. Like they say -- "leave it better than you found it" and you'll start finding it in better shape each time you come back to it. Tests are the best way to leave it better than you found it.
如果它就像我一直在处理的那样,那就是将一个方法拉到一个帮助类并将其修补回现有代码的顺序,几乎不值得 - 但它确实每次都付出代价你必须再次触摸系统的那一部分。就像他们说的那样 - “让它比你发现它更好”,每当你回到它时你就会开始找到更好的形状。测试是让它比你发现它更好的最佳方法。
But seriously, getting the client confident in the accuracy of your estimates is required before they will be fully confident in your ability to handle a rework.
但是,在他们对您的返工能力充满信心之前,需要让客户对估算的准确性充满信心。
#5
5
Absolutely write tests. Especially in a tight-coupled environment the tests are going to be even more critical (since a bug fix in one area can drastically affect other areas due to the tight coupling).
绝对写测试。特别是在紧耦合环境中,测试将变得更加重要(因为由于紧耦合,一个区域中的错误修复会严重影响其他区域)。
Now, realize that this will likely not be a trivial task. In order to write tests, you'll need to modify the code to be testable. In order to modify the code, you need to have tests. So you're caught in a dependency cycle...
现在,意识到这可能不是一项微不足道的任务。为了编写测试,您需要修改代码以使其可测试。要修改代码,您需要进行测试。所以你陷入了依赖循环......
However, look at the potential benefits. That should tell you if it is really worth it or not.
但是,看看潜在的好处。这应该告诉你它是否真的值得。
If you do start out, start small. Pick one tiny piece that looks loosely-coupled, and test that. Then find something else that's not that tangled. Test all the loosest pieces first (the low hanging fruit). Then, once you get to the really tight parts, you'll both feel more comfortable and (hopefully) have more insight as to what you really need to do.
如果你开始做的话,从小做起。选择一块看起来松散耦合的小块,然后进行测试。然后找一些不那么纠结的东西。首先测试所有最松散的碎片(低垂的果实)。然后,一旦你到达非常紧凑的部分,你会感觉更舒服,并且(希望)对你真正需要做的事情有更多的了解。
Remember, you don't need 100% coverage to reap the benefits. Each test adds meaning...
请记住,您不需要100%的覆盖率来获得收益。每个测试都增加意义......
#6
3
You can't scrap it. The customer isn't going to let you, and it might not be the best path anyways.
你不能废弃它。客户不会让你,它可能不是最好的路径。
So instead of quoting 40 hours for a fix that should have taken minutes... quote 60. The customer seems A-OK with that. Use 40 to fix, and 20 to refactor... and write tests on what you refactor. If the 60 runs to 100, then spend 120; 80 to fix, and 40 to refactor/test.
因此,而不是引用40小时来进行应该花费几分钟的修复...引用60.客户似乎A-OK。使用40来修复,20来重构......并对你重构的内容进行测试。如果60跑到100,那么花120; 80修复,40重构/测试。
Build in time to improve the thing into your normal estimates, or find new work; the current situation, it sounds like, will drive you into hating our field.
及时建立以将事物改进到正常估计中,或找到新工作;听起来,现在的情况会让你讨厌我们的领域。
#7
2
This sounds like in order to make it testable at all, you'd have to rewrite parts of the system from scratch - unavoidably causing tons of bugs in the process.
这听起来是为了让它完全可测试,你必须从头开始重写系统的一部分 - 不可避免地在这个过程中造成大量的错误。
From what you describe, the old system is not worth putting that kind of effort into.
根据您的描述,旧系统不值得付出这样的努力。
I would under no circumstances try and introduce testing for this, but try to get permission to rewrite as soon as possible.
在任何情况下我都不会尝试为此进行测试,但尝试尽快获得重写权限。
If your client doesn't see the light, consider whether refactoring the project is worth giving some time of your own: Working with clean code is so much better for one's well-being...
如果您的客户没有看到亮点,请考虑重构项目是否值得给自己一些时间:使用干净的代码对于一个人的幸福来说更好......
#8
2
The most important thing (After buying Working efficiently with legacy code) is to start small. I work on several projects, each several thousand PHP lines long and often without a single function (and don't even think of objects) and whenever i have to change code i try to refactor the part into a function and write a test for it. This is combined with extensive manual testing of that part so i can be sure it works as before. When i have multiple functions for similar things i move them as static methods into a class and then, step by step, replace them with proper object-oriented code.
最重要的事情(购买后使用遗留代码高效工作)是从小做起。我在几个项目上工作,每个项目长达数千个,并且通常没有单个函数(甚至没有想到对象),每当我必须更改代码时,我会尝试将该部分重构为函数并为其编写测试。这与该部件的广泛手动测试相结合,因此我可以确定它像以前一样工作。当我有类似事物的多个函数时,我将它们作为静态方法移动到一个类中,然后,一步一步地用适当的面向对象的代码替换它们。
Every step from moving it into a function to changing it into a real class is surrounded by unit testing (not very good one as 90% of the code are SQL queries and it's nearly impossible to set up a reliable testing database, but i can still test the behaviour).
从将其转换为函数到将其更改为真实类的每一步都被单元测试所包围(不是非常好的,因为90%的代码是SQL查询,并且几乎不可能建立可靠的测试数据库,但我仍然可以测试行为)。
Since a lot of code repeats (i found a single SQL query repeated 13 times in a single file and many times more in the other 50 files of that project) i could change all other places, but i don't since those are neither tested nor can i be sure the surrounding code doesn't depend on that code in some wierd way (think global
). That code can be changed as soon as i have to touch that code anyways.
由于大量代码重复(我发现单个SQL查询在一个文件中重复13次,而在该项目的其他50个文件中重复多次)我可以更改所有其他地方,但我不会因为那些都没有经过测试我也无法确定周围的代码是否以某种奇怪的方式依赖于该代码(想想全局)。一旦我必须触摸该代码,就可以更改该代码。
It's a long and tedious work and every time i see the code i feel a step (or rather a leap) closer to mental breakdown, but the code quality will improve (slowly but mostly reliably).
这是一项漫长而乏味的工作,每当我看到代码时,我感觉更接近精神崩溃的一步(或者更确切地说是跳跃),但代码质量将会提高(缓慢但最可靠)。
Your situation seems to be quite similar, so maybe my ideas might help you with your code.
您的情况似乎非常相似,所以也许我的想法可能会帮助您使用代码。
In short
简而言之
Start small, change only what you work on and begin to write only limited unit tests and expand them the more you learn about the system.
从小处着手,只改变你工作的东西,开始只编写有限的单元测试,并在你学习系统的过程中扩展它们。
#9
1
Start by doing black box, functional testing, connected parts or bits and pieces here and there. This makes continued development and refactoring/rewriting much easier.
首先要做黑盒子,功能测试,连接部件或零碎件。这使得持续开发和重构/重写变得更加容易。
Been there, doing that.
在那里,做到这一点。
Took a while till we could start adding unit testing, but got there eventually.
花了一段时间,直到我们可以开始添加单元测试,但最终到达那里。
It's still far from bulletproof but all developers are much more confident to dare to change/fix things when you know that there is a test suite waiting to try to verify your code changes.
它仍然远非防弹,但当您知道有一个测试套件等待尝试验证您的代码更改时,所有开发人员都更有信心敢于更改/修复问题。
#10
1
From your scenario, you should have a long list of fragile areas of the code that tend to be affected by innocuous changes (or at least areas that absolutely must work). If you can wright tests against this list, you have a quick way to find out when a change you're implementing has broken something.
从您的场景中,您应该有一长串代码的脆弱区域,这些区域往往会受到无害的更改(或者至少必须工作的区域)的影响。如果你可以对这个列表进行测试,你可以快速找到你正在实施的更改何时破坏了某些内容。
#11
0
In theory, definitely. The more tightly coupled, bug ridden the maintenance process then the more important the tests. In practise, walk away and live another day!
理论上,绝对。绑定越紧密,错误就越多,维护过程就会越多,测试就越重要。在实践中,走开,再过一天!
#12
0
If things behave reliably, you can test them, right? Your system works the majority of the time, so you can test for those success conditions.
如果事情表现得可靠,你可以测试它们,对吧?您的系统大部分时间都在工作,因此您可以测试这些成功条件。
..innocuous part of the website, such as splitting a "name" field into two separate "first" and "last" fields, will bring the site to its knees and require hours of rollbacks
..网站的一部分,例如将“名称”字段拆分为两个单独的“第一”和“最后”字段,将使网站陷入困境并需要数小时的回滚
Splitting a field apart such as first and last name sounds like a potential massive thing - but sounds like you've learned your lesson. At least try to get some funding for a full size test system and put the procedures in place to make moving production data to it automatic, so you can fully test this thing.
拆分一个字段,如名字和姓氏听起来像一个潜在的巨大的东西 - 但听起来你已经吸取了教训。至少尝试为全尺寸测试系统获得一些资金并制定程序以自动生成生产数据,因此您可以对此进行全面测试。
Sounds pretty horrible though. Time to dust of the ole resume?
听起来很可怕。时间尘埃的简历?
#13
0
You might want to consider billing another 40 hours/iteration to create a nice BDD (domain) model of how the application works or better: should work. That creates a nice framework where you can document the needed features. When the model is complete enough, you can estimate how much time you'd need to convert it to a working application.
您可能需要考虑另外40小时/迭代计费,以创建应用程序如何工作或更好的良好BDD(域)模型:应该工作。这创建了一个很好的框架,您可以在其中记录所需的功能。当模型足够完整时,您可以估计将其转换为工作应用程序所需的时间。
#1
12
You'll likely not get full coverage for some time. But you can write tests for new code/features you implement. Start small. Don't try to do everything all at once.
一段时间后,你可能无法完全覆盖。但是您可以为您实现的新代码/功能编写测试。从小处开始。不要试图一次完成所有事情。
And perhaps the book "Working effectively with Legacy Code" is worth a read?
或许“有效地使用遗留代码”一书值得一读?
Edit
I also would recommend watching this presentation from Uncle Bob which touches on this scenario and how to transform a bad code base, into a good one using "Progressive Widening"
我还建议观看Bob叔叔的演示文稿,该演示文稿涉及这个场景,以及如何使用“Progressive Widening”将糟糕的代码库转换为好的代码库。
Edit 2
Start by finding any self contained functions. Functions that don't reference anything but the arguments passed in. Move and organize them into helper classes. This is likely just temporary, as many will end up in different classes later, but this will help identify some duplicated code, and start getting things organized. Then, look at how these are used, write tests based on these uses. And pat yourself on the back. You've now started making your code maintainable.
首先找到任何自包含的函数。除了传入的参数之外不引用任何内容的函数。将它们移动并组织成辅助类。这可能只是暂时的,因为许多人最终会在不同的课程中结束,但这将有助于识别一些重复的代码,并开始组织事情。然后,看看如何使用它们,根据这些用途编写测试。并拍拍自己的背部。您现在已经开始使代码可维护。
Edit 3
With great timing InfoQ just posted another article How To Do Large Scale Refactoring which is specifically this sort of thing, and another, older article called Refactor or Rewrite? and there are techniques like the Mikado Method where you have to realize you can't always make the move you want in one step, you have to make other moves to setup and realize your goal.
有了很好的时机,InfoQ刚刚发布了另一篇文章“如何进行大规模重构”,这是另类,还有另一篇名为Refactor或Rewrite的旧文章?还有像Mikado方法这样的技术,你必须意识到你不能总是在一步中完成你想要的移动,你必须做出其他动作来设置并实现你的目标。
#2
11
Absolutely not.
If you say that multiple things rely on other things specifically not working then how can you even begin to test it?
如果你说多件事依赖于其他特别不起作用的东西那么你怎么能开始测试呢?
Personally I would say scrap it and start over. Four hour features that take 80? I hope this is an exaggeration. The headaches you must have.
就个人而言,我会说废弃它并重新开始。四小时功能需要80?我希望这是夸大其词。你必须要头痛。
I would start with a very firm proposal to re-write the code base. Hand-wringing clients must be told the blunt truth some times. How many other developers will work with a broken base? Make some pretty cost / benefit charts.
我会从一个非常坚定的建议开始重新编写代码库。有时候,必须让烦恼的客户被告知这个直言不讳的事实。有多少其他开发人员将使用破损的基础?制作一些漂亮的成本/效益图表。
By all means write tests for code you write. Don't neglect that. I'm saying I wouldn't try to write tests on the existing code base.
通过各种方式为您编写的代码编写测试。不要忽视这一点。我说我不会尝试在现有代码库上编写测试。
#3
7
Give it a go
Writing tests enables you to refactor. If you write your tests at a high-enough level, you might manage to make it so you can refactor without having to re-write the tests every time.
编写测试可以让你重构。如果你在足够高的水平上编写测试,你可能会设法做到这一点,这样你就可以重构而不必每次都重新编写测试。
It's a least worth a go, on a small part of the site (I know you won't be able to fully isolate any part, but you can still target part).
在网站的一小部分(我知道你不能完全隔离任何部分,但你仍然可以锁定部分)是最不值得的。
Maybe set yourself a time budget (it's down to you to work out what's affordable/worth it), then have a go with some tests and some refactorings. If it doesn't work out, roll back. If it does, carry on.
也许为自己设定一个时间预算(由你来决定什么是实惠的/值得的),然后去做一些测试和一些重构。如果不能解决问题,请回滚。如果确实如此,请继续。
Good luck!
祝你好运!
#4
6
First, if your customer is use to your estimates being half what it actually takes, fix your estimates! It is nice the customer is 'OK' with the estimates being off -- but it is critical you get your estimates more in line with effort actually needed. Without that, what customer would ever consent to a major refactoring -- let alone a rewrite. So get some history of being right with estimates, then move to rework the project.
首先,如果您的客户使用的估算值是实际需要的一半,请修正您的估算值!很高兴客户对“估计已关闭”感到“满意” - 但重要的是让您的估算更符合实际需要的工作量。没有它,客户会同意进行重大重构 - 更不用说重写了。因此,通过估算得到一些正确的历史,然后转向重新设计项目。
As for writing tests. That is even more vital for what you describe than for a green-field project. In every piece of code you touch ask yourself if it is possible to decouple the behavior that should be there from the behavior that is there. Write the code the way it should be (with tests) and then add a layer of abstraction to make it the way it currently is (and test that too!). You will feel like your adding to the mess, and you will be -- but slowly, over time, the tests will give you confidence in these areas.
至于写测试。对于你描述的内容而言,这比绿地项目更为重要。在你接触的每一段代码中,你都会问自己是否有可能将应该存在的行为与那里的行为分开。以应有的方式编写代码(使用测试),然后添加一个抽象层,使其成为当前的样式(并测试它!)。你会觉得你加入了这个烂摊子,你会 - 但慢慢地,随着时间的推移,这些测试会让你对这些方面充满信心。
If it's anything like what I've been dealing with, it will be on the order of pulling a single method out into a helper class and patching it back into the existing code, hardly seems worth it -- but it does pay off every time you have to touch that part of the system again. Like they say -- "leave it better than you found it" and you'll start finding it in better shape each time you come back to it. Tests are the best way to leave it better than you found it.
如果它就像我一直在处理的那样,那就是将一个方法拉到一个帮助类并将其修补回现有代码的顺序,几乎不值得 - 但它确实每次都付出代价你必须再次触摸系统的那一部分。就像他们说的那样 - “让它比你发现它更好”,每当你回到它时你就会开始找到更好的形状。测试是让它比你发现它更好的最佳方法。
But seriously, getting the client confident in the accuracy of your estimates is required before they will be fully confident in your ability to handle a rework.
但是,在他们对您的返工能力充满信心之前,需要让客户对估算的准确性充满信心。
#5
5
Absolutely write tests. Especially in a tight-coupled environment the tests are going to be even more critical (since a bug fix in one area can drastically affect other areas due to the tight coupling).
绝对写测试。特别是在紧耦合环境中,测试将变得更加重要(因为由于紧耦合,一个区域中的错误修复会严重影响其他区域)。
Now, realize that this will likely not be a trivial task. In order to write tests, you'll need to modify the code to be testable. In order to modify the code, you need to have tests. So you're caught in a dependency cycle...
现在,意识到这可能不是一项微不足道的任务。为了编写测试,您需要修改代码以使其可测试。要修改代码,您需要进行测试。所以你陷入了依赖循环......
However, look at the potential benefits. That should tell you if it is really worth it or not.
但是,看看潜在的好处。这应该告诉你它是否真的值得。
If you do start out, start small. Pick one tiny piece that looks loosely-coupled, and test that. Then find something else that's not that tangled. Test all the loosest pieces first (the low hanging fruit). Then, once you get to the really tight parts, you'll both feel more comfortable and (hopefully) have more insight as to what you really need to do.
如果你开始做的话,从小做起。选择一块看起来松散耦合的小块,然后进行测试。然后找一些不那么纠结的东西。首先测试所有最松散的碎片(低垂的果实)。然后,一旦你到达非常紧凑的部分,你会感觉更舒服,并且(希望)对你真正需要做的事情有更多的了解。
Remember, you don't need 100% coverage to reap the benefits. Each test adds meaning...
请记住,您不需要100%的覆盖率来获得收益。每个测试都增加意义......
#6
3
You can't scrap it. The customer isn't going to let you, and it might not be the best path anyways.
你不能废弃它。客户不会让你,它可能不是最好的路径。
So instead of quoting 40 hours for a fix that should have taken minutes... quote 60. The customer seems A-OK with that. Use 40 to fix, and 20 to refactor... and write tests on what you refactor. If the 60 runs to 100, then spend 120; 80 to fix, and 40 to refactor/test.
因此,而不是引用40小时来进行应该花费几分钟的修复...引用60.客户似乎A-OK。使用40来修复,20来重构......并对你重构的内容进行测试。如果60跑到100,那么花120; 80修复,40重构/测试。
Build in time to improve the thing into your normal estimates, or find new work; the current situation, it sounds like, will drive you into hating our field.
及时建立以将事物改进到正常估计中,或找到新工作;听起来,现在的情况会让你讨厌我们的领域。
#7
2
This sounds like in order to make it testable at all, you'd have to rewrite parts of the system from scratch - unavoidably causing tons of bugs in the process.
这听起来是为了让它完全可测试,你必须从头开始重写系统的一部分 - 不可避免地在这个过程中造成大量的错误。
From what you describe, the old system is not worth putting that kind of effort into.
根据您的描述,旧系统不值得付出这样的努力。
I would under no circumstances try and introduce testing for this, but try to get permission to rewrite as soon as possible.
在任何情况下我都不会尝试为此进行测试,但尝试尽快获得重写权限。
If your client doesn't see the light, consider whether refactoring the project is worth giving some time of your own: Working with clean code is so much better for one's well-being...
如果您的客户没有看到亮点,请考虑重构项目是否值得给自己一些时间:使用干净的代码对于一个人的幸福来说更好......
#8
2
The most important thing (After buying Working efficiently with legacy code) is to start small. I work on several projects, each several thousand PHP lines long and often without a single function (and don't even think of objects) and whenever i have to change code i try to refactor the part into a function and write a test for it. This is combined with extensive manual testing of that part so i can be sure it works as before. When i have multiple functions for similar things i move them as static methods into a class and then, step by step, replace them with proper object-oriented code.
最重要的事情(购买后使用遗留代码高效工作)是从小做起。我在几个项目上工作,每个项目长达数千个,并且通常没有单个函数(甚至没有想到对象),每当我必须更改代码时,我会尝试将该部分重构为函数并为其编写测试。这与该部件的广泛手动测试相结合,因此我可以确定它像以前一样工作。当我有类似事物的多个函数时,我将它们作为静态方法移动到一个类中,然后,一步一步地用适当的面向对象的代码替换它们。
Every step from moving it into a function to changing it into a real class is surrounded by unit testing (not very good one as 90% of the code are SQL queries and it's nearly impossible to set up a reliable testing database, but i can still test the behaviour).
从将其转换为函数到将其更改为真实类的每一步都被单元测试所包围(不是非常好的,因为90%的代码是SQL查询,并且几乎不可能建立可靠的测试数据库,但我仍然可以测试行为)。
Since a lot of code repeats (i found a single SQL query repeated 13 times in a single file and many times more in the other 50 files of that project) i could change all other places, but i don't since those are neither tested nor can i be sure the surrounding code doesn't depend on that code in some wierd way (think global
). That code can be changed as soon as i have to touch that code anyways.
由于大量代码重复(我发现单个SQL查询在一个文件中重复13次,而在该项目的其他50个文件中重复多次)我可以更改所有其他地方,但我不会因为那些都没有经过测试我也无法确定周围的代码是否以某种奇怪的方式依赖于该代码(想想全局)。一旦我必须触摸该代码,就可以更改该代码。
It's a long and tedious work and every time i see the code i feel a step (or rather a leap) closer to mental breakdown, but the code quality will improve (slowly but mostly reliably).
这是一项漫长而乏味的工作,每当我看到代码时,我感觉更接近精神崩溃的一步(或者更确切地说是跳跃),但代码质量将会提高(缓慢但最可靠)。
Your situation seems to be quite similar, so maybe my ideas might help you with your code.
您的情况似乎非常相似,所以也许我的想法可能会帮助您使用代码。
In short
简而言之
Start small, change only what you work on and begin to write only limited unit tests and expand them the more you learn about the system.
从小处着手,只改变你工作的东西,开始只编写有限的单元测试,并在你学习系统的过程中扩展它们。
#9
1
Start by doing black box, functional testing, connected parts or bits and pieces here and there. This makes continued development and refactoring/rewriting much easier.
首先要做黑盒子,功能测试,连接部件或零碎件。这使得持续开发和重构/重写变得更加容易。
Been there, doing that.
在那里,做到这一点。
Took a while till we could start adding unit testing, but got there eventually.
花了一段时间,直到我们可以开始添加单元测试,但最终到达那里。
It's still far from bulletproof but all developers are much more confident to dare to change/fix things when you know that there is a test suite waiting to try to verify your code changes.
它仍然远非防弹,但当您知道有一个测试套件等待尝试验证您的代码更改时,所有开发人员都更有信心敢于更改/修复问题。
#10
1
From your scenario, you should have a long list of fragile areas of the code that tend to be affected by innocuous changes (or at least areas that absolutely must work). If you can wright tests against this list, you have a quick way to find out when a change you're implementing has broken something.
从您的场景中,您应该有一长串代码的脆弱区域,这些区域往往会受到无害的更改(或者至少必须工作的区域)的影响。如果你可以对这个列表进行测试,你可以快速找到你正在实施的更改何时破坏了某些内容。
#11
0
In theory, definitely. The more tightly coupled, bug ridden the maintenance process then the more important the tests. In practise, walk away and live another day!
理论上,绝对。绑定越紧密,错误就越多,维护过程就会越多,测试就越重要。在实践中,走开,再过一天!
#12
0
If things behave reliably, you can test them, right? Your system works the majority of the time, so you can test for those success conditions.
如果事情表现得可靠,你可以测试它们,对吧?您的系统大部分时间都在工作,因此您可以测试这些成功条件。
..innocuous part of the website, such as splitting a "name" field into two separate "first" and "last" fields, will bring the site to its knees and require hours of rollbacks
..网站的一部分,例如将“名称”字段拆分为两个单独的“第一”和“最后”字段,将使网站陷入困境并需要数小时的回滚
Splitting a field apart such as first and last name sounds like a potential massive thing - but sounds like you've learned your lesson. At least try to get some funding for a full size test system and put the procedures in place to make moving production data to it automatic, so you can fully test this thing.
拆分一个字段,如名字和姓氏听起来像一个潜在的巨大的东西 - 但听起来你已经吸取了教训。至少尝试为全尺寸测试系统获得一些资金并制定程序以自动生成生产数据,因此您可以对此进行全面测试。
Sounds pretty horrible though. Time to dust of the ole resume?
听起来很可怕。时间尘埃的简历?
#13
0
You might want to consider billing another 40 hours/iteration to create a nice BDD (domain) model of how the application works or better: should work. That creates a nice framework where you can document the needed features. When the model is complete enough, you can estimate how much time you'd need to convert it to a working application.
您可能需要考虑另外40小时/迭代计费,以创建应用程序如何工作或更好的良好BDD(域)模型:应该工作。这创建了一个很好的框架,您可以在其中记录所需的功能。当模型足够完整时,您可以估计将其转换为工作应用程序所需的时间。