处理别人的代码[关闭]


60

我几乎没有一年的编码经验。开始工作后,大多数时候我都会处理别人的代码,或者在现有功能上添加新功能,或者修改现有功能。编写实际代码的人在我公司不再工作。我很难理解他的代码并完成任务。每当我尝试修改代码时,我都会以某种方式弄乱正常工作的功能。在处理别人的代码时,我应该牢记什么?


103
欢迎来到代码永远存在的现实世界,程序员来来往往。

65
这不是别人的代码。现在是您的代码。
2012年

6
@gnat再次说明,这只能归因于OP的经验不足和缺乏知识。如果我进入同事的职务,删除了一行基本代码,将所说的代码投入使用并破坏了代码,那是我的疏忽,而不是结构上不合理的代码
rickyduck 2012年

19
@Buhb:但是,从现在起6个月,当你回来吧,这将是别人的代码,即使你写的部分;-)
约尔格W¯¯米塔格

6
要开心。您正在开发一项关键技能,可以使您与经验不足或仅具有学术经验的人区分开。它应该很难。这就是为什么它很有价值。
Scott C Wilson

Answers:


59

代码中是否包含单元测试?如果没有,我强烈建议您开始添加它们。这样,您可以将新功能/错误修复编写为失败的测试,然后修改测试通过的代码。您构建的代码越多,您对所添加的代码不会破坏其他内容的信心就越大。

为您不完全理解的代码编写单元测试将有助于您理解所说的代码。当然,如果尚不存在功能测试,则应添加它们。我的印象是,OP问题已经存在这些问题。如果我在这一点上错了,那么这些功能测试应该是您的第一步。

Eagle76dk使一个伟大的一点关于让你的经理在船上做这项工作-更多细节Eagle76dk的职位。

另外,在编写这些测试时,我鼓励您尝试编写测试,以便它们验证该方法可能试图完成的业务行为,而不是代码行为。另外,请不要完全假设您在代码中看到的业务行为是正确的-如果有人可以告诉您应用程序应该做什么,那么在许多情况下,这些行为比代码可以告诉您的价值更大。


12
根据代码及其依赖性,编写单元测试说起来容易做起来
难。– Svish

1
@Svish:好点。我从未暗示过这样做很容易,即使需要进行一些重构以使代码更适合于单元测试也值得这样做。
Sardathrion 2012年

46
如果代码不是为此设计的,则在现有代码上编写单元测试是一项非常具有挑战性和耗时的工作。对于初学者来说,使用您不理解的代码来完成它可能是一项非常艰巨的工作,将永远不会结束。这将是开始学习代码的一种方式,但是我不会说这是开始学习代码的明显方式。
jake_hetfield'5

3
单元测试最好在开发期间编写。如果您必须修复错误而又不了解设计或没有规范,则倾向于添加批准现有错误的单元测试。有时错误是错误的功能。因此,在这种情况下,我建议首先建立功能测试而不是单元测试。这意味着使用示例来生成用户认可的结果。通过彻底写下这些情况,动作和结果来制作测试用例。如果您的功能测试涵盖了所有用户案例并且在补丁发布后可以正常工作,那么无需进行单元测试就可以了。
阿尔夫,2012年

2
编写单元测试是自下而上的方法,将花费大量时间,因此在大型项目中通常不实用。在这种情况下,重新编写整个内容可能会更快。您可能会发现(然后需要时间修复)单元错误,这些错误并不重要,因为这种情况永远不会在功能上下文中发生。
阿尔夫,2012年

46

除了提到单元测试的另一个答案之外,我建议您确保所有内容都在版本控制中,以便能够轻松还原所做的更改。并进行少量更改以使代码更易于维护。


11
的确不错,但是我有点假设现在有人可以使用(阅读:应该使用)版本控制...
Sardathrion 2012年

6
您会感到惊讶。我曾在许多公司中担任承包商,这些公司只提交了最终代码。老实说
5arx

4
5arx指出:如果公司文化只是提交完美的代码,则可以维护自己的个人Git或Mercurial存储库。如果公司的“真实”版本控制是SVN,则这特别容易。
达斯汀·拉森纳

