最近有人在Twitter上问我,如果不理解代码的工作原理,如何重构。 我回答说 ,这是“通过重构学习”。 然后我尝试用Google搜索它,却一无所获 。 我很惊讶。 对我来说,重构似乎是研究源代码的最有效,最明显的方法。 这是我通常的九个面向对象步骤。
理查德·谢泼德(Dom Hemingway)(2013)
根据Wikipedia的说法, 代码重构是“重构现有计算机代码的过程-更改因子分解-而无需更改其外部行为。” 重构的目的是使代码更具可读性并适合修改。
这是我不知道代码但需要对其进行修改时通常要做的事情。 从最简单的技术开始,按照复杂性的顺序对技术进行排序。
当我使用自定义settings.jar在IntelliJ IDEA中打开Cactoos的源代码时,我看到的是这样的: 当我打开诸如Spring Boot的源代码时,我会看到类似的东西(它是osbImageBanner它是从一千个看起来非常相似的其他类中随机选择的): 看到不同?
当我看到别人的代码时,我要做的第一件事就是使它对我的IDE来说是“红色斑点”。 这些红色斑点中的大多数很容易消除,而其他一些将需要一些时间进行重构。 在这样做的同时,我学到了很多关于 废话 我必须处理的程序。
我前段时间写道 ,方法主体内的空行是不好的事情。 它们是冗余复杂度的明显指标。 程序员倾向于将它们添加到他们的方法中以简化内容。
这是来自Apache Maven代码RepositoryUtils一种方法(随机选择类RepositoryUtils ,但几乎所有其他类的格式都相同): < 除了“全红”之外,他们的代码还充满了空行。 删除它们将使代码更易读,也将帮助我理解它的工作方式。 更大的方法将需要重构,因为如果没有空行,它们将几乎变得完全不可读。 因此,我主要通过将它们分解为更小的方法来压缩,理解并缩小它们。
我通常赞成为变量使用简短的一名词名称,并为方法使用简短的动词名称。 我相信较长的“复合”名称表明不必要的代码复杂性。
例如,我在Spring Boot的osbweuUndertowServletWebServerFactory类中找到了方法registerServletContainerInitializerToDriveServletContextInitializers (69个字符!)。 我不知道为什么笔者跳过couldYouPlease前缀和otherwiseThrowAnException后缀。
除了笑话,这么长的方法名称清楚地表明代码太复杂了,无法用简单的register甚至registerContainer来解释。 似乎有许多不同的容器,初始化程序,Servlet和其他需要以某种方式注册的生物。 当我加入一个项目并看到一个使用该名称的方法时,我正为大麻烦做准备。
当开始使用外部代码或旧代码时,使名称更短是我必须执行的重构步骤。
大多数类(和方法)都没有任何文档,特别是当我们谈论的是闭源商业代码时。 如果这些班级或多或少具有描述性的名称并且规模小且具有凝聚力,我们将很幸运。
但是,我更喜欢处理单元测试,而不是文档。 他们更好地解释了代码,并证明了它可以工作。 当我不了解类的工作原理时,我尝试为其编写单元测试。 在大多数情况下,由于许多原因,这是不可能的。
我之前写过 ,在单个方法中存在多个return语句并不是鼓励面向对象的编程。 相反,方法必须始终具有单个出口点,就像函数编程中的那些函数一样。
从Spring Boot的osbcpbBinder类中查看此方法(那里有很多类似的示例,我随机选择了一个):
这么小的方法有五个return语句。 对于面向对象的代码来说太多了。 程序代码可以,我有时也会写。 例如,我们的这个Groovy脚本也有五个return关键字:
但这是Groovy,不是一门课。 这只是一个过程,一个脚本。
重构和删除多个return语句绝对有助于使代码更整洁。 通常是因为没有它们,有必要使用if/then/else语句的更深层嵌套,然后代码开始看起来很难看,除非您将其分解为较小的部分。
空是邪恶的 ,这是众所周知的事实。 但是,它们仍然无处不在。 例如,Spring Boot v2.0.0.RELEASE和243K LoC中有4,100个Java文件,其中包含null关键字7,055次。 这意味着每35行大约有一个null 。
相反,我几年前创建的Takes Framework具有771个Java文件,15.4万个LoC和58个null关键字。 每2700行大约是一个null 。 看到不同?
当您删除NULL时,代码会变得更整洁,但这并不是那么容易。 有时甚至是不可能的。 这就是为什么我们在Takes中仍然有58个null情况。 我们根本无法删除它们,因为它们来自JDK。
正如我前段时间所展示的 , 不变性有助于缩小对象。 我在处理的外部代码中看到的大多数类都是可变的。 和大。
如果查看jpeek分析的任何工件,您会发现在大多数对象中,大约80%的类是可变的。 从可变性到不变性是面向对象编程中的一大挑战,如果解决,它将带来更好的代码。
使事物不可变的重构步骤纯粹是有利可图的。
如果您是过程程序员,则静态方法和属性很方便。 如果您的代码是面向对象的,那么它们必须消失 。 在Spring Boot中,有7,482个static关键字,这意味着每32行代码需要一个。 相反,在Takes中,我们有310个static -s,每496行是一个。
将这些数字与有关NULL的统计数据进行比较,您会发现摆脱static是一项更为复杂的任务。
这是最后一步,也是最复杂的一步。 这很复杂,因为我将静态分析仪配置为最大潜力甚至更高。 我正在使用Qulice ,它是Checkstyle,PMD和FindBugs的聚合器。 这些家伙本身很坚强,但Qulice使他们变得更坚强 ,增加了几十个定制支票。
我用于静态分析的原理是0/100。 这意味着整个代码库是干净的,没有Qulice投诉,或者它很脏。 中间什么都没有。 这不是查看静态分析的非常典型的方法。 大多数程序员使用这些工具只是为了收集有关其代码的“意见”。 我将它们用作重构的指南。
观看此视频,该视频演示了Qulice对Spring Boot中的spring-boot-project/spring-boot子模块的投诉(该视频无休止,因为我在等待中失去了耐心):
当Qulice说一切都干净时,我认为代码库已准备就绪,可以进行维护和修改。 至此重构已经完成。
翻译自: https://www.javacodegeeks.com/2018/04/nine-steps-of-learning-by-refactoring.html