技术债务_有效解决技术债务

技术债务

“Shipping first time code is like going into debt. A little debt speeds development so long as it is paid back promptly with a rewrite… The danger occurs when the debt is not repaid. Every minute spent on not-quite-right code counts as interest on that debt. Entire engineering organizations can be brought to a stand-still under the debt load of an unconsolidated implementation, object-oriented or otherwise.” — Ward Cunningham, 1992

“首次交付代码就像负债累累。 只要通过重写Swift偿还债务,一点债务就能加快发展速度。如果不偿还债务,就会发生危险。 每分钟上不-相当右代码计数的花费 利息 这些债务。 整个工程组织可能会因为未合并的实施, 面向对象 或其他原因 的债务负担而陷入停顿 。” 沃德·坎宁安 ( Ward Cunningham) ,1992年

Most teams deal with technical debt in one way or another. Just like with credit card debt, once you get to a certain point a feeling of defeat may take over and declaring bankruptcy may feel like the only way out. In software land this is equivalent to declaring we need a full rewrite. Fortunately I never had to dig myself out of financial debt but I did have to do it for technical debt on more than one occasion. To further extend this analogy, the advice to get rid of financial debt is being strategic, and prioritizing the debt that is hurting you the most so you can increasingly improve the financial situation. In this article I’ll talk about similar strategies to deal with technical debt, including concrete tips that can be applied to almost any codebase.

大多数团队以一种或另一种方式处理技术债务。 就像信用卡债务一样,一旦达到某一点,失败的感觉就会被接管,宣告破产可能是唯一的出路。 在软件领域,这等同于声明我们需要完全重写。 幸运的是,我从来不必从财务债务中解脱出来,但我确实不得不多次处理技术债务。 为了进一步扩展此类比喻,消除金融债务的建议具有战略意义,并且将对您最不利的债务排在优先位置,以便您可以逐步改善财务状况。 在本文中,我将讨论解决技术债务的类似策略,包括可应用于几乎所有代码库的具体技巧。

了解你的情况 (Understand Your Situation)

The first step in the improvement journey is to determine where you currently stand. In order to do that the team will need a good set of metrics. These metrics will help paint a clear picture of the current state of the codebase so developers and stakeholders can understand why things need to change. These metrics will also help track the progress, which is extremely important for the success of the project. Stakeholder support will continue (or increase) as progress is demonstrated and the developer team will also feel a burst of motivation as they see the impact of their changes.

改善旅程的第一步是确定您目前的位置。 为了做到这一点,团队将需要一套很好的指标。 这些度量标准将帮助您清楚地了解代码库的当前状态,以便开发人员和涉众可以理解为什么需要更改。 这些度量标准还将有助于跟踪进度,这对于项目的成功至关重要。 随着进度的证明,利益相关者的支持将继续(或增加),并且开发人员团队在看到变更的影响时也会感到一阵冲动。

Different teams may choose different metrics and that’s all good. What really matters is if these metrics will be an effective measurement for your organization. If the organization already values (or collects) a certain set of metrics, the safest route may be to use those. For our team, we use SonarQube (SQ) which exposes a good set of sensible metrics:

不同的团队可能会选择不同的指标,这很好。 真正重要的是,这些指标是否将对您的组织有效。 如果组织已经评估(或收集)了一组特定指标,那么最安全的方法就是使用这些指标。 对于我们的团队,我们使用SonarQube(SQ),它公开了一系列合理的指标:

  • Code coverage

    代码覆盖率
  • Duplication

    复制
  • Code smells

    代码气味

SonarQube exposes many more in-depth metrics as defined in their docs but for the purposes of our project we found those to be good metrics to use to track progress for a few reasons. First, SQ is the official tool in our organization so every other project uses the same metrics. Second, these are the main metrics in the dashboard, so anyone that looks at the report can clearly see them. Last, these metrics are fairly easy to explain to any stakeholders, unlike afferent coupling, cyclomatic complexity etc.

SonarQube公开了其文档中定义的更多深入指标,但出于我们的项目目的,出于某些原因,我们发现这些指标是跟踪进度的良好指标。 首先,SQ是我们组织中的官方工具,因此每个其他项目都使用相同的指标。 其次,这些是仪表板中的主要指标,因此查看报告的任何人都可以清楚地看到它们。 最后,与传入耦合,圈复杂度等不同,这些度量标准很容易向任何涉众解释。