2
+1和+1到5arx的评论。我已经在真正的大型公司中完成了集成工作,这些公司的版本控制系统包括在文件中写上日期,您的姓名和注释。与git一起使用后,这似乎效率低下且容易出错。
Leo

1
@Sardathrion你知道当你“对我说”时会发生什么...
WernerCD

32

我认为,学习别人代码的最快方法(尤其是当更改触发您所描述的异常行为时)是使用调试器逐步遍历代码

首先逐步完成程序的主要循环/主要方法。使用单步执行和单步执行功能可以查看不同方法的作用。这将教您代码的一般结构。

之后,逐步学习并深入了解程序的不同部分,从而分而治之。在大多数调试器中,您可以研究变量及其当前值。研究它们如何改变以及何时改变。

在触发与您有关的行为的方法上设置断点。例如,如果您尝试更改程序中的文本,并且文本不断更改回原始值,请在更改文本的所有位置上设置断点,或尝试将所有这些更改移动到一个方法中。使用调用堆栈查看从何处调用此方法,等等。

如果更改一行代码导致其他地方发生意外更改,请在该行上放置一个断点,然后查看发生的情况,例如,通过检查作用域中当前变量的值,使用step into或调用堆栈来查看从何处来电来了。

通过大量这样做,您将开始以惊人的速度学习代码的结构。我就像您刚开始从事编程工作时一样,一开始就是用很多代码编写的,这些代码是很多年前编写的,并且许多人多年来一直在修改它们。该代码不是我的代码,因为那里有其他人同时在工作。那时候我无法全部重写。为所有这些代码编写测试将花费我几个月甚至几年的时间。调试器真的救了我,不知道如果没有它我将如何学习代码...


3
我认为这是唯一现实的答案,为一个大型应用编写单元测试,而没有它们的不实用性
CommonSenseCode

希望我能投票一次以上。
user949300

30

首先要记住的是,与编写代码相比,阅读代码花费的时间更多。花时间了解另一个人的工作方式-他的风格和解决问题的方法。

尝试尽可能采用现有样式-否则您之后的那个家伙将有两倍的调整要做。

与他人的代码打交道是常态,并非例外,您需要精通弄清楚另一个人如何解决问题或实现功能。完成此操作后,您将发现更轻松地处理他的代码。


21

不要太快假设其他人的代码很臭。

但请始终保持可疑。

但是,是的,了解其他开发人员的代码需要花费时间。系统的多个部分使用的功能或对象越多,则需要格外小心。如果您可以更接近症状地解决问题,那有时会有所帮助。例如,在数据交付后但在其他任何事情发生之前,对来自围栏问题对象一侧的另一个对象的传入数据进行规范化。

当更改一件事意外破坏另一件事时,这是一个不好的信号。如果您还有其他经验更丰富的开发人员,可以依靠您寻求帮助,我建议您让他们研究引起您问题的内容。至少您可能会看到一些调试它们的内容。


9
+1。抵制重新编写您不了解的块的诱惑-几乎可以肯定,您会引入新的错误。而是在代码中缓慢而有条理地移动,仅在实际需要新功能(或错误修复)的地方进行更改。
Scott C Wilson

1
我一年会错判多次。今天刚刚完成,意识到我认为有问题的5个项目中的每一个都是有原因的。他/他们本来可以给他们留下更清晰的标记,但是如果他/他们出于充分的理由没有去那里,我本可以浪费更少的时间。
Erik Reppen

14

在理想的情况下,将使用自动工具(例如单元测试)和用户运行的用例脚本来检查给定开发人员编写的所有代码,并对其进行全面的测试,以检查您是否获得了预期的结果。

但是,您首先要了解的是我们没有生活在理想的世界中!

许多开发人员没有正确记录其代码,或者根本没有将业务逻辑与不相关的代码混合在一起,而他们所做的唯一测试就是快速浏览他们期望的正常用例。

