代码之家  ›  专栏  ›  技术社区  ›  Xzhsh

处理代码维护的建议[关闭]

  •  19
  • Xzhsh  · 技术社区  · 16 年前

    今年夏天我在我的大学里的一个图像/视频实验室工作。就在最近,我的教授给了我一个由一个研究生写的程序,他刚离开这个程序去“修复”,因为这是“犯了一些错误”。

    该项目是用C++编写的(在学生代码中似乎是一个反复出现的坏信号)。我在VS08中打开了这个项目,运行了这个项目,结果发现“错误”是一个糟糕的分配。当然,内存管理,或者更准确地说,缺少它是问题所在。

    程序员似乎喜欢在整个代码中混合mallocs、new s和new[]s,而绝对没有free、delete或delete[]。更糟糕的是,所有的对象似乎都至少做了4-5件不相关的事情。最重要的是,程序员留下了一条评论:

    //do not delete objects, it seems to cause bugs in the segmenter
    

    从我所看到的,指针和引用的引用有一个很好的不健康的混合,所有值都是通过引用传递给可能是静态的单块类函数而改变的。在编译时,大约有23个警告——比如从双到字符转换时可能丢失的数据,大约17个未使用的变量等等。现在是这样的,我希望C++永远不存在于大学中,而且所有的实验室工作都是在Python或Matlab中完成的。

    所以现在,教授要我“摆弄”这个程序,这样它就可以在比以前大10倍的数据集上运行。我承认,我有点害怕告诉她密码是垃圾。

    Stackoverflow,你们以前从来没有失败过,给过好的建议,所以现在我请求,任何关于处理这种情况的建议都会非常感谢。

    编辑 代码大约是5000个loc

    编辑2 教授决定采用最简单的方法。有更多的内存。是的,因为你要花钱解决这个问题…

    14 回复  |  直到 8 年前
        1
  •  23
  •   wadesworld    16 年前

    首先,坏代码就是坏代码。Python、Java、Matlab或任何其他垃圾收集都不等于好代码。您也可以很容易地花时间调试不好的python代码。

    这么说的话,绝对要提前告诉教授。告诉她代码不好,给她举几个例子。你能做的最糟糕的事就是设法掩盖这个问题。如果你这样做,问题不仅肯定会落在你的大腿上,而且肯定会归咎于你。

    找出最佳解决方案并向她提出。它可能是修复代码,征集计算机科学部门的帮助,或者改写它,无论是C++还是其他语言。很有可能她没有其他选择,会很乐意接受你提出的任何解决方案。

        2
  •  15
  •   zwol    16 年前

    重构代码,每次更改一次,直到它对您有意义为止。最重要的不是精确的编码策略,而是 了解它在做什么和为什么。

    你可能会碰到每一行代码,所以不要试图以任何特定的顺序做事情-先解决第一个跳到你面前的错误,然后继续下一个错误,依此类推。例外:如果前一个人没有使用一致的代码格式化策略,那么作为第一个操作,通过autoindenter运行整个过程。

    随时随地编写测试套件。

        3
  •  10
  •   sbi    16 年前

    老实说。 立刻告诉你的教授 密码是废话,为什么呢?如果你在问题中列出的是真的,那么代码就是垃圾。

    你手头有多少时间?您了解已实现的算法吗?
    5kloc并不是那么多,尤其是当它都是低级的摆弄。当你知道底层的算法并且有足够的时间在手边的时候, 重写 它有2行易于理解的代码 也许更好 而不是试图修复它。

        4
  •  7
  •   Steve S    16 年前

    5000个位置还不错。算你自己幸运。

    因为听起来内存管理是最大的问题之一,所以我将从这里开始。

    1. 更换每次使用的 malloc 具有 new .
    2. 修复编译器警告。
    3. 用向量(或更合适的数据结构)替换数组。
    4. 尽可能将原始指针替换为堆栈变量/引用,否则替换为智能指针。不要担心主要的体系结构更改或100%的转换——关注低挂起的成果并清除一些主要的内存泄漏。
    5. 开始重新构造应用程序。
      1. 在应用程序中选择离散的行为/任务。
      2. 大致弄清楚 工作。
      3. 弄清楚你是怎么做到的 希望 它可以工作(集中在界面上)。
      4. 制定过渡计划。
      5. 执行你的计划。
      6. 重复。
        5
  •  6
  •   Community Mohan Dere    9 年前

    我建议遵循MichaelFeathers在他的“有效地使用遗留代码”一书中所描述的一些步骤。即:尽快进行代码测试。

    使用运行功能的单元测试将为您提供一些可以自由重构的东西,而无需担心。

    不过,我知道说这个比实际做起来容易得多。阅读本章关于接缝的内容(您可以覆盖/钩住代码的一部分,以便更轻松地获取测试中的代码): http://www.informit.com/articles/article.aspx?p=359417&seqNum=3 也可以看到CppUnit和CPUMPITLITE,一个C++中的单元测试框架: http://c2.com/cgi/wiki?CppUnitLite

    通过内存分析器运行代码。查看此SO链接: https://stackoverflow.com/questions/818673/memory-profiler-for-c 这将帮助您跟踪需要开始放置delete/free语句的位置。 我还将开始尝试使内存分配至少在它使用的API中保持一致。

        6
  •  3
  •   Dr. Snoopy    16 年前

    在我看来,你能做的最好的事情就是告诉教授代码是一团糟的,除非某些部分被重写,否则不会按预期工作。建议一个小代码重构,只重写需要它的部分(而不是整个程序)。

    不说这些,会给你带来比你现在更多的问题:)

        7
  •  1
  •   Timo Geusch    16 年前

    作为一个止点,您可以尝试使用类似dlmalloc的垃圾收集内存管理实现,以查看这是否允许您暂时跨越内存不足的障碍。

    从长远来看,您将不得不解决内存管理混乱的问题——根本没有办法解决这个问题。根据您的描述,您可能还必须解决对象设计问题,但您可能可以先做一些内存管理清理。

    以下是我的方法:

    • 在代码中查找调用的所有位置 malloc() . 好好看看他们,试着用电话代替他们 new 因此,您只需要处理单一类型的内存管理,这将使您更容易进入下一步。
    • 找到所有的地方 新的 调用并查看是否可以替换结果为 新的 分配给 boost::shared_ptr<> . 这至少会给您带来一些穷人的垃圾收集;当然,您还应该更改接收这些指针的函数的所有函数原型。 shared_ptr<> 而不是原始的指针,否则你只是打扮的一团糟,没有真正改善任何东西。事实上,我认为你改变的事情越来越糟…

    一旦解决了即时内存管理问题,就可以开始重构对象并改进设计。我不会首先修复设计,你最好让软件正常工作,对它的工作有更多的了解,然后整理出设计,否则你很可能会用另一个来替换一个烂摊子。

        8
  •  1
  •   Starkey    16 年前

    听起来真是一团糟。重构是您最不需要做的。新的和Malloc的混合是一个灾难的配方!

    我想你可能要重写整个过程。幸运的是5000个sloc不是 巨大的 不应该花太长时间。

    听起来是个不错的练习!

        9
  •  1
  •   NinjaCat    16 年前

    向教授解释你看到的问题。永远不要在没有解决方案的情况下提出问题。在写报告和建议时要记住这一点。你可以提供多种可能性,让他们选择他们想要的。在那一点上,你已经完成了你的工作——是他们完成任务的时候了!

        10
  •  1
  •   MickeyfAgain_BeforeExitOfSO    16 年前

    对于如何处理代码本身,已经给出了许多好的建议。在我看来,其中一个潜在的问题可能是(可以理解)这是由非程序员为非计算机类编写的。您可能会向您的教授建议,将来她可以让程序员流类中的某个人(与CS教授合作)在这些情况下执行实际的实现。

    当然,这对每个参与的人都有一个颠倒的一面。最终用户(您的教授)必须能够创建一个规范,或者至少清楚地表达她的需求。她可能需要确信,为了做到这一点,把时间从她宁愿做的事情中抽出是有价值的。实现团队必须能够按照该规范工作并与最终用户进行通信。如果代码实际上是一个团队而不是一个人,那么实现团队将确保代码写得相当好。

    这一切都是为“现实世界”做好的良好准备,也是跨学科合作的机会,与那些了解问题领域的人合作,与那些了解工具的人合作。

    它给学生们提供了一个“真实”的而不是一个做作的练习,并且应该给他们带来更多的热情。(当然,这取决于部门间的竞争和小众政治,它也可能是一个正在形成的笨蛋或一个不启动者,但嘿,我是一个乐观主义者…)

        11
  •  1
  •   Jay    16 年前

    向“是”教授隐瞒这个问题没有什么好处,抱怨你有一堆垃圾要处理,听起来像是在抱怨,但隐瞒事实并试图从侧面解决它会让你看起来像一个最慢的工人,最坏的情况是,无能。我认为首先要做的是礼貌地告诉教授这个程序有很多问题,需要清理并举例说明…教授对编程有什么了解吗?我不认为这是在问题中说的…但无论如何,要解释这个问题并说出你认为解决它需要什么。

    也就是说,我想到的下一个大问题是,糟糕的内存管理和糟糕的类型转换是唯一的大问题,还是这些只是你从一百个严重问题中选择的例子?也就是说,程序的基本结构和逻辑基本上是合理的,还是整个程序一团糟?(我想是一团糟,但显然我没看过节目。)

    这里要做的关键决定是,你(a)通过程序一次修复一系列的细节错误吗?(b)是否进行了认真的重组和清理?或者(c)扔掉它,从头重写。在这种情况下,我经常倾向于选择(C),因为看起来重写比清理混乱要简单得多,但现有代码中可能嵌入了许多详细的逻辑决策。除非你有详细的、最新的需求文档——这是一个不太可能的可能性,以至于我会在一想到这个问题就大笑起来的时候立刻忽略它——了解所有规则的唯一方法就是阅读现有的代码并找出它的目的。此时(a)或(b)比(c)更有效。

    希望我能说“只做X”,不幸的是,由于你能合理地把大量的信息放进一个帖子,我认为我们都只能说“这里有一些合理的选择要考虑…”

        12
  •  0
  •   Inverse    16 年前

    替换每一个:

    Type* data = (Type*)malloc(123*sizeof(Type));
    

    具有

    std::vector<Type> data(123);
    

    已删除所有内存管理!易如反掌。 然后按值传递向量。

        13
  •  0
  •   Vadim Kotov First Zero    8 年前

    维护要点:

    • SCM . 在Windows上,我建议您使用Mercurial( TortoiseHg client )创建中央祝福存储库,让其他人从中获得软件,并从开发人员专用存储库中提交修复程序。

    • 问题/错误跟踪。如果你还没有,就去拿吧。这应该是一个简单的销售给教授,不能给任何Windows的建议。朋友正在使用 Mantis .

    • 发布管理。通常是问题跟踪系统的一部分。但发布的过程本身更多的是组织和政治问题,而不是技术问题。本质上,它是关于为软件的某些内部版本提供公共名称。在现实生活中,当决定什么才是真正的释放时,它就变得高度政治化。

    5公里的地方不多。使用SCM有助于跟踪更改并在回归时返回。跟踪问题有助于团队在问题上进行协作。在修复问题(例如,malloc与new与memory leaks)时进行较小的释放。为更大的修复程序和功能(例如支持更大的数据集)制作主要版本。

    重要的是不要急于求成,从细微的变化开始。现代的SCM允许许多小的提交(使用问题依赖树跟踪DITTO问题),应该使用它。这样可以跟踪软件的行为是如何变化的,以及什么变化精确地引入了回归。这往往是最天真的变化。

        14
  •  -1
  •   moreram    16 年前

    这个问题可以通过增加RAM很容易解决。1-2GB就可以了。