This is by no means a pitch for SQ but this tool does have a very handy feature to measure a change in the team’s behavior pretty quickly. When you make a few small changes in a codebase with hundreds of thousands (or millions) of lines of code, a few changes may be a drop in the bucket, not affecting the overall metrics at all. SQ defines a Leak Period, which analyzes code that was modified since your last release. So, any change in how the team is committing code will show up pretty quickly, even if the total numbers are insignificant when looking at totals.

这绝不是SQ的重点,但此工具确实具有非常方便的功能,可以很快地衡量团队行为的变化。 当您在具有成千上万(或数百万)行代码的代码库中进行一些小更改时,一些更改可能会丢掉整个存储桶,根本不会影响总体指标。 SQ定义了“泄漏期”,该泄漏期分析自您上次发行以来已修改的代码。 因此,即使在查看总数时总数并不重要,团队提交代码方式的任何更改也将很快显示出来。

Below is a sample screenshot from SQ showing the total numbers on the left and the leak period numbers on the right, in yellow.

以下是SQ的示例屏幕截图,以黄色显示了左侧的总数和右侧的泄漏时间数。

Image for post
Sample dashboard provided by SonarQube. On the left, the all time numbers for the code analyzed. On the right, in yellow, is the leak period showing the metrics for code that has changed in the current period.
SonarQube提供的示例仪表板。 在左侧,分析了代码的所有时间编号。 右侧的黄色为泄漏时间段,显示了当前时间段内已更改的代码的指标。

These metrics are great to track the overall progress but they don’t really tell you what the actual problem areas of the codebase are. For that we relied on another tool: JArchitect. This is the Java version of NDepend, a tool I’ve used a lot in the past and that makes it really easy to get really useful metrics about your code, such as:

这些指标非常适合跟踪总体进度,但它们并不能真正告诉您代码库的实际问题所在。 为此,我们依赖于另一个工具:JArchitect。 这是NDepend的Java版本,这是我过去经常使用的工具,它使得获取有关代码的真正有用的指标非常容易,例如:

  • Lines of code per class and method;

    每个类和方法的代码行;
  • Methods per class and parameters per method;

    每个类的方法和每个方法的参数;
  • Afferent and efferent coupling;

    传出耦合;
  • Cyclomatic complexity;

    圈复杂度;
  • etc

    等等

These are just a few of the metrics but the JArchitect documentation lists dozens more. Below is a sample visualization with a treemap showing the number of instructions per method.

这些只是一些指标,但JArchitect 文档列出了数十个指标。 下面是带有树形图的示例可视化示例,其中显示了每种方法的指令数量。

Image for post
JArchitect snapshot showing a treemap with the number of bytecode instructions per method.
JArchitect快照显示一个树形图,其中包含每个方法的字节码指令数。

These metrics are the ones we initially used to determine the health of the codebase from the developers, fine grained, perspective. Again, choose whatever ones make the most sense for your team.

这些指标是我们最初用于从开发人员的角度来确定代码库运行状况的指标。 同样,选择对您的团队最有意义的选项。

Once metrics are defined the next step is to figure out where to get started. The natural place to start is to look at the metrics and find the worst parts of the codebase and tackle those, right? Well… not really. Sure, refactoring a huge class, breaking it down into smaller components and adding tests, will make that code easier to maintain in the future. These improvements will also show up in our dashboards as an improvement but that’s not guaranteed to be the most effective change for our team, especially in the short term.

定义指标后,下一步就是弄清楚从哪里开始。 一个自然的起点是查看指标并找到代码库中最糟糕的部分并加以解决,对吗? 好吧……不是真的。 当然,重构庞大的类,将其分解为较小的组件并添加测试,将使该代码在将来更易于维护。 这些改进也将作为改进出现在我们的仪表板上,但这不能保证对我们的团队是最有效的更改,尤其是在短期内。

The problem with looking at static code analysis results is they can’t really say what is impacting developers the most. A class may contain a lot of duplication, high cyclomatic complexity or even be a God object but if that class is a part of the system that has been relatively stable, not requiring many changes, then that is not the best place to start spending time on in my opinion.

查看静态代码分析结果的问题是,他们无法真正说出对开发人员影响最大的因素。 一个类可能包含很多重复项,很高的循环复杂性,甚至可能是上帝的对象,但是如果该类是系统中相对稳定的一部分,不需要进行很多更改,那么这不是开始花费时间的最佳位置在我看来。

Git can offer the additional insights that are missing, the temporal data to determine where the team is spending most of their time. A couple of good indicators are the number of commits per file and the age in months since a file was modified. Below are two charts with real data from one of our projects.

