对于承担增强和改进任务的开发人员的任何建议重构业务关键应用程序?
最近我在工作中继承了一个业务关键项目来“增强”。在过去的五年里,该代码经过了许多人的编写和传递。不再在公司工作的顾问和全职员工已经扼杀了这个非常微妙且过于敏感的应用程序。我们大多数人都必须处理遗留代码或此类项目……这是作为开发人员的一部分……但是……
零单元和零系统测试。逻辑在存储过程、视图(是的,我说视图)和代码之间相互混合(有时无缘无故地重复)。文档?是的,对。 我很害怕。是的,即使是最小的“调整”或重构也是非常神圣的。一点小事故就会给我的雇主带来重大的收入损失和潜在的法律问题。
那么,有什么建议吗?我的第一个想法是开始针对现有代码编写断言/单元测试。然而,这也只能到此为止,因为存储过程中嵌入了很多逻辑。 (我知道可以测试存储过程,但从历史上看,与单元测试源代码逻辑相比,它要困难得多)。 另一种或附加的方法是比较应用程序执行功能之前和之后的数据库状态,进行一些代码更改,然后进行数据库状态比较。
Recently I inherited a business critical project at work to "enhance". The code has been worked on and passed through many hands over the past five years. Consultants and full-time employees who are no longer with the company have butchered this very delicate and overly sensitive application. Most of us have to deal with legacy code or this type of project... its part of being a developer... but...
There are zero units and zero system tests. Logic is inter-mingled (and sometimes duplicated for no reason) between stored procedures, views (yes, I said views) and code. Documentation? Yeah, right.
I am scared. Yes, very sacred to make even the most minimal of "tweak" or refactor. One little mishap, and there would be major income loss and potential legal issues for my employer.
So, any advice? My first thought would be to begin writing assertions/unit tests against the existing code. However, that can only go so far because there is a lot of logic embedded in stored procedures. (I know its possible to test stored procedures, but historically its much more difficult compared to unit testing source code logic).
Another or additional approach would be to compare the database state before and after the application has performed a function, make some code changes, then do database state compare.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
我刚刚重写了企业文件系统最复杂的子系统的数千行,使其成为多线程的,所以所有这些都来自经验。如果重写是合理的(如果进行重写是为了显着增强功能,或者如果现有代码妨碍了更多增强功能),则以下是提示:
您需要对首先你自己的能力能够做到这一点。只有当您对所涉及的技术有足够的经验时,才能做到这一点。
沟通,沟通,沟通。让所有相关利益相关者知道,这是一团糟,这是有风险的,这不能急于完成,这需要零碎完成 - 一次攻击一个领域。
彻底了解系统。记录每一个细微差别、技巧和技巧。记录总体设计。向任何老前辈询问您无法证明的任何代码存在的历史原因。这些是您不想踩到的地雷 - 您可能会认为这些是无用的代码,然后在摆脱它们后后悔不已。
单元测试。通过任何已存在的测试套件来运行系统,否则首先为现有代码编写测试(如果它们不存在)。
在重写期间将调试代码喷到各处 - 断言、日志记录、控制台打印(您应该能够打开和关闭它们,以及指定不同级别的输出,即控制详细程度)。根据我的经验,这是必须的,并且在重写期间有很大帮助。
在重写
在浏览代码时,列出所有需要完成的事情 - 你需要找出的事情,你需要编写测试的事情,你需要提出问题的事情,提醒你如何做的注释重构一些代码,任何可能影响你重写的东西......你不能忘记任何事情!我使用 Outlook 任务来执行此操作(只需确保您使用的任何内容始终在您面前 - 这是我坐在办公桌上后打开的第一个应用程序)。如果我被打断,我会写下我一直在思考的任何事情,并提示返回任务后从哪里继续。
尝试避免重写中的黑客行为(这是您重写它的原因之一)。想想你遇到的棘手问题。与其他人讨论这些问题,并反驳你的想法(没有什么比这更好的了),并提出干净的解决方案。查看您放入待办事项列表中的所有任务 - 为现有设计绘制 10,000 英尺的图片,然后决定新的重写将是什么样子(在模块、子模块、它们如何组合在一起等方面)。
先解决最棘手的问题。这将使你避免在隧道尽头遇到无法解决的问题,并避免你后退一步。当然,您需要知道最棘手的问题是什么 - 因此,在尝试现有代码时,最好先记录所有内容。
先
I just rewrote thousands of lines of the most complex subsystem of an enterprise filesystem to make it multi-threaded, so all of this comes from experience. If the rewrite is justified (it is if the rewrite is being done to significantly enhance capabilities, or if existing code is coming in the way of putting in more enhancements), then here are the pointers:
You need to be confident in your own abilities first of all to do this. That comes only if you have enough prior experience with the technologies involved.
Communicate, communicate, communicate. Let all involved stake-holders know, this is a mess, this is risky, this cannot be done in a hurry, this will need to be done piece-meal - attack one area at a time.
Understand the system inside out. Document every nuance, trick and hack. Document the overall design. Ask any old-timers about historical reasons for the existence of any code you cannot justify. These are the mines you don't want to step on - you might think those are useless pieces of code and then regret later after getting rid of them.
Unit test. Work the system through any test-suite which already exists, otherwise first write the tests for existing code, if they don't exist.
Spew debugging code all over the place during the rewrite - asserts, logging, console prints (you should have the ability to turn them on and off, as well specify different levels of output i.e. control verbosity). This is a must in my experience, and helps tremendously during a rewrite.
When going through the code, make a list of all things that need to be done - things you need to find out, things you need to write tests for, things you need to ask questions about, notes to remind you how to refactor some piece of code, anything that can affect your rewrite... you cannot afford to forget anything! I do this using Outlook Tasks (just make sure whatever you use is always in front of you - this is the first app I open as soon as I sit down on the desk). If I get interrupted, I write down anything that I have been thinking about and hints about where to continue after coming back to the task.
Try avoiding hacks in your rewrite (that's one of the reasons you are rewriting it). Think about tough problems you encounter. Discuss them with other people and bounce off your ideas against them (nothing beats this), and put in clean solutions. Look at all the tasks you put into the todo list - make a 10,000 feet picture of existing design, then decide how the new rewrite would look like (in terms of modules, sub-modules, how they fit together etc.).
Tackle the toughest problems before any other. That'll save you from running into problems you cannot solve near the end of tunnel, and save you from taking any steps backward. Of course, you need to know what the toughest problems will be - so again, better document everything first during your forays into existing code.
获取非常严格的要求列表。
确保您有隐式需求和显式需求 - 即它必须与哪些程序一起工作以及如何工作。
写下当前如何使用它的所有场景和用例。
编写大量单元测试。
编写大量集成测试来测试程序与其必须使用的现有程序的集成。
编写大量
与使用该程序的每个人交谈,以找出更多隐性要求。
在投入生产之前测试、测试、测试变更。
CYA:)
Get a very firm list of requirements.
Make sure you have implicit requirements as well as explicit ones - i.e. what programs it has to work with, and how.
Write all scenarios and use cases for how it is currently being used.
Write a lot of unit tests.
Write a lot of integration tests to test the integration of the program with existing programs it has to work with.
Talk to everyone who uses the program to find out more implicit requirements.
Test, test, test changes before moving into production.
CYA :)
除了@Sudhanshu 的伟大清单之外(并且在某种程度上不同意他的#8),还有两件事:
首先,请注意未经测试的代码是有错误的代码 - 对于“的任何定义,您开始使用的代码几乎肯定无法正常工作正确”而不是“像未修改的代码一样工作”。也就是说,准备好发现系统中的意外行为,向系统中的专家询问该行为,并让他们得出结论:系统没有按应有的方式工作。让他们做好准备 - 警告他们,如果没有测试或其他文档,就没有理由认为它会按照他们认为的方式工作。
下一篇: 重构唾手可得的成果 放轻松,慢慢来,非常小心。注意代码中一些简单的东西——比如重复——并测试包含重复的任何方法,然后消除它。起泡沫,冲洗,重复。在进行更改之前不要为所有内容编写测试,而是为要更改的内容编写测试。这样,它在每个阶段都保持可发布,并且您可以不断增加价值,不断改进代码库。
我说了“两件事”,但我想我会添加第三件事:管理期望。让你的客户知道你对这项任务有多害怕;让他们知道他们的处境有多糟糕。让他们知道进展有多慢,并让他们知道你会随时向他们通报进展情况(当然,要这样做)。您的客户可能认为他/她要求“只是一点点修复” - 并且功能确实可能只改变一点点 - 但这并不意味着它不会需要大量的工作和大量的时间。你明白这一点;您的客户也需要这样做。
Two things, beyond @Sudhanshu's great list (and, to some extent, disagreeing with his #8):
First, be aware that untested code is buggy code - what you are starting with almost certainly does not work correctly, for any definition of "correct" other than "works just like the unmodified code". That is, be prepared to find unexpected behavior in the system, to ask experts in the system about that behavior, and for them to conclude that it's not working the way it should. Prepare them for it to - warn them that without tests or other documentation, there's no reason to think it works they way they think it's working.
Next: Refactor The Low-Hanging Fruit Take it easy, take it slow, take it very careful. Notice something easy in the code - duplication, say - and test the hell out of whatever methods contain the duplication, then eliminate it. Lather, rinse, repeat. Don't write tests for everything before making changes, but write tests for whatever you're changing. This way, it stays releasable at every stage and you are continuously adding value, continuously improving the code base.
I said "two things", but I guess I'll add a third: Manage expectations. Let your customer know how scared you are of this task; let them know how bad what they've got is. Let them know how slow progress will be, and let them know you'll keep them informed of that progress (and, of course, do it). Your customer may think s/he's asking for "just a little fix" - and the functionality may indeed change only a little - but that doesn't mean it's not going to be a lot of work and a lot of time. You understand that; your customer needs to, too.
我以前遇到过这个问题,并且四处询问过(在堆栈溢出的日子之前),并且一直向我推荐这本书。 http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/ dp/0131177052
I've had this problem before and I've asked around (before the days of stack overflow) and this book has always been recommended to me. http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052
问问自己:你想实现什么目标?你的使命是什么?你有多少时间?衡量成功的标准是什么?有什么风险?您如何减轻和处理它们?
除非您知道自己想要实现什么目标,否则不要碰任何东西。
代码可能是“坏”的,但这意味着什么?代码工作正常吗?因此,如果您重写代码,使其执行相同的操作,您将花费大量时间重写一些引入错误的内容,以便代码执行相同的操作?为了什么目的?
您可以做的最简单的事情就是记录系统的功能。我并不是说要编写令人头脑麻木的 Word 文档,没人会读。我的意思是编写关键功能的测试,并在必要时重构代码以允许编写此类测试。
Ask yourself this: what are you trying to achieve? What is your mission? How much time do you have? What is the measurement for success? What risks are there? How do you mitigate and deal with them?
Don't touch anything unless you know what it is you're trying to achieve.
The code might be "bad" but what does that mean? The code works right? So if you rewrite the code so it does the same thing you'll have spent a lot of time rewriting something introducing bugs along the way so the code does the same thing? To what end?
The simplest thing you can do is document what the system does. And I don't mean write mind-numbing Word documents no one will ever read. I mean writing tests on key functionality, refactoring the code if necessary to allow such tests to be written.
你说你害怕接触代码,因为法律、收入损失以及零文档。那么你看懂代码了吗?您应该做的第一件事就是记录它并确保您在考虑重构之前理解它。完成此操作并确定问题区域后,按照以最少的更改获得最大收益的顺序列出重构建议,并逐步解决它。如果满足以下条件,重构就更有意义:代码的预期寿命很长,将添加新功能,错误修复很多。至于测试数据库状态 - 我最近参与了一个项目,这正是我们成功所做的。
You said you are scared to touch the code because of legal, income loss and that there is zero documentation. So do you understand the code? The first thing you should do is document it and make sure you understand it before you even think about refactoring. Once you have done that and identified the problem areas make a list of your refactoring proposals in the order of maximum benefit with minimum changes and attack it incrementally. Refactoring makes additional sense if: the expected lifespan of the code will be long, new features will be added, bug fixes are numerous. As for testing the database state - I worked on a project recently where that is exactly what we did with success.
是否有可能将数据库部分和非数据库部分分开,以便 DBA 能够应对存储过程和数据库本身的挑战,从而让您有时间处理系统的其他部分?这还假设有一名 DBA 可以挺身而出并承担应用程序的这一部分。
如果这是不可能的,那么我会建议看看代码库有多大,以及是否有可能获得一些帮助,这样这就不全靠你了。虽然这可能被视为逃避责任,但关键是事情通常不应该只掌握在一个人手中,因为它们有时可能会消失。
祝你好运!
Is it possible to get a separation of the DB and non-DB parts, so that a DBA can take on the challenge of the stored procedures and databases themselves freeing you up to work on the other parts of the system? This also presumes that there is a DBA who can step up and take that part of the application.
If that isn't possible, then I'd make the suggestion of seeing how big is the codebase and if it is possible to get some assistance so it isn't all on you. While this could be seen as side-stepping responsibility, the point would be that things shouldn't be in just one person's hands usually as they can disappear at times.
Good luck!