您使用什么工具和技术来探索和学习未知的代码库?
我在考虑诸如grep
,,ctags
单元测试,功能测试,类图生成器,调用图,代码度量之类的工具sloccount
,等等。我会对您的经验,您使用或编写的助手以及您使用的代码库的大小感兴趣。
我意识到熟悉代码库是一个随时间推移而发生的过程,熟悉度可以表示从“我能够总结代码”到“我可以将其重构并缩小到其大小的30%”之类的任何内容。但是,如何开始呢?
您使用什么工具和技术来探索和学习未知的代码库?
我在考虑诸如grep
,,ctags
单元测试,功能测试,类图生成器,调用图,代码度量之类的工具sloccount
,等等。我会对您的经验,您使用或编写的助手以及您使用的代码库的大小感兴趣。
我意识到熟悉代码库是一个随时间推移而发生的过程,熟悉度可以表示从“我能够总结代码”到“我可以将其重构并缩小到其大小的30%”之类的任何内容。但是,如何开始呢?
Answers:
我一直做的事情如下:
打开我的编辑器的多个副本(Visual Studio / Eclipse / Whatever),然后调试并执行换行以单步执行代码。找出代码流程,堆栈跟踪以查看关键点在哪里,然后从那里开始。
我可以逐个方法地查看方法-但是如果我可以单击某些内容,然后查看它在代码中的执行位置并进行后续操作,那就太好了。让我来感受一下开发人员如何使事情工作。
你怎么吃大象?
一次咬一口:)
认真地说,我尝试先与代码的作者交谈。
在完成工作之前,我是否需要hack一下
在很大程度上,是(抱歉)。
您可能会考虑的方法:
我要做的一些澄清代码的事情是:
...以及您可以进行的其他任何简单的改进。
逐渐地,这背后的含义应该变得更加清晰。
至于开始的地方?从您所知道的开始。我建议输入和输出。您通常可以弄清楚这些应该是什么以及它们的用途。通过应用程序跟踪数据,并查看数据去向和更改方式。
我所有这些问题中的一个是动力-它可能是一个真正的障碍。它帮助我将整个业务视为一个难题,并庆祝我正在取得的进步,无论规模如何。
您的情况实际上很普遍。任何不得不从事可以处理现有代码的新工作的人都将处理其中的某些元素。如果该系统确实是一个令人讨厌的旧系统,则非常类似于您所描述的。当然,目前没有任何文档。
首先,许多人推荐Michael Feathers 撰写的《有效使用旧版代码》。这确实是一本不错的书,其中包含有用的章节,例如“我无法将此类纳入测试工具”或“我的应用程序没有结构”,尽管有时Feathers只能提供比解决方案更多的同情。特别是,这本书及其示例主要针对花括号语言。如果您正在使用粗糙的SQL过程,则可能没有那么有用。我认为“我对这个代码的理解不充分,无法更改它”一章谈到了您的问题。Feathers在这里提到了一些明显的事情,例如做笔记和标记清单,但也很重要的一点是,如果您具有源代码管理,则可以删除未使用的代码。许多人将代码的注释部分留在原地,
接下来,我认为您建议的方法无疑是一个好步骤。您必须首先全面了解代码的用途。
如果您需要回答问题,一定要与导师或团队中的某人合作。
另外,如果发现了缺陷,请抓住机会支持代码(尽管有时您不必为此自愿……缺陷将找到您!)。用户可以解释他们使用软件的目的以及缺陷如何影响他们。当试图理解软件的含义时,这通常可能是非常有用的知识。此外,以有针对性的攻击目标进入代码有时可以帮助您在面对“野兽”时集中精力。
当我有一个非常大的源文件时,我喜欢执行以下操作:
当您回到普通编辑器时,您会对代码看起来多么陌生而感到惊讶。
尝试理解旧版代码库时不要太着急,尤其是当它使用的是您不熟悉的技术/语言/框架时。这只是一个不可避免的学习过程,需要一些时间。
一种方法是在相关技术的代码和教程之间来回切换。您阅读/观看了该教程,然后查看代码以了解您的前辈是如何做到的,请注意任何异同,做笔记并向任何现有开发人员提问。
“为什么你要这样做?”
“我注意到大多数在线人都是这样做的,你们都是这样做的。为什么呢?”
“是什么让你们所有人选择技术X而不选择技术Y?”
这些问题的答案将帮助您了解项目的历史以及设计和实施决策背后的原因。
最终,您将对它足够熟悉,可以开始添加/修复问题。如果这一切看起来令人困惑,或者似乎发生了太多的“魔术”,则您还没有花费足够的时间查看,消化和绘制图表。创建图表(顺序图,过程流程图等)是您了解复杂过程的好方法,此外,它们还将帮助“下一个家伙”。
要做的重要一件事是使用工具生成依赖关系图,以自上而下地探索代码架构。首先可视化.NET程序集或jar之间的图形,这将使您对功能和层的组织方式有所了解,然后深入研究名称空间的依赖关系(在一个或几个相对的.NET程序集或jar中),从而获得更细粒度的代码概念结构,最后您可以查看类的依赖关系,以了解一组类如何协作以实现功能。有几种工具可以生成依赖关系图,例如,用于生成.NET的NDepend(例如)。
这是我的简短列表:
如果可能,请某人对代码进行高级介绍。考虑了什么模式,我希望看到什么样的约定,等等。这可能会有一些回合,就像一开始我会得到一个故事:随着我对代码的更加熟悉,我可能会有新的问题在我研究现有项目的过程中问。
运行代码,看看系统是什么样的。当然,它可能包含多个错误,但这对于了解其功能很有用。这与更改代码无关,而只是查看其运行方式。各个部分如何组合在一起构成一个整体系统?
寻找基础文档的测试和其他指标,这些指标可能有助于构建代码的内部思维模型。除非很少的文档和测试,否则我可能至少建议几天。
我对本项目中使用的语言和框架的了解程度如何?这里的重要性是区别看待事物和“是的,以前看过十几遍并且相当了解”和“这里尝试了什么?谁认为这是个好主意?”之间的区别。这类问题,虽然我不会大声说出来,但我会特别思考,如果我正在查看可能非常脆弱的旧代码,并且编写该代码的人要么不可用,要么不记得为什么事情按原样完成。对于新领域,可能值得花一些额外的时间来了解什么是结构以及在此代码中可以找到哪些模式。
最后但并非最不重要的一点是:考虑到以下几个可能的预期想法,就应该在每个时间点执行项目的人员的期望:
我总是尝试从程序的入口开始,因为所有程序都有一个(例如main方法,main类,init等)。然后,这将为我指出开始的地方,有时是如何链接的。
之后,我进行深入研究。数据库和DAO在某处配置,因此我对事物的存储方式有所了解。也许还启动了某种全局实例类,在那里我可以弄清楚存储了什么。借助出色的折光工具,我可以找出谁叫什么。
然后,我尝试查找该接口的配置和处理位置,因为这是信息的下一个入口点。折射,搜索和调试工具可帮助我进行搜索。然后,我可以找出所有类文件中信息处理的起点和终点。
然后,我尝试将流程记录在纸上,只是为了一开始就把我的头缠在东西上。提交按钮传递到通用验证,然后传递到DAO或数据库,然后存储在数据库中。这是大多数应用程序的过度简化,但这是总的想法。笔和纸在这里非常有帮助,因为您可以快速记下所有内容,而不必担心格式化程序本该对您有所帮助。
我做了很多
这是我目前针对“某些事情正在工作”的情况的当前方法,您需要使其“以其他方式工作”。
在每个步骤之间可能还需要执行另一种可选的操作:f经理(项目所有者)告诉您“这些更改应该已经在昨天完成”。在完成几个项目之后,他甚至可以开始帮助提前获取规格和文档。
但是通常(尤其是脚本)在业务范围内是不可能的(成本太高,而价值却很低)。一种选择是不进行任何更改,直到达到临界质量并且系统停止生产(例如将要使用新系统)或管理层认为所有这些都值得做。
PS:我记得一个代码用于5个具有不同设置的客户端。而且,每项更改(新功能)都需要考虑“使用了哪些部件”和“配置客户端具有的配置”,以免制止任何事情,也不复制粘贴代码。将他们的设置放到项目CVS中并编写规范,可以将这种思考时间几乎减少到0。
如果代码库很大,则将注意力集中在当前正在处理的部分上。否则,您会感到不知所措,并且可能会爆炸。我认为一些高级概述会有所帮助(如果可用),但是您可能会在调试器中花费大量时间来遵循以下程序流程。概述应用程序并查看其使用是一个好主意,因此您可以了解代码的使用方式/用途/原因。
我通常在代码上运行某种代码复杂性工具,以告诉我问题区域在哪里。得分高的区域可能很难更新。例如,我遇到了一个在圈尺度上得分为450的函数。果然有数百个IF。很难维护或更改它。所以要做好最坏的准备。
另外,不要害怕向现有的开发人员提出问题,特别是如果他们在系统上工作。保持内心的想法,专注于解决问题。避免发表可能会使其他开发人员感到沮丧的评论。毕竟,这可能是您的孩子,没有人喜欢被告知他们的孩子丑陋。
采取小步骤,即使最小的代码更改也会产生很大的影响。
我发现提出程序代码流是有帮助的,因此,如果我进行更改,则可以进行依赖项搜索以查看哪些方法/函数调用了什么。假设我要更改方法C。
如果只有一个方法/函数调用C,那么这是一个相当安全的更改。如果数百个方法/函数调用C,那么它将产生更大的影响。
希望您的代码库具有良好的架构,编写和维护。如果是这样,将需要一些时间来理解它,但最终将扭转潮流。
如果它是一个大泥球,您可能永远不会理解(或想了解)其内部运作方式。
我做的一些事
1)使用诸如Source Monitor之类的源分析工具来确定各种模块大小,复杂性度量标准等,以使您对项目有所了解并帮助确定不重要的领域。
2)在Eclipse中从上至下钻取代码(拥有一个可以浏览引用等的编辑器是一件好事),直到我知道代码库中发生了什么以及代码在哪里。
3)有时,我会在Visio中绘制图表以更好地了解体系结构。这对项目中的其他人也可能有帮助。
我建议您在更改任何内容之前编写单元测试。并且一次只更改足够的代码以使测试通过。重构时,请事先添加单元测试,以便您知道重构并没有破坏业务功能。
对编程是一种选择吗?让另一个人反弹想法是一个应对如此讨厌的好主意。
我认为最重要的事情之一就是采用一个简单的功能,选择您能想到的最简单的功能,然后实施它。如果有一个已维护的愿望清单,请使用该清单,否则请与熟悉代码库的人交谈,并请他们提出功能建议。通常我希望这是5〜20 LOC的变化。重要的一点不是您要添加一个非常精美的功能,而是要使用代码库(或努力解决:))并遍历整个工作流程。你将不得不
清单继续进行,但要指出的是,像这样的小型项目将带您浏览检查清单上的所有项目,以熟悉系统,还可以进行富有成效的更改。
没有任何文档,或者文档很少,或者已经过时。查找确实存在的所有文档。如果在团队存储库中,请不要进行复制。如果不是,请将其放在此处,并可能需要在某些监督下,征求您的经理的许可才能组织它。
将所有内容收集到团队的资料库中,然后添加词汇表。所有基地都有行话;将其记录在词汇表中。制作工具,产品,特定于客户的部分等。
创建/更新软件环境创建文档。所有工具,古怪之处,安装选项等均在此处。
然后上传“ ProductName”入门文档等。让它随时间流逝并随着时间自我组织。然后查看过时的文档,并使其恢复最新状态。其他开发人员将不胜感激,您将在学习代码的同时以独特的方式做出贡献。尤其要记录所有使您难堪或被错误命名或违反直觉的事物。
一旦您的倾斜曲线即将结束,就不必担心更新文档。让下一个新家伙来做。当他到达时,将他指向您的工作。当他不断困扰您寻找答案时,请不要回答他。而是将问题添加到您的文档中,然后将其交给他。钓鱼竿。
副作用是您将制作一个自己可以在几个月后忘记的情况下引用的工具。
尽管它不是文档,但相关的问题是团队伙伴所做的所有古怪的,人工密集的过程。使用批处理,sql脚本等自动化它们,并共享它们。毕竟,就在新环境中产生生产力而言,过程知识可以说与声明性知识一样大。不管是什么,都不要这样做。而是编写脚本,然后运行脚本。钓鱼竿再次触击。