【问题标题】:The best way to familiarize yourself with an inherited codebase熟悉继承代码库的最佳方式
【发布时间】:2008-10-18 05:05:39
【问题描述】:

堆垛机没有人询问most shocking thing new programmers find as they enter the field

列表中非常重要的是继承一个必须迅速熟悉的代码库的影响。突然发现自己负责维护 N 行代码,这些代码已经被拼凑了多久,并且有很短的时间开始为它做出贡献,这可能会非常令人震惊。

您如何有效地吸收所有这些新数据?是什么缓解了这种转变?唯一真正的解决方案是已经为足够多的开源项目做出了贡献,从而消除了冲击?

这也适用于资深程序员。您使用什么技术来简化向新代码库的过渡?

我为此添加了 Community-Building 标签,因为我还想听听一些关于这些过渡的战争故事。欢迎分享您如何应对压力特别大的学习曲线。

【问题讨论】:

    标签: language-agnostic legacy-code


    【解决方案1】:

    铅笔和笔记本(不要分心试图创建一个未经请求的解决方案)

    • 边做边做笔记,每周一花一个小时通读并整理前几周的笔记

    • 对于大型代码库,第一印象可能具有欺骗性,当您熟悉自己时,问题往往会迅速重新排列。

    • 请记住,您上次工作环境中的问题在您的新环境中不一定有效或密切相关。谨防先入为主的观念。

    • 您所做的笔记/观察将帮助您快速了解要问什么问题以及问谁。 希望您一直在收集所有官方(和非官方)利益相关者的姓名。

    【讨论】:

      【解决方案2】:

      熟悉继承代码的最佳方法之一是亲自动手。从修复一些简单的错误开始,然后逐步解决更复杂的错误。与尝试系统地审查代码相比,这会让您更好地熟悉代码。

      如果有需求或功能规范文档(希望是最新的),您必须阅读它。

      如果有高级或详细的设计文档(希望是最新的),您可能应该阅读它。

      另一个好方法是与熟悉代码的人安排一次“信息传递”会议,他们提供高级设计的演示文稿,并对代码的重要/棘手部分进行演练代码。

      【讨论】:

        【解决方案3】:

        编写单元测试。您会更快地发现缺陷,并且在需要更改代码时更有信心。

        【讨论】:

          【解决方案4】:

          尝试理解代码背后的业务逻辑。一旦你知道为什么要编写代码以及它应该做什么,你就可以开始阅读它,或者像有人说的那样,到处修复一些错误

          【讨论】:

            【解决方案5】:

            我的步骤是:

            1.) 在代码库中设置包含所有源代码、头文件的源代码洞察(或您使用的任何好的源代码浏览器)工作区/项目。从最高功能(主要)到最低功能在更高级别浏览。在此代码浏览期间,请继续在纸/或 Word 文档上做笔记,以跟踪函数调用的流程。在这一步中不要进入函数实现的细节,保留它以供以后的迭代。在这一步中,跟踪传递给函数的参数、返回值、传递给函数的参数是如何初始化的、这些参数集的值是如何修改的、返回值是如何使用的?

            2.) 在步骤 1.) 的一次迭代之后,您在代码库中使用了某种级别的代码和数据结构,根据代码库的编程语言设置 MSVC(或任何其他相关的编译器项目) ),编译代码,使用有效的测试用例执行,然后从 main 再次单步执行代码,直到函数的最后一级。在函数调用之间不断移动传递、返回的变量的值、采用的各种代码路径、避免的各种代码路径等。

            3.) 不断重复 1.) 和 2.) 直到您适应了可以更改一些代码/添加一些代码/在现有代码中查找错误/修复错误的程度!

            -AD

            【讨论】:

              【解决方案6】:

              我不知道这是“最好的方法”,但我最近的工作是编写一个代码蜘蛛/解析器(在 Ruby 中),它通过并构建了一个调用树(以及一个反向调用树),我以后可以查询。这有点不重要,因为我们有 PHP,它调用 Perl,它调用 SQL 函数/过程。任何其他代码抓取工具都会以类似的方式提供帮助(即 javadoc、rdoc、perldoc、Doxygen 等)。

              阅读任何单元测试或规范都会很有启发性。

              记录事情会有所帮助(无论是对自己,还是对其他队友,现在和未来)。阅读任何现有文档。

              当然,不要低估简单地向队友(或你的老板!)提问的力量。早些时候,我经常根据需要询问“我们是否有执行 X 的函数/脚本/foo?”

              【讨论】:

                【解决方案7】:

                浏览核心库并阅读函数声明。如果它是 C/C++,这意味着只有标题。记录你不明白的任何东西。

                我上次这样做时,我插入的一个 cmets 是“从未使用过此类”。

                【讨论】:

                • 我曾经继承了一个代码库,在我第一次尝试调试应用程序时,调试器进入了一个注释为“不再使用”的函数:-)
                【解决方案8】:

                请尝试通过修复代码中的错误来理解代码。纠正或维护文档。不要修改代码本身的 cmets,这有可能引入新的 bug。

                在我们的工作中,一般来说,我们不会无故更改生产代码。这包括外观变化;即使这些也会引入错误。

                无论一段代码看起来多么令人作呕,除非您有错误修复或其他更改要做,否则不要试图重写它。如果您在阅读代码时发现错误(或可能的错误)以尝试了解它,请记录该错误以供以后分类,但不要尝试修复它。

                【讨论】:

                  【解决方案9】:

                  另一个过程...

                  在阅读了 Andy Hunt 的 “Pragmatic Thinking and Learning - Refactor Your Wetware”(没有直接解决这个问题)后,我总结了一些可能值得一提的技巧:

                  观察行为:

                  如果有 UI,那就更好了。使用该应用程序并获得关系的心理地图(例如链接、模式等)。如果有帮助,请查看 HTTP 请求,但不要过分强调它——您只需要轻松、友好地了解应用即可。

                  确认文件夹结构:

                  再一次,这很轻。只要看看什么属于哪里,并希望结构足够语义——你总是可以从这里得到一些顶级信息。

                  自上而下分析调用堆栈:

                  在纸上或其他媒介上浏览并列出清单,但尽量不要打字——这会让你大脑的不同部分参与进来(如果必须的话,可以用乐高积木搭建)——函数调用、对象和最接近顶层的变量。看看常量和模块,如果可以的话,请确保不要深入研究细粒度的功能。

                  思维导图!

                  也许是最重要的一步。为您当前对代码的理解创建一个非常粗略的映射。确保快速浏览思维导图。这可以让你大脑的不同部分(主要是 R 模式)均匀分布,从而在地图上发表意见。

                  1. 创建云、盒子等。最初认为它们应该出现在纸上。随意用句法符号表示框(例如,'F'-Function、'f'-closure、'C'-Constant、'V'-Global Var、'v'-low-level var 等)。使用箭头:传入数组作为参数,传出作为返回,或者对你来说更自然的东西。
                  2. 开始绘制连接以表示关系。如果它看起来很乱也没关系 - 这是初稿。
                  3. 进行快速粗略修改。它太难阅读了,做另一个快速组织,但不要做多个修订。

                  打开调试器:

                  1. 验证或使映射后的任何概念无效。跟踪变量、参数、返回等。
                  2. 跟踪 HTTP 请求等以了解数据的来源。查看标头本身,但不要深入了解请求正文的详细信息。

                  再次使用思维导图!

                  现在您应该对大多数顶级功能有了一个不错的了解。

                  1. 创建一个 MindMap,其中包含您在第一个中遗漏的任何内容。您可以花更多时间处理这个问题,甚至添加一些相对小细节——但不要害怕它们可能与之前的概念相冲突。
                  2. 将此地图与您上一张地图进行比较,消除您之前提出的任何问题,记下新问题,并记下相互矛盾的观点。
                  3. 如果地图太模糊,请修改此地图。尽可能多地修改,但尽量减少修改。

                  假装它不是代码:

                  如果你可以用机械术语来表达,那就去做吧。其中最重要的部分是为应用程序的行为和/或代码的较小部分提出隐喻。认真想想荒谬的事情。如果是动物,怪物,星星,机器人。会是什么样的。如果是在星际迷航中,他们会用它做什么。考虑很多事情来衡量它。

                  综合大于分析:

                  现在你想看的不是“什么”,而是“如何”。任何通过你循环的低级部件都可以取出并放入无菌环境(你控制它的输入)。你得到什么样的输出。系统是否比您最初想象的更复杂?更简单?需要改进吗?

                  贡献点东西,伙计!

                  编写测试、修复错误、评论、抽象。你应该有足够的能力开始做一些小的贡献并且失败是可以的:)!请注意您在提交、聊天、电子邮件中所做的任何更改。如果你做了一些卑鄙的事情,你们可以在它投入生产之前发现它 - 如果有什么问题,这是让队友为你解决问题的好方法。通常听队友的谈话会让你的思维导图发生冲突的事情变得清晰。

                  简而言之,最重要的事情是使用自上而下的方式让大脑的尽可能多的不同部分参与进来。如果可能的话,它甚至可以帮助关闭您的笔记本电脑并将您的座位面向窗外。研究表明,执行截止日期会在截止日期后约 2.5 天产生“压力宿醉”,这就是为什么截止日期通常最好在星期五进行。所以,放轻松,没有时间紧迫,现在为自己提供一个可以安全失败的环境。在您深入了解细节之前,大部分内容都可以相当匆忙地完成。确保您不会绕过对高级主题的理解。

                  希望这对你也有帮助:)

                  【讨论】:

                    【解决方案10】:

                    所有非常好的答案都在这里。只是想添加更多内容:

                    人们可以将架构理解与闪存卡结合起来,重新访问这些卡片可以巩固理解。我发现诸如“代码的哪一部分具有 X 功能?”之类的问题,其中 X 在您的代码库中可能是一个有用的功能。

                    我也喜欢在 emacs 中打开一个缓冲区并开始重写我想熟悉的代码库的一些部分并添加我自己的 cmets 等。

                    【讨论】:

                      【解决方案11】:

                      vi 和 emacs 用户可以做的一件事就是使用标签。标签包含在一个文件中(通常称为 TAGS )。您可以通过命令生成一个或多个标签文件( etags 用于 emacs vtags 用于 vi )。然后我们编辑源代码,你会看到一个令人困惑的函数或变量,你加载标签文件,它将带你到声明函数的位置(不够完美)。我实际上已经编写了一些宏,可以让您使用 Alt 光标导航源代码, 有点像许多 UNIX 风格中的 popd 和 pushd。

                      巴巴特

                      【讨论】:

                        【解决方案12】:

                        在开始编写代码之前,我要做的第一件事是使用应用程序(如有必要,作为几个不同的用户)了解所有功能并查看它们如何连接(信息如何在应用程序内流动)。

                        之后,我检查了构建应用程序的框架,以便我可以在我刚刚看到的所有界面与一些视图或 UI 代码之间建立直接关系。

                        然后我查看数据库和任何数据库命令处理层(如果适用),以了解这些信息(用户操作的)是如何存储的,以及它是如何进出应用程序的

                        最后,在了解了数据的来源和显示方式之后,我查看了业务逻辑层以了解数据是如何转换的。

                        我相信每个应用程序架构都可以像这样划分,并且在真正调试它或添加新东西之前了解整体功能(你的应用程序中的谁是谁)可能是有益的 - 也就是说,如果你有足够的时间这样做.

                        是的,与开发当前版本软件的人交谈也很有帮助。但是,如果他/她即将离开公司,请在他/她的愿望清单上记下(他们想为该项目做什么,但由于预算限制而无法做到)。

                        【讨论】:

                          【解决方案13】:

                          为您从代码库中发现的每一件事创建文档。 通过实验找出它是如何工作的——在这里和那里改变几行,看看会发生什么。 使用 geany,因为它可以加快程序中常用变量和函数的搜索速度,并将其添加到自动完成中。 了解您是否可以通过 facebook 或通过谷歌搜索联系代码库的原始开发人员。 找出代码的原始用途,看看代码是否仍然适合该用途,或者是否应该从头开始重写,以实现预期用途。

                          找出代码使用了哪些框架,他们使用了哪些编辑器来生成代码。

                          推断代码如何工作的最简单方法是实际复制某个部分将由您完成的方式,并重新检查代码是否存在这样的部分。

                          这是逆向工程 - 通过尝试重新设计解决方案来解决问题。

                          大多数计算机程序员都有编码经验,如果代码中存在某些模式,您可以查找这些模式。

                          有两种类型的代码,面向对象的和面向结构的。

                          如果您两者都知道,那么您就可以开始了,但如果您不熟悉其中之一,您就必须重新学习如何以这种方式编程,才能理解为什么要这样编码方式。

                          在面向对象的代码中,您可以轻松地创建图表来记录每个对象类的行为和方法。

                          如果它是面向结构的(按功能表示),请创建一个功能列表,记录每个功能的作用以及它在代码中的位置。

                          上述任何一项我自己都没有做过,因为我是一名网络开发人员,从 index.php 开始到其他页面的其余部分,相对容易弄清楚某些东西是如何工作的。

                          祝你好运。

                          【讨论】:

                            猜你喜欢
                            • 1970-01-01
                            • 2010-09-17
                            • 1970-01-01
                            • 2011-05-11
                            • 2010-09-16
                            • 1970-01-01
                            • 2012-04-24
                            • 2011-05-19
                            • 2016-09-22
                            相关资源
                            最近更新 更多