Git可以提供缺少的其他见解,时间数据,以确定团队将大部分时间花在哪里。 几个好的指标是每个文件的提交次数以及自文件被修改以来的月数。 以下是两个图表,其中包含来自我们一个项目的真实数据。

Image for post
Git log analysis showing a small number of files with a high number of commits and a long tail with almost no commits at all.
Git日志分析显示少量文件具有大量提交,尾巴很长,几乎没有任何提交。
Image for post
Git log analysis showing how long ago files were last changed. Most files haven’t been changed in the last two years.
Git日志分析显示最近一次更改文件的时间。 在过去两年中,大多数文件都没有更改。

The commits per file chart shows how a small number of files received the overwhelming majority number of changes. The Age in Months chart shows that a great majority of the files haven’t been changed in over two years. The files that show up in the far left of both charts are excellent candidates for further investigation. Now, cross-referencing these results with the hot spots revealed by the static code analysis tools produces a solid list of components that, when refactored, will have a high impact on the quality of life for the team.

每个文件的提交图显示了少数文件是如何收到绝大多数变更的。 “月龄”图表显示,大多数文件在两年内没有更改。 在两个图表的最左端显示的文件都是进行进一步研究的极好候选。 现在,将这些结果与静态代码分析工具所揭示的热点进行交叉引用,即可生成可靠的组件列表,这些组件在进行重构时将对团队的生活质量产生重大影响。

Image for post
The overlap of code highlighted by the metrics, code frequently changed and that was modified recently makes for a great place to start an investigation.
度量突出显示的代码重叠,经常更改的代码以及最近进行了修改的代码重叠,是进行调查的好地方。

I find teams will have a very good gut feeling about which places of the codebase will be the most impactful if fixed. Having the data to backup these assumptions will take the confidence to the next level, especially by stakeholders such as managers, directors etc.

我发现团队对代码库中的哪些位置(如果已修复)最有影响力会有很好的直觉。 拥有数据来备份这些假设将使信心更上一层楼,尤其是对于利益相关者,例如经理,董事等。

如何开始 (How to Get Started)

Going back to the financial debt analogy, we need to find where to start making the incremental changes that are going to get us out of debt. Teams, like most people, can’t afford to put everything on hold, they have to continue to do everything else that keeps the lights on, that keeps the business running while they start to introduce changes to get back on track. Even if they could afford to do it, they may still not be ready to start at the expense of using their time and resources on the wrong things.

回到金融债务的类比,我们需要找到从哪里开始进行逐步改变的方式,这些改变将使我们摆脱债务。 像大多数人一样,团队负担不起一切,他们必须继续做所有其他事情以保持照明状态,使业务保持运转,同时他们开始进行更改以使自己回到正轨。 即使他们有能力做到这一点,他们也可能仍不准备开始,但要花费时间和资源来做错事情。

Starting slow is good, it allows for the time to analyze the results and document any patterns learned that work along the way. In our case, we created a few helper classes on top of Mockito to help simplify testing some parts of the system that were really difficult to test and were amongst our areas of interest. This work took a week or so but it made it possible to test classes that hadn’t been tested in years due to the complexity in mocking the dependencies. That was a good investment.

从慢开始是好的,它使您有时间分析结果并记录在此过程中学习到的所有模式。 在我们的案例中,我们在Mockito之上创建了一些帮助程序类,以帮助简化对系统中某些真正难以测试且属于我们感兴趣的部分的测试。 这项工作花了一周左右的时间,但是由于模拟依赖项的复杂性,使得测试多年来未测试过的类成为可能。 那是一笔不错的投资。

Some components that were at the top of the priority list after our analysis became small refactoring projects. We used them as examples with the rest of the team on how complex changes could be tackled incrementally. Every change was done in small pull requests that attempted to keep the old code and new code running in parallel. I won’t go into the refactoring patterns here but checkout Working Effectively with Legacy Code for more details.

在我们进行分析之后,那些在优先级列表顶部的组件变成了小型重构项目。 我们以团队其他成员为例,说明如何逐步解决复杂的变化。 每个更改都是在小的请求中完成的,这些请求试图使旧代码和新代码保持并行运行。 在这里,我将不介绍重构模式,但请查看“ 有效使用旧版代码”以了解更多详细信息。

At first, the team might be skeptical of these changes, and you might hear statements like:

起初,团队可能会对这些更改表示怀疑,并且您可能会听到类似以下的声明:

  • “This codebase is hopeless, we might as well just start from scratch”

    “此代码库毫无希望,我们不妨从头开始”
  • “We won’t have the time to do this, we’re already behind as it is, management will never let us do it”

    “我们没有时间这样做,我们已经落后了,管理层永远不会让我们这样做”
  • “There are too many risks, you might end up breaking something”

    “风险太多,您可能会破坏某些东西”