当使用这样的代码时,您要做的第一件事就是确定它的意图。如果有任何评论,他们可能会为您提供线索,但不要指望它。我的经验是,许多编码员都不善于自我解释,即使他们留下评论,也可能毫无意义。但是,除非您是公司中唯一的编码人员,否则肯定有人必须至少对代码的用途和用途有一个基本的了解。问问周围!

如果您有单元测试,那么它们将使您的生活变得轻松许多。如果您不这样做,那么学习代码库的一部分可能涉及为已经存在的代码编写单元测试。通常,这不是一个好习惯,因为如果您编写单元测试以适合现有代码,那么您最终将获得认为该代码按原样工作的单元测试(它们将被编写为假定实际上是一个错误的行为是是正确的),但至少它为您提供了基线。如果以后发现您认为正确的某些行为实际上是错误的,则可以更改单元测试以测试预期结果是什么,而不是代码现在给出的结果。进行单元测试后,您可以进行更改并评估所做的任何更改的副作用。

最后,在处理未记录的代码时,最好的资源是询问最终用户。他们可能对代码一无所知,但是他们知道他们想要应用程序做什么。需求收集是任何项目的第一步,与要开发的系统的潜在用户进行交谈始终是其中的重要部分。可以将其视为刚好已经完成的新项目的需求捕获阶段。

请记住,即使局外人也难以理解即使编写良好且文档齐全的代码。代码本质上是表达编写该代码的人当时的思维方式的表达,每个人都有自己独特的思维过程。您将必须学会变得耐心,成为一名侦探。能够进入他人的思维过程很困难,但这对于程序员进行现有代码维护是一项必不可少的技能。由于大多数编码(大约70%)与维护现有代码有关,因此这是学习的一项重要技能。

哦,既然您已经看到了文档编写不当,未经测试且混乱的代码可能造成的痛苦,那么您将不会再遇到下一个可怜的开发人员,对吧?:)从前任的错误中吸取教训,对代码进行很好的注释,确保每个模块都有明确定义的职责,并确保您拥有一套完整的单元测试,这些单元测试要么首先编写(针对TDD方法),要么编写至少与正在开发的代码一起。


13

请记住,读取尚未编写的代码的能力是一项非常有价值的技能,可能比编写代码更有价值。不幸的是,这在学校普遍被低估和教导。

我要说的是,在第一次阅读时并不总是理解代码是很正常的(就像第一次不编写完美的代码是正常的一样)。如果您接受获取外部代码需要花费时间,那么您不介意付出额外的努力。一个小总结:

  • 单元测试将是理想的,但并不总是现实的;尤其是当您在官僚机构繁重的大型组织中工作时。

  • 学习正确使用版本控制系统;您将永远不会破坏现有的(不是真的不会,但这是一个很好的安全网)。

  • 不要仅仅因为您不立即了解它就认为它很糟糕。不要仅仅因为它起作用就认为它很好。重要的是,您应该了解以前的维护者的代码风格,并使添加的行适应他的风格。维护人员会在您之后感谢您。

  • 不幸的是,在某些公司中,阅读代码的难度可能会被低估。这在具有严格流程的大型公司中很常见。他们经常(隐式地)喜欢您推送可快速工作的代码,而不是花时间来编写干净的东西。我将由您来决定您的团队在这一点上的立场。

  • 最后,永远不要忘记阅读代码是一种技巧。您做得越多,就会越好。另一种说法是,要善于练习,唯一的方法就是要练习多次。就像上面提到的,与编写相比,阅读代码现在是而且将在您的工作中占更大的比重。


11

从您无意间破坏东西的问题来看,我将假设该代码未包含在自动化测试中。步骤#0是立即订购并阅读Michael Feathers的《有效处理旧版代码》。这简直是​​无价之宝。

我建议的基本步骤:

  • 用涵盖当前功能的测试覆盖代码。
  • 重构直到可以理解。
  • 为新功能或修改的功能编写测试。
  • 实施新功能。
  • 重构直到满意。

我特意省略了指定测试风格的内容(单元,集成等),只是获得了某种自动化的测试范围。

