有效使用遗留代码的要点

2020-10-29 10:26:29

如果你见过这个定义,那就是迈克尔·费瑟斯的书“有效地使用遗留代码”(Working Efficient With Legacy Code)中的定义。

虽然我有一个稍微扩展的定义,但这是一个非常有效和有用的定义!

费瑟斯的书是2004年出版的。然而,它的内容并没有过时。这是有原因的,这个委员会地带说得最好:

当有关于遗留代码的帖子时,很快就会有人留言建议你阅读它。

我没看过。我看过推荐的。但是那本书的重点是什么呢?

下面是我对本书要点的总结,以及它们如何帮助您处理现有的代码库。

当代码没有经过测试时,您怎么知道您没有破坏任何东西呢?

你需要反馈。自动反馈是最好的。因此,这是您需要做的第一件事:编写测试。

你的目标是到达那里。这本书的重点是告诉你,当你必须处理一个令人难以置信的复杂的代码库时,你如何才能做到这一点。这就把我们带到了下一个点…。

在更改代码之前,您应该准备好测试。但是要将测试放在适当的位置,您必须更改代码。

你不会的。但在检查到位之前你应该格外小心。您应该执行最低限度的、安全的重构。

一旦你到了测试阶段,你就知道如何继续了。前两点是难点。

这是因为代码从一开始就不是为了可测试而编写的。99%的情况下,这是一个依赖问题:您想要测试的代码无法运行,因为它需要一些难以放入测试中的东西。

有时是数据库连接。有时是对第三方服务器的呼叫。有时它是一个难以实例化的复杂参数。通常,这是所有这些的复杂组合。

Seam是在不更改代码的情况下更改程序行为的地方。

有不同类型的接缝。它的要点是确定如何在不接触源代码的情况下更改代码行为。

