代码之家  ›  专栏  ›  技术社区  ›  David Johnstone

什么是重构,什么只是修改代码?

  •  65
  • David Johnstone  · 技术社区  · 16 年前

    我知道重构就是“改变程序的结构,使其功能不变”。我和一些大学最后一年项目的同事谈过,我很惊讶他们有更多 膨胀的 (为了更好的表达)重构的观点。

    我认为重构就是提取方法和重命名类。他们还建议改变数据结构(比如Java)。 LinkedList ArrayList ,更改算法(使用合并排序而不是冒泡排序),甚至重写大块代码作为重构。

    我很确定他们是错的,但我不能给出一个很好的理由来解释为什么,因为他们的建议确实在不改变程序行为的情况下改变了程序(并且可能使程序变得更好)。我说得对吗?更重要的是,为什么?

    10 回复  |  直到 6 年前
        1
  •  62
  •   Mitch Wheat    6 年前

    Martin Fowler "Refactoring: Improving the Design of Existing Code" 可能是参考:

    重构是一种受控技术 用于改进 现有代码库。其本质是 应用一系列小的 行为保持转换, 每一个都“太小了,不值得 “做”。但是累积效应 每一个转换都是 相当重要。把它们放进去 小步骤可以降低 引入错误。你也避免 当你在的时候系统坏了 进行重组-其中 允许您逐步重构 系统超过 时间。

    重构与单元测试密切相关。在重构之前编写测试,然后在重构中拥有一个置信级别(与测试的覆盖率成比例)。

    一个好的参考是: Information about Refactoring

        2
  •  27
  •   Carl Manaster    16 年前

    Fowler在对代码所做的更改和对代码所做的更改之间画了一条清晰的线来影响代码的行为。他把那些不需要的称为“重构”。这个 一个重要的区别是,如果我们将工作划分为重构和非重构代码修改活动(Fowler称之为“戴着不同的帽子”),我们可以应用不同的、目标适当的技术。

    如果我们正在进行重构或行为保留代码修改:

    • 我们所有的单元测试都应该在 修改后
    • 我们不需要修改任何 测试,或编写任何新的测试
    • 我们希望有更干净的代码 完成
    • 我们不期望有新的行为

    如果要修改行为更改代码:

    • 我们期待新的行为
    • 我们应该写新的测试
    • 完成后,我们可能会得到更脏的代码(然后应该重构它)

    如果我们忽视了这一区别,那么我们对任何给定的代码修改任务的期望都是混乱和复杂的,或者至少比我们注意到的更混乱和复杂。这就是为什么这个词及其含义很重要。

        3
  •  17
  •   peterchen    16 年前

    要给出我的观点:

    小的增量更改,使代码处于比发现的更好的状态

    肯定是的: 与功能不直接相关的“外观”更改(即,不作为更改请求计费)。

    绝对没有: 重写大块显然违反了“小的,增量的”部分。重构通常被用作 相反的 重写:不要再做,而是改进现有的。

    当然可能: 替换数据结构和算法有点像一个边界案例。在这里,IMO的决定性区别在于:准备好交付,准备好处理另一个案件。


    例子: 假设您有一个报告随机化模块,由于它使用了一个向量而减慢了速度。您已经分析过向量插入是瓶颈,但不幸的是,模块在许多地方依赖于不规则的内存,所以当使用列表时,事情会安静地中断。

    重写意味着将一个模块从零开始丢弃一个更好更快的模块,只需从旧模块中挑选一些片段。或者编写一个新的核心,然后将其安装到现有的对话框中。

    重构将意味着采取小步骤删除指针算术,以便切换。也许您甚至创建了一个实用函数来包装指针算法,用对该函数的调用替换直接的指针操作,然后切换到迭代器,这样编译器就会抱怨指针算法仍在使用的地方, 然后 切换到 list ,然后移除Ultility函数。


    背后的想法是代码本身会变得更糟。在修复错误和添加功能时,质量会以很小的步骤下降——变量的含义会发生细微的变化,函数会得到一个额外的参数来破坏隔离,循环会变得有点复杂等等。这些都不是真正的错误,您不能告诉行数使循环变得复杂,但会损害可读性和维护。

    同样,更改变量名或提取函数本身并没有明显的改进。但是,它们一起对抗缓慢的侵蚀。

    就像一堵鹅卵石墙,每天都有人掉在地上。每天,一个路人把它捡起来放回去。

        4
  •  11
  •   Jonik    16 年前

    考虑到马丁·福勒的定义,

    重构是一种训练有素的技术 重组现有机构 代码,改变其内部结构 不会改变它的外部行为。

    …我认为你是对的。

    他们还建议 改变数据结构(如Java) LinkedList到ArrayList),更改 算法(使用合并排序代替 甚至重写 作为重构的大块代码。

    将一个算法改得更快显然不是重构,因为外部行为已经改变了!(同样,如果效果从来没有被注意到,也许你可以称之为重构——以及过早的优化。-)

    这是我的一个小毛病;当人们使用“草率”这个词时,这很烦人——我甚至遇到过一些可能会随意使用的人。 重构 基本上是任何形式的改变或修复。是的,这是一个时髦而酷的流行词,但简单的老术语没什么错,比如 改变 , 重写 绩效改进 . 我们应该在适当的时候使用它们,并保留 重构 如果您真正只是在改进软件的内部结构。在开发团队中,尤其是在 准确地 讨论你的工作很重要。

        5
  •  8
  •   cbp    16 年前

    我认为你是对的,但是争论一个词的意思并不是特别有趣或有效。

        6
  •  8
  •   DanSingerman    16 年前

    如果一段代码的接口发生了变化,那么我认为这不仅仅是重构。

    重构的典型情况是

    • “噢,我所有的单元测试都在运行,但我认为我的代码可以变得更干净。”
    • 将代码更改为更可读/更清晰/更高效
    • 重新运行单元测试(不更改测试)并检查它们是否仍然工作

    这意味着术语重构与您正在讨论的接口相关。也就是说,您可以重构一个接口后面的代码,同时更广泛地在较低的级别上更改另一个接口的代码(也许这一区别是您和您的同事在这里混淆的原因?)

        7
  •  4
  •   superlogical    16 年前

    http://en.wikipedia.org/wiki/Code_refactoring

    代码重构是 改变计算机的过程 程序的内部结构没有 修改其外部功能 行为或现有功能,在 改善内部秩序 的非功能属性 软件,例如改进代码 可读性,简化代码 结构,更改代码以遵守 给定的编程范例,to 提高可维护性 性能,或改进 可扩展性。

    我同意重构代码包括破坏现有代码。只要确保你有单元测试,这样你就不会引入任何错误,其余的代码就会编译。使用重构工具,如resharper for c使这变得如此简单!

    • 使代码更易于理解
    • 清理代码并使其更整洁
    • 删除代码!应删除多余的、未使用的代码和注释。
    • 提高性能
    • 使一些更通用的东西。从最简单的事情开始,然后重构它,使其更容易测试/隔离或通用,这样它就可以通过多态性以不同的方式工作。
    • 保持代码干燥-不要重复,因此重构会话可能涉及到将一些重复的代码重构为单个组件/类/模块。
        8
  •  2
  •   l0b0    16 年前

    disagree :

    在软件工程中,“重构” 源代码意味着不需要 更改其总体结果[…]

    您已经知道了用于重构子集的更精确的术语,是的,这是一个非常通用的术语。

        9
  •  1
  •   Boris Pavlović    16 年前

    我认为没有人能从“重构”这个词的定义中获益。你如何看待它和你的同事之间的界限是模糊的,并且可以根据许多事实更接近他们或你的观点。因为它是动态的,所以我们试着定义它。首先,定义要重构的系统或子系统的边界。

    如果它是一个方法,请保持名称、输入参数、返回值的类型以及可能的抛出语句不变。应用方法内部的所有更改,而不更改方法外部的查看方式。

    如果您重构一个类,修复它的公共API,并使用重命名变量、提取方法和所有其他可用的技术,将类更改为更可读和/或更具性能。

    如果要重构的代码部分是一个包或模块,则在其中进行重构,可能会重命名类、删除、引入接口、将代码推/拉入超/子类。

        10
  •  -1
  •   Robert Fijałkowski    8 年前

    如果你想阅读一些提示,为什么重构很重要,为什么你总是不满意你的旧工作,我可以推荐新的博客文章。它将回答一些关于重构的问题,如何说服您的老板它是重要的,等等。

    http://www.schibsted.pl/blog/back-end/refactoring 艾尔/