(是的,在布局和命名方面遵循编码风格)


10

如前所述:欢迎来到现实世界。我只能同意较早的答案。我只希望通过我的时间估算工作经验来扩展答案。

一个很好的建议是使您的老板清楚,这将需要时间来学习其他开发人员的想法。通常,您会发现当前的解决方案通常取决于开发人员的年龄和经验。

如果幸运的话,必须分析当前的任务,了解文档将对您有很大帮助(但事实并非如此)。

我的经验是,在修改其他代码时,请尽量不要更改不涉及您当前任务的代码。您可能知道更好的解决方案,或者可以以更直观的方式编写它,但是更改它通常会导致诸如以下的问题:

  • 该任务将花费更长的时间,而您的老板也不会理解。
  • 您更改的代码必须经过测试,并且要花钱。当前的解决方案已经过测试和批准。
  • 很难看到哪些更改可以解决当前任务,哪些是“公正的”更正。

但是,请不要犹豫告诉老板,如果您发现自己认为应该有所不同的事物(只是表明您可以思考)。

最后,请确保您有足够的时间来制定解决方案。经验带来了更快的解决方案。但是很少有快速的解决方案,因为这是错误和代码无法维护的首要原因。


5

可以将其视为对一个人执行操作。

您在内部寻找需要修复的问题,并注意到大多数动脉等未按照您的设置方式进行布置-因此您将它们切开并砍成碎片,直到看起来对您来说再解决。

令人惊讶的是,您的患者几乎立即死亡。

旧版应用程序是相同的。他们已经有了一种工作方式-您需要了解软件中的各个组件以及它们之间的相互关系,然后进行更改,使其工作方式相同。让您的创造力疯狂起来并不令人兴奋,但是您可以在个人项目上做到这一点。

我会请一个高级工程师在每个星期一和您一起坐一个小时左右,并解释系统的另一个方面。记下他说的话,然后将其通过电子邮件发送给他和您的经理,以查看您的经理是否有任何要补充的内容。您应该以这种方式快速起步。

至于如何不破坏事物,首先要确保您了解系统的功能。先测试-进行更改-之后再测试。没有神奇的公式。随着经验的积累,您会变得更好-否则就会被炒鱿鱼!


3

我没有真正看到的一件事触及到这里- 不要在岛上工作。

除非您是唯一的程序员,否则肯定会有一些人的经验超过您,并且很可能有很多人可以依靠。

问问题。其中很多。

不必担心(在合理范围内)“烦恼”别人-我宁愿有人在正常的开发周期中因一两个问题而打扰我,而不必稍后在生产环境中开火。

当您准备好办理登机手续时,请与导师一起检查。他们不仅应该告诉您某些东西是否会破坏其他东西,而且更重要的是,为什么。审查代码还将使指导者成为更好的程序员,使他/她对系统的看法是,他们可能不会经常查看。

记住-您不仅在学习新员工需要做的系统,而且还在学习如何成为一名程序员。

五年后,鼓励下一个新家伙来使用您作为导师。


2

在调试代码时,请记住:总是有原因的。当您试图寻找并修复同一愚蠢的错误几天而又没有取得任何进展时,便很容易开始考虑以下一项或多项:

  • 我只是不够聪明,无法弄清楚这段代码是如何工作的

  • 编写此代码的人不知道他在做什么

  • 涉及魔术:非常黑的魔术

这些都是放弃的形式。解毒剂是要始终记住,计算机是确定性的:总是有其做事的理由。该代码在鱼罐头厂闻起来像潮水似的,就像一大碗扁面条,但是通过坚持不懈的理性和开放的心态,您会发现它


1

无论是在可能的情况下编写单元测试,还是编写涉及要修改的代码的小型应用程序,您都必须查看,理解并记录逻辑。

如果代码大部分都起作用(听起来像是一样),那么我将保留该模块的代码格式设置样式,无论您使用的是不是这种样式。它使事情保持一致。但是,好的评论永远不会过时。

我建议使用一个测试系统和测试平台,您可以在其中修改和测试此代码,而不会中断生产。