Don’t let that drag you down, there’s also going to be some that believe in the cause and start showing changes in behavior early. Make these folks your allies, your champions. Work closely with them, support them and empower them to make the changes that need to be made. That group will grow and you’ll see the power of multiplier effect.

不要让这拖垮您,还会有一些人相信原因并尽早开始表现出行为上的变化。 让这些人成为您的盟友,您的拥护者。 与他们紧密合作,为他们提供支持,并授权他们进行需要进行的更改。 该组将增长,您将看到乘数效应的力量。

Don’t let the time constraints affect you either. Think about Uncle Bob’s Boy Scout Rule: Always leave the code a little better than you found it. Adding one test to a class may not seem like a big deal but the first test is the hardest one to write. It’s hard because there’s all the initial setup to be done, no examples to follow and no precedent to inspire the current developer to add the next test. At first, it won’t seem like a big deal but give it time and the impact will become really clear, just keep watching the metrics.

也不要让时间限制影响您。 想一想鲍伯叔叔的童子军规则:总是把代码比发现的要好一些。 在一个类中添加一个测试似乎没什么大不了,但是第一个测试是最难编写的。 这很困难,因为要完成所有初始设置,没有要遵循的示例,也没有启发现有开发人员添加下一个测试的先例。 起初,这似乎没什么大不了,但是给它一点时间,其影响将变得很明显,只要继续观察指标即可。

东西会碎 (Stuff Will Break)

Stuff will break, that’s a fact! The question is how the team will deal with it. Taking on legacy codebases and dragging them into the future isn’t easy. Ideally one would write tests before every change made, in order to define the base behavior and make sure that holds after the changes. This isn’t always possible and at times you might want to take some calculated risks, actually that might be the first step so that you can even write tests at all. Second, that might be code that no one understands which you might want to remove or refactor. That’s what source control is for, make the changes and revert them if it doesn’t work.

东西会破裂,这是事实! 问题是团队将如何处理它。 继承传统代码库并将其拖到未来并不容易。 理想情况下,应在进行每次更改之前编写测试,以定义基本行为并确保更改之后保持有效。 这并非总是可能的,有时您可能要承担一些经过计算的风险,实际上这可能是第一步,因此您甚至都可以编写测试。 其次,这可能是没人知道您想要删除或重构的代码。 这就是源代码管理的用途,进行更改并在不起作用时将其还原。

All of that isn’t to say a safety net isn’t required. One way of creating a safety net of sorts, when unit tests aren’t there, is to create a suite of integration tests. Testing your software though its external interface, be it a user interface or an API, is easier (at least initially) than trying to get good unit test coverage. Integration tests are generally slower and more prone to fail due to environmental issues, like latency for example. That’s why Martin Fowler’s test pyramid recommends having more unit tests that are fast and reliable instead of relying too much on integration tests. As the project progresses, the integration tests can be replaced by unit tests wherever possible.

所有这些并不是说不需要安全网。 当没有单元测试时,创建各种安全网的一种方法是创建一组集成测试。 通过软件的外部接口(无论是用户界面还是API)来测试软件,比起获得良好的单元测试覆盖范围(至少在最初)要容易得多。 集成测试通常较慢,并且由于诸如延迟之类的环境问题而更容易失败。 这就是为什么马丁·福勒(Martin Fowler)的测试金字塔建议使用更多快速且可靠的单元测试,而不要过多地依赖集成测试。 随着项目的进行,尽可能将集成测试替换为单元测试。

Win的代码审查 (Code Reviews for the Win)

Once the transformation begins, code reviews will become your best friend. In our case, that was the best way to keep sharing the work that was being done as well as starting the conversation about how to write better code, how to follow good patterns and how to test challenging parts of the system.

转换开始后,代码审查将成为您最好的朋友。 在我们的案例中,这是保持共享所做工作以及开始有关如何编写更好的代码,如何遵循好的模式以及如何测试系统中具有挑战性的部分的对话的最佳方法。

Code reviews aren’t meant to impose your style, to force people to do what you want or to demand changes to the code. Use them to ask questions, to understand how developers are thinking about the code and sometimes to provide alternative ways in which problems can be solved. Be patient, the code doesn’t have to be perfect, it should just be trending in the right direction, it should be showing improvement. It’s better for the code to be at 70% of the ideal state but have the developers have ownership over the solution than for you to obsess over every little detail. In other words, choose your battles wisely, let the hard opinions for when they are absolutely necessary, for everything else, prioritize your team’s ownership.

