代码之家  ›  专栏  ›  技术社区  ›  Chris Bunch

如何处理坏代码[关闭]

  •  42
  • Chris Bunch  · 技术社区  · 7 年前

    作为一名开发人员,我在一整天的生活中遇到的最不愉快(而且非常频繁)的情况之一是,我必须修复错误或将特性添加到设计糟糕的代码中。现在作为一个好的工匠,我想让代码处于比我发现的更好的状态。通常,如果不重构设计,就无法实现新功能。嗯-他们可以,但那会使代码更糟。

    不幸的是,这正是我所面临的困难。我觉得如果有一件事很难做到,那就是重构坏代码,特别是当你有最后期限的时候。接触或多或少起作用的坏的和复杂的代码是可怕的。因此,当我在不修改现有代码的情况下,将新特性侵入代码时,会引入更多的混乱。

    现在我的问题是 我如何才能学会处理坏代码?我如何才能学会理解巨大的代码库,然后在不破坏已经工作的东西和不超过期限的情况下重构其中的一部分呢?你能推荐什么文献吗?你有什么给我的一般提示吗?

    9 回复  |  直到 13 年前
        1
  •  21
  •   Oded    16 年前

    迈克尔·费瑟写了一本关于这个问题的好书。

    Working Effectively with Legacy Code .

    另一本好书是马丁·福勒、肯特·贝克和其他人写的:

    Refactoring: Improving the Design of Existing Code .

        2
  •  24
  •   alemjerus    16 年前

    一般提示:

    if (it is working)
       Do (not touch it);
    else
    {
       Make (as few modifications as possible)
       Or (it will stop working at all);
    }
    

    这是世世代代的经验。

        3
  •  9
  •   Daniel Elliott    16 年前

    重构需要一个单元测试套件的安全工具来移除“我已经破坏它了吗?”感觉。在一系列测试中覆盖坏代码将有助于您争取好的干净代码。

    Pex 是一个工具,我发现它对于为遗留代码创建测试很有用(如果您在.NET世界中)。

    旧代码==没有测试的代码!

    仁慈,

        4
  •  7
  •   LukáÅ¡ Lalinský    16 年前

    当我必须处理向坏代码添加功能时,我通常的方法是:

    • 为必须工作的每个重要特性编写自动测试(因为大多数坏代码没有任何测试)。
    • 进行代码更改。
    • 确保测试仍然有效。

    这至少给了你一些信心,你没有破坏一切。至于如何学习如何应对坏代码,我想这只是经验的问题。

        5
  •  4
  •   Oxymoron    16 年前

    好吧,如果您要在项目中重构大量的代码,我建议您使用一些合适的版本控制,这样您就可以轻松地进行分支和回滚。考虑到,这可能是一扇敞开的门,但在我看来至关重要。

    此外,在开始进入复杂的OO之前,尝试将方法和函数分解为较小的方法和函数。在每个函数中确保一定程度的原子性,这使得代码更容易维护、读取和管理。 所有这些都是关于小东西的,把它分解成逻辑操作单元,我在一个1K行方法上做一个重构操作。它做各种花哨的事情。 我的第一个目标是把尽可能多的东西分成小块,完成后,我会开始考虑一个更好的OO设计,这更容易,因为我对事物有更好的掌握。

    阿司匹林也很有效。

        6
  •  3
  •   kow    13 年前

    我现在处于这种情况。我的方法是在接触代码之前回答一些问题:

    1. 是代码吗? 真正地 那么糟糕?如果是,常见的错误是什么?==>也许先集中精力
    2. 代码中的主要运行时流是什么?也许您可以放弃它的许多构造。
    3. 尝试在不更改代码的情况下对代码进行分层/模块化。这会导致一些相互依赖性的减少。
    4. 尝试用测试插入代码。如果代码库陷入了希望之外:使用 PowerMock 模拟尚不需要更改的对象
    5. 有一个可用的集成环境,您可以在该环境中测试生产环境附近的更改。
    6. 不要羞于重写部分代码库。但是尽量不要在其中实现太多的新东西
    7. 尝试团队合作,讨论设计、原则、解决方案

    这是一项艰巨的工作,没有人会为此感谢你。为小的改进感到骄傲,并享受完成的好工作:)

        7
  •  1
  •   Muhammad Farhan    16 年前

    我认为,对您正在开发/改进的软件中的所有工作原理有一个大致的了解总是很好的。这就是设计文档和其他在开发过程之后或过程中生成的文档出现的地方。我相信,如果您之前的某个人没有完成适当的文档,那么至少您应该在某个地方写几行关于您在整个开发过程中所经历的事情。我通常使用OneNote或其他东西来记录我遇到的情况,并经常列出我认为需要重构的内容。如果在项目期间有一些停机时间,我通常会回到那个列表,并尝试一点一点地改进事情。

    所以,基本上,如果你之前的某个人做得不好,至少你可以帮助任何其他开发人员减少遇到相同代码的问题,这是件好事。

        9
  •  0
  •   NawaMan    16 年前

    这取决于因素的数量,但最重要的是你是否有权修改它。

    如果需要,请重构它。例如,重命名类/函数/变量。提取和概括功能。请参见重构: Improving the Design of Existing Code (主题为《圣经》)。 在开始执行此操作之前,请确保代码位于正确的版本控制(VC)中,并且具有一组良好的测试用例。VC允许您回滚,测试用例有助于捕获意外的副作用。

    我建议使用像mercurial/bazaar和git这样的分布式版本控制,因为它的重构结构与添加特性不同。

    如果没有测试(公共),则必须创建它们。读 Working Effectively With Legacy Code . 尤其是关于“密封点”(不是关于暹罗猫:p)。

    如果您没有创建更干净的包装API。

    例如:

    
    Old code ====================
    const ACT_SHOW = 'show';
    const ACT_HIDE = 'hide';
    function int DoThing(Object $Obj, Stirng $Action, Object $Param1, Object $Param1) {
         ....;
    }
    Added code ==================
    enum Actions {
        show, hide;
    };
    class ActionDoer {
        private obj;
        ActionDoer($Object) {
            this.obj = $Object;
        }
        function int act(Actions $Action, $Param1, $Param1) {
            this.act($Action.toString(), $Param1, $Param1) ;
        }
        function int act(String $Action, $Param1, $Param1) {
            DoThing(this.obj, $Action, $Param1, $Param1) ;
        }
        function int show() {
            this.act(Actions.show, null, null);
        }
        function int hide(Color $ToBGColor, long $FadeTime) {
            this.act(Actions.hide, $ToBGColor, $FadeTime);
        }
    }
    

    这样,旧代码就不会被触动,扩展可以使用新代码来完成。这个方法的一个很好的例子是jquery,在这里访问DOM的旧(默认)方法很痛苦。

    希望这有帮助。