如果可以将代码的元素删除到库中,除非您正在使用库,否则我会这样做。

随着时间的流逝,一旦您了解了逻辑,就可以重写和测试。

该建议取决于您使用的语言,获得测试平台的能力以及您所遇到的其他限制。


“好的注释永远不会过时”……除非代码更改。尽管注释有时可能会有所帮助,但请务必对它们加一点盐-您必须验证代码是否确实按照注释的说明进行操作。通常,有人会更改一行代码,但留下现有的(现在不相关的)注释。
2012年

1
@ dj18同意,清理旧注释是编写代码的一部分。我的意思是保持格式(如果可能)以保持一致,但是发表评论不是一件坏事。
octopusgrabbus 2012年

1

尝试使用一些代码分析器工具来查找可以删除的未使用的代码-因此至少您不必担心此代码。


1

上面已经指出,您需要了解系统的目的,而不仅仅是代码的细节。具有足够的经验来编写订单输入系统的程序员通常会喜欢“前进”部分,该部分涉及选择产品,格式化发票和处理付款。当用户决定“不介意”并开始撤消交易时,或者当他们在付款处理中出错并点击“后退”按钮时,它们就会卡住。到那时,许多程序员感到困惑,因为他们看到代码“无处不在”,并且不知道为什么存在。

简而言之,您不仅需要了解“正常流程”,还必须了解如果有人犯了错误或改变了主意,则必须进行的所有回溯。对于主管覆盖,情况变得更糟,在某些情况下,某些代码只能使用某些帐户特权才能运行。

如果某人每年编写10,000行代码,而一个应用程序有十年的“生命”,那么负责接管他人工作的程序员可能必须理解100,000行代码。用每页50行除以2000页。如果将程序编写为一种设计模式,则程序员将发现对一个“块”的理解至少可以对其余大部分进行一般性的理解。如果不是,那么有必要阅读每条该死的行。

一些程序员“只是按照他们的要求去做”并写意粉。他们从不理解“大局”-当用户抱怨时,他们只是简单地进行修复。在这种情况下,最好将所有可能的方法迁移到适当的模式。最终,这可能意味着重新编码未损坏的内容。不用担心,只要确保它是您的项目,它就可以逐步维护。


0

这里有一些非常好的答案。但是我认为值得一提的是,熟悉良好的设计模式可以帮助您阅读(编写良好的)现有代码并编写可读的代码。

当然,当您SomethingFactory在现有代码中遇到实际上并不遵循工厂模式的代码时,可能会非常混乱。但是,在您的团队和框架允许的范围内,将此类案件的发生率降至最低可能是有益的。

遵循设计模式(在业务需求允许的情况下)还可以大大减少代码重复,从而减少以后修改的错误。

有关设计模式的一些很好的资料是

http://sourcemaking.com/design_patterns

http://www.oodesign.com/

当然还有书

http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612


0

跟踪方法之间的控制流对于开发业务逻辑思维图非常重要。

我们的解决方案基于以下认识:运行遗留系统时,为数不多的几条值得信赖的信息之一就是运行系统本身。我们的方法改进了执行轨迹,并使用逻辑编程对它们进行测试。

生成工作流数据模型是分析所有代码路径的最佳方法:

在实践中,代码审查在传统的科学工作流程中变得笨拙。这种工作流程的起源意味着在开发过程中可能尚未应用软件工程实践,从而导致代码库被有效地混淆了。尽管静态分析具有完善的数据流分析技术,但它们无法支持现实工作流中的行为。例如,何时必须加载配置文件以确定应如何处理数据,或何时使用动态代码评估。

可视化工作流程是理想的:

有助于视觉开发的常见主题是将工作流程表示为图形。这使用户免受资源和执行的潜在复杂性影响

参考文献


-1

确保您使用的程序可以帮助您在当前文件中查找内容。没有比知道您要查找的内容在当前文件中更糟糕的了,但是您不断滚动并找不到它。您用来编辑代码的工具中的大纲视图确实有助于解决该问题。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.