导出类DatabaseConnector{//大量代码…。Connect(){//执行一些调用以连接到数据库。}}。

假设当您尝试将代码放入测试中时,connect()方法会给您带来问题。嗯,整个班级都是你可以改变的接缝。

您可以在测试中扩展此类,以防止其连接到实际的数据库:

FakeDatabaseConnector类扩展DatabaseConnector{connect(){//覆盖对DB控制台的有问题的调用。日志(";连接到数据库";)}}。

如果您的语言允许您在不更改源代码的情况下更改代码行为,那么您就有了编写测试的入口点。

关于测试最佳实践的讨论通常会变成激烈的辩论。您是否应该应用测试金字塔原则并编写最多的单元测试?或者,您是否应该转而接受测试杯,并且主要编写集成测试?

因为他们对“单位”的定义不一样。因此,有些人谈论“集成测试”,而另一些人则谈论“单元测试”。

为了避免任何混淆,Michael Feeters对什么不是单元测试给出了明确的定义。

它与基础架构(例如数据库、网络、文件系统、环境变量…)通信。

编写最多具有这两个品质的测试。你怎么称呼他们并不重要。

现在,有时编写这样的测试真的很难,因为您甚至不理解代码应该做什么。有一种技术可以解决这个…问题。

在重构代码之前,您需要测试。但是编写这些测试可能很有挑战性。尤其是当代码很难理解的时候。

“表征测试是表征一段代码的实际行为的测试。”

您可以捕获代码的当前行为,而不是编写全面的单元测试。您可以对它的功能进行快照。

对于大多数系统,代码实际做什么比它应该做什么更重要。

您可以通过这些测试快速覆盖遗留代码,为您提供重构的安全网。

这项技术在野外也被称为“批准测试”、“快照测试”或“黄金大师”。一样的东西。

期限短是很常见的情况。当你很匆忙的时候,很难抽出时间不把事情弄得更糟。希望你能做点什么,…。

这就是破窗理论:小小的混乱会招致更严重的犯罪。如果类已经有2,000行长,谁会在乎您再添加3条if语句呢?

但是,如果您真的、真的没有时间为那个类编写测试怎么办?这只是3个if语句,你可能觉得你没有理由为此花2天的时间--尽管你应该这样做。

在这样一个棘手的位置,你仍然可以用这两个技巧做出正确的决定。

类事务网关{//…。很多代码postEntries(条目){for(Let Entry Of Entry){条目。PostDate()}//…。很多代码交易捆绑包。GetListManager()。添加(条目)}//…。很多代码}。

假设您需要对条目进行重复数据删除,但是postEntries()很难测试,您真的没有时间做这件事。

然后,在现有的未经测试的代码中插入对该方法的调用。最小的变化,最小的风险。

类事务网关{//…。很多代码唯一条目(Entries){//一些巧妙的逻辑来消除条目的重复数据,经过充分测试!}postEntries(条目){const Unique eEntries=this。唯一条目(唯一条目的Let Entry){Entry.(Let Entry Of Unique EEntries){Entry.。PostDate()}//…。很多代码交易捆绑包。GetListManager()。Add(唯一条目)}//…。很多代码}。

类事务网关{//…。很多代码+唯一条目(条目){+//一些巧妙的逻辑来消除条目的重复数据,经过充分测试!+}postEntries(条目){+Const Unique eEntries=this.Unique eEntries(条目)++for(让条目条目){-for(让条目条目){entry.postDate()}//…。大量代码+transactionBundle.getListManager().add(uniqueEntries)-transactionBundle.getListManager().add(entries)}//…。很多代码}。

您可以萌发单个方法、整个类或隔离新代码的任何东西。

当您需要做的更改应该发生在现有代码之前或之后时,您也可以包装它。

类事务网关{//…。很多代码postEntries(条目){for(Let Entry Of Entry){条目。PostDate()}//…。很多代码交易捆绑包。GetListManager()。添加(条目)}//…。很多代码}。

解决该问题的另一种方法是包装它,因此我们将已消除重复项的列表传递给postEntries():

类事务网关{//…。很多代码postEntries(条目){//一些巧妙的逻辑来检索唯一的条目。PostEntriesThatAreUnique(Unique EEntries)}postEntriesThatAreUnique(Entries){for(Let Entry Of Entries){Entry.。PostDate()}//…。很多代码交易捆绑包。GetListManager()。添加(条目)}//…。很多代码}。

在测试中,您需要更改有问题的postEntriesThatAreUnique(),这样您就可以测试重复数据删除逻辑是否工作。

类事务网关{//…。很多代码+postEntries(条目){+//一些用于检索唯一条目的巧妙逻辑+this.postEntriesThatAreUnique(Unique EEntries)+}+postEntriesThatAreUnique(Entries){-postEntries(Entries){for(Let Entry Of Entries){entry.postDate()}//…。大量代码transactionBundle.getListManager().add(entries)}//…。很多代码}。

这些技术并不理想,而且存在缺陷。但在处理遗留代码时,它们是有用的工具。

当您不得不使用不是您编写的、没有经过测试并且文档记录很少的代码时,您会不知所措!

因此,首先,您需要打破依赖关系并编写测试。但是,当代码确实不透明时,您从哪里开始呢?

想怎么玩代码就怎么玩吧。提取函数、简化代码、重命名变量…。了解一下密码。一旦您这样做了,恢复您的更改并通过适当的测试重新开始。

“避免在代码中乱放对库类的直接调用。你可能认为你永远不会改变它们,但这可能会成为一个自我实现的预言。“。

我想强调这个建议,因为这是一个非常常见的错误。我看过很多次了!

我们使用图书馆来做这项工作,并且节省了我们的时间。到目前一切尚好。

但我们很少会花额外的时间将这些工具包装在我们拥有的自定义抽象中。

因此,它们的实现会在我们的代码库中泄漏!我们的所有代码都快速依赖于特定的API。它像寄生虫一样传播。直到有一天,我们可以很容易地摆脱它,或者对图书馆进行重大升级。

考虑一下您使用的所有ORM代码、监控库和实用程序包。你能控制他们吗?或者你依赖他们吗?

虽然我已经概述了书中的建议,但书中还有更多的示例和方法!

你每天都要处理遗产法。这是您可以在该主题上找到的最具可操作性的资源之一。

您可能已经阅读(或列出)了其他书籍,如“干净代码”和“重构”。这些也是必读的。但我建议从有效使用遗留代码开始。

如果您想重构您的代码,您首先需要对其进行测试。迈克尔·费瑟斯的书的重点是对现有的、错综复杂的乱七八糟的东西进行测试。

诚然,您可能会对书中的代码示例使用您不懂的语言编写感到不舒服。

遗留代码并不总是易于阅读,因此这实际上是相关的。这是一项你需要练习的技能。

Java代码是面向对象的代码,即使您不懂该语言,也应该能够理解。

所以,再说一遍:这个总结给了你一个很好的概述,告诉你书中有哪些建议。但是还有更多!

这本书详细介绍了如何在不同的用例中应用这些建议。如果你喜欢这篇摘要,你就会喜欢这本书。

订阅我的时事通讯,每周三直接在您的收件箱中接收我的传统代码提示和技巧。

由在加拿大蒙特利尔生活和工作的Nicolas Carlo撰写,🍁他创建了软件工匠蒙特利尔社区,该社区关心构建可维护的软件。

←查找使用旧代码的更多提示