在编程的世界里,代码的可读性和可维护性是至关重要的。随着项目的发展,代码库可能会变得庞大而复杂,这时候就需要对代码进行重构,以保持其清晰和高效。重构的一个关键方面就是函数的提取。函数提取不仅能提高代码的可读性,还能增强其可维护性。但是,如何正确地提取函数,避免过度重构,是一个需要仔细考虑的问题。
函数提取是将代码分解成更小、更易于管理的部分的过程。这样做的好处是显而易见的:代码变得更加模块化,每个函数都有明确的职责,这有助于其他开发者理解和维护代码。然而,如果函数提取得过于频繁,可能会导致代码变得过于分散,反而增加了理解代码的难度。
曾经遇到过一个极端的例子,一个函数的长度超过了5000行。这个函数是整个程序的核心,而整个程序有大约150000行代码。这个函数的存在严重影响了整个应用程序的架构。最终,决定完全重写这个程序。这个例子说明了函数过大可能导致的问题。
另一方面,如果过度提取函数,可能会导致代码变得过于分散,每个函数只包含一行代码。这并不是说一行函数不好,而是不能忘记使用大脑进行思考。在提取函数之前,需要考虑想要实现的目标。
在重构的问题上,曾经有过一场有趣的争论。一位编程大师提出了一种名为“提取至极限”的技术,这意味着要不断地提取函数,直到没有东西可以提取为止。然而,另一位专家认为这种技术听起来像是不经过大脑的。
让考虑一个重构的例子。一个开发者将一个方法提取成了一个类,并进一步提取了一些函数。他最终得到了一个包含四个函数的类,但是没有注释。这是否使代码变得更容易阅读了呢?这并不容易判断。
如果试图深入理解更高级别的函数在做什么,那么这个函数现在比原来更难阅读,因为需要跳过所有的函数并理解它们内部发生了什么。相反,原始的例子更容易快速浏览。
如果试图理解原始函数的总体概念,那么它的重构版本更好,因为立即看到这个函数在概念上做了什么。
看到的第三个区别是维护成本。考虑到具体例子,会说重构的版本比第一个更昂贵,至少需要花时间进行重构。一般来说,哪个例子在维护上更昂贵的答案在于需求领域。这些需求告诉,在这种情况下是否如此重要坚持单一职责原则。如果这个函数可以一次性编写并在时间的尽头被遗忘,那么就没有理由提取一个包含四个方法的额外类,没有理由花时间进行重构。相反,如果功能预计会随着时间的推移而增长,那么有充分的理由将其重构成一个类。
此外,当偶然(或故意)在遗留系统中遇到类似的函数时,会急于提取一个包含四个函数的类吗?建议是——没有理由不要这样做,即使代码库测试覆盖率接近100%。为什么?因为没有技术债务。说的是造成真正伤害的坚实技术债务。