重构20K行库的技巧

jbl*_*lue 31 php oop refactoring open-source

我已经给马里奥的答案赢得了100分的奖励,但是如果我看到新的好答案,我可能会开始第二个100分的奖励.这就是为什么我要保持这个问题的开放并且不会选择最终的答案,尽管将奖金授予马里奥.

这可能看起来像一个简单的问题(研究代码和重构),但我希望那些有更多经验的人可以给我一些可靠的建议.

该库是一个开源的20,000行库,它们都在一个文件中,我自己也没有写过.代码看起来写得很糟糕,单个文件甚至是一个更大的问题,因为它至少每次我想要进行更改时都会冻结eclipse半分钟,这也是我认为重构这个库的重要原因之一小班.

因此,除了阅读代码并试图理解它之外,在重构像这样的库时,是否存在常见的(或不常见的)提示?你有什么建议让我的生活更轻松一点?

感谢大家的意见.

Bru*_*son 42

一些通用原则适用:

  1. 分而治之.将文件拆分为较小的逻辑库和功能分组.您将以这种方式了解有关库的更多信息,并使其更易于理解和逐步测试.

  2. 删除重复.查找重复的函数和概念,并将其替换为标准库函数或库中的集中函数.

  3. 添加一致性.平滑参数和命名.

  4. 添加单元测试.这是重构库的最重要部分.使用jUnit(或类似),并添加可用于验证函数是否正确以及它们是否未更改的测试.

  5. 添加文档.在编写测试时记录您对一致,改进的库的理解.

  • 好的原则.但从测试开始. (4认同)
  • 另外,别忘了,"别恐慌!" 很容易被一个巨大的,旧的,硬皮的图书馆吓倒. (4认同)
  • +1好答案.我实际上最近做了这个(在C++中).18k行源文件.从第1步开始,将其拆分为文件,为类提供自己的文件,并将相关的函数分组到自己的文件中.在此阶段拒绝更改代码的冲动.只是重新安排它. (2认同)

Ira*_*ter 28

如果代码编写得很糟糕,很可能它有很多克隆.找到并摆脱克隆可能会使其更易于维护以及减小其大小.

你可以找到各种克隆探测器,专门用于PHP:

在检测有趣克隆的质量不同的能力方面,排名最低的能力顺序(恕我直言,我个人对CloneDR的强烈兴趣).

如果代码写得不好,很多可能已经死了.值得找出哪个部分在实践中执行,哪个部分不执行.即使没有测试(您只需手动锻炼程序),测试覆盖工具也可以让您很好地了解此问题的答案.测试覆盖工具所执行的内容显然并没有消失.什么不执行...可能值得进一步调查,看看你是否可以删除它.如另一个答案所示,测试覆盖工具对于告诉您单元测试执行了多少代码也很有用.最后,测试覆盖率工具可以帮助您找到某些功能的位置:从外部运行功能,以及测试覆盖工具所执行的任何代码可能都是相关的.

我们的PHP测试覆盖率工具可以收集测试覆盖率数据.


mar*_*rio 10

如果它是一个开源库,请询问开发人员.首先,很可能某人已经(尝试过)重组后的版本.事实上,大量膨胀的东西实际上是从更模块化的版本自动生成的.

实际上我有时会为我的一个严格插入的应用程序执行此操作,并且允许简单cat */*.php > monolithic.php,这样可以简化分发和处理.所以问那可能是那种情况.

如果您真的想重组它,那么使用久经考验的增量扩展结构.library通过隔离原始类将类拆分为多个文件.每隔约2000行拆分,并命名第一部分library0.php:

 class library0 {
     var $var1,$var2,$var3,$var4;
     function method1();
     function method2();
     function method3();
     function method4();
     function method5();
Run Code Online (Sandbox Code Playgroud)

下一部分简单地从那里开始并保留接下来的几个方法:

 class library1 extends library0 {
     function method6();
     function method7();
     function method8();
     ...
Run Code Online (Sandbox Code Playgroud)

这样做直到你把它们全部分开.用真实姓名调用最后一个文件library.php,并且class library extends library52 {应该这样做.这是如此荒谬的简单化,正则表达式脚本应该能够做到这一点.

显然,这里没有节省内存.然后把它拆分就像在结构化方面没有任何收获.然而,有了20000行,很难在第一时间获得快速概览和有意义的分组.因此,从任意重组开始,代替一个明显的计划.但是从那里开始你可以很好地排序并将最不实用的代码放到最后一个文件中,并且只要它们足够就使用较轻的基类.但是,您需要一个依赖关系图来查看这是否可行,否则错误可能会在运行时爆炸.

(我没有尝试过像这样的大型项目这种方法.但是任意将某些东西分成三部分,然后为了感性而重新组合它确实有效.那次.)


Pek*_*ica 9

  • 我假设你打算将图书馆分成主题相关的课程.绝对考虑使用自动加载.这是自切片面包以来最好的事情,并使相互依赖性易于处理.

  • 从一开始就使用phpDoc兼容的注释记录代码.


ope*_*age 5

通过大量示例和详细信息回答您的问题的好书是:Michael Feathers有效地使用遗留代码.

  • 有效地使用Legacy Code实际上是由Michael Feathers编写的.... :-). (3认同)

die*_*dha 5

呼叫侧方法

如果您知道库的使用仅限于特定的类,模块或项目,则可以更容易地从调用端处理问题.然后,您可以执行以下操作来清理代码并重构代码.从呼叫方接近的一点是因为很少有人进入图书馆.调用越少(可能)在lib中实际使用的代码越少.

编写呼叫方测试

编写一个模拟对库完成的调用的测试.

埋葬死法典

如果有很多死代码,这将是一个巨大的胜利.跟踪对库的实际调用并删除其他所有内容.运行测试并验证.

重构是什么左翼

由于您有测试,因此重构(甚至替换)库中的代码应该更容易.然后,您可以应用标准重构规则,即.(重复数据删除,简化,合并等).


Gor*_*don 5

除了已经陈述的内容之外,我建议根据他的书来看看Martin Fowler的Refactorings目录.该页面还包含大量其他来源,可用于了解应如何处理重构.更详细的目录列表中,可以发现sourcemaking.请注意,并非所有这些技术和模式都可以应用于PHP代码.

还有很多有用的工具可以帮助您进行http://phpqatools.org的重构(一般情况下).使用这些来分析您的代码,以查找死代码或重复代码,高圈复杂度,经常执行的代码等等.这不仅可以让您更好地了解代码,还可以告诉您代码的哪些部分是关键的(最好在开头不要触及),哪些部分可能是重构的候选者.

无论你做什么,都要写单元测试.您必须确保在重构​​时不会破坏代码.如果库尚未经过单元测试,请在更改任何代码之前添加测试.如果您发现无法为要更改的部分代码编写测试,请检查在其他位置执行较小的重构是否可以让您更轻松地执行此操作.如果没有,请不要尝试重构.


dhi*_*esh 5

  1. 编写库的测试,以覆盖代码的所有行(即100%覆盖率).
  2. 使用 TDD.从更高级别的模块开始并重新考虑因素(从上到下).
  3. 运行步骤1中提到的测试并验证步骤2的结果.

据我所知,100%的覆盖率(如步骤1中所述)并不一定意味着所有功能都已被涵盖,至少我们确保无论当前系统的o/p与新的o/p相同系统.