代码审查并非旨在强加您的风格,强迫人们做您想做的事情或要求更改代码。 使用它们提出问题,了解开发人员如何思考代码,有时还提供解决问题的替代方法。 请耐心等待,代码不一定是完美的,它应该朝着正确的方向发展,应该表现出改进。 最好将代码保持在理想状态的70%,但让开发人员拥有解决方案的所有权,而不是让您沉迷于每个小细节。 换句话说,明智地选择自己的战斗,在绝对必要的时候让艰难的观点,对于其他所有事情,优先考虑团队的所有权。

我们走了多远 (How Far We’ve Come)

We’ve been on this journey for two years at the time of the writing. We’re not even close to paying all of our debt, and there’s still a lot to be done, but our “quality of life” has changed completely and so has the way we work. When we started, most pull requests didn’t have tests on them, actually a good chunk of our team hadn’t written unit tests at all.

在撰写本文时,我们已经进行了两年的旅程。 我们甚至还没有偿还全部债务,还有很多事情要做,但是我们的“生活质量”已经完全改变,我们的工作方式也已经改变。 当我们开始时,大多数拉动请求都没有对它们的测试,实际上我们团队中的很大一部分根本没有编写单元测试。

Currently, most of our pull requests are at 85–100% coverage. New people on the team that are completely oblivious to our old state are creating pull requests with 100% coverage on their first week. That’s just our new normal. Thanks to one of the developers on our team, the code has been completely reformatted and it’s following a sensible style guide that is enforced on every build in our CI. Code duplication, which was at about 10% is consistently at 0%. We went from roughly 800 unit tests written over many years by a few heroes to almost 7000 written by each one of us.

当前,我们的大部分拉取请求覆盖率在85-100%之间。 完全不了解我们以前状态的团队新成员在第一周就创建了请求请求,覆盖率达到100%。 那只是我们的新常态。 感谢我们团队中的一名开发人员,代码已完全重新格式化,并且遵循了在我们CI中的每个版本上强制执行的明智的样式指南。 代码重复率大约为10%,始终为0%。 我们从一些英雄多年来写的大约800个单元测试,变成了我们每个人写的大约7000个单元测试。

The following image shows the real metrics of our current (as I write this article) leak period without any embellishments. As you can see, it’s not perfect but it feel really good because we know the progress we’ve made.

下图显示了当前(我撰写本文时)泄漏期间的真实指标,没有任何修饰。 如您所见,它并不完美,但感觉确实不错,因为我们知道我们所取得的进步。

Image for post
Our actual metrics on the current leak period.
我们当前泄漏时间的实际指标。

Honestly, I don’t care about hitting 100% coverage or any other specific number really. The most important thing is that our team knows to test the code that increases the confidence in the releases. We are all empowered to make decisions about what is right, the metrics are just guidance.

老实说,我并不关心达到100%的覆盖率或其他任何具体数字。 最重要的是,我们的团队知道要测试可增加对发行版信心的代码。 我们都有权决定什么是对的,指标只是指导。

结论 (Conclusion)

Hopefully this article gave you a little insight on how to run your own revolution and to dust off that old codebase that everyone says it’s a lost cause.

希望本文能使您对如何进行自己的革命以及清除旧代码库(每个人都认为这是一个失败的原因)有所了解。

The main takeaway from this should be that you don’t need to fix everything, just what has the most impact on slowing your team down. Finding the right metrics is a critical step for you and your team to be confident you’re in the right direction. Additionally, if you need the support of your stakeholders, these numbers will show them you mean business.

这样做的主要好处应该是,您无需修复所有问题,而最能解决影响团队速度的问题。 找到正确的指标是您和您的团队确信您在正确方向上的关键步骤。 此外,如果您需要利益相关者的支持,这些数字将向您表明您的意思是生意。

Changing the culture on the team is going to be the most difficult part of the work, don’t overlook that aspect or else everything may go back to the old ways once you step away. One of my favorite quotes about culture is: “Culture is what happens when no one is looking”. For the change to be permanent your team has to embrace this new way of working.

改变团队的文化将是工作中最困难的部分,不要忽视这一方面,否则一旦您离开,一切都可能会回到原来的方式。 我最喜欢的关于文化的名言之一是:“文化就是没有人看时发生的事情”。 为了使变更永久存在,您的团队必须采用这种新的工作方式。

翻译自: https://medium.com/swlh/tackling-tech-debt-effectively-aeba1527c555

技术债务

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值