多年来如何保持大型复杂软件产品的可维护性?


156

我已经从事软件开发工作多年了。我的经验是,随着越来越多的开发人员参与产品开发,项目变得更加复杂和难以维护。

似乎在开发的某个阶段,软件趋向于变得“骇客”和“骇客”,尤其是当没有一个定义架构的团队成员在公司工作时。

我感到沮丧的是,必须更改某些内容的开发人员很难了解架构的概况。因此,存在解决问题或以与原始体系结构相适应的方式进行更改的趋势。结果是代码变得越来越复杂,甚至变得难以理解。

关于如何保持源代码多年来的可维护性,是否有任何有用的建议?


9
强烈推荐的书籍:Steve McConnell撰写的“软件项目生存指南”,Steve McConnell撰写的“ Rapid Development”,Martin Fowler
撰写的

15
...以及Bob叔叔(Bob叔叔)的“清洁代码”;)(Robert C. Martin)
Gandalf 2012年

34
难道这不是几十年来在大学引起大量阅读和整个课程价值的问题吗?
2012年

17
@Eric Yin-我不同意这些评论。对我来说,它们是一种代码气味,从长期来看,项目往往弊大于利,因为它们不可避免地会过时并引起误解。
JohnFx 2012年

8
@Eric Yin:争取自记录代码。仅在意图理解能增进理解的地方使用它们。
米奇·麦特

Answers:


138

避免代码腐烂的唯一真正的解决方法就是编写好代码!

如何编写良好的代码是另一个问题。即使您是一个优秀的程序员,单独工作也很难。在一个异构团队中,这变得更加困难。在外包(子)项目中……祈祷吧。

通常的良好做法可能会有所帮助:

  1. 把事情简单化。
  2. 把事情简单化。这尤其适用于架构“大局”。如果开发者有时间难以得到大画面,他们要编写反对。因此,使体系结构简单,以便所有开发人员都能使用。如果架构必须不那么简单,那么必须培训开发人员以了解该架构。如果他们不对其进行内部化,则不应在其中进行编码。
  3. 旨在实现低耦合高凝聚力。确保团队中的每个人都理解这个想法。在一个由松散耦合的,有凝聚力的部分组成的项目中,如果某些部分变得难以维护,则只需拔下插头并重写该部分即可。如果联接紧密,则更难甚至几乎不可能。
  4. 始终如一。遵循哪些标准无关紧要,但是请遵循某些标准。在团队中,每个人当然都应遵循相同的标准。另一方面,很容易变得过于依附标准而忘记了其余部分:请务必理解,尽管标准很有用,但它们只是编写良好代码的一小部分。不要大量使用。
  5. 代码审查对于使团队保持一致的工作可能很有用。
  6. 确保所有工具(IDE,编译器,版本控制,构建系统,文档生成器,库,计算机椅子整体环境等)都得到良好维护,以使开发人员不必浪费时间在诸如此类的次要问题上由于战斗项目文件的版本冲突,Windows更新,噪音以及任何平庸但令人讨厌的内容。必须反复浪费大量时间来处理这些无趣的东西,这会降低士气,至少不会提高代码质量。在一个大型团队中,可能会有一个或多个人的主要工作是维护开发人员工具。
  7. 在做出技术决策时,请考虑如何切换技术;哪些决定是不可逆的,哪些不是。仔细评估不可逆转的决策。例如,如果您决定用Java编写项目,那是一个几乎不可逆的决定。如果您决定对数据文件使用某种自煮式二进制格式,那也是一个相当不可逆的决定(一旦代码变得狂热,您就必须继续支持该格式)。但是GUI的颜色可以轻松调整,以后可以添加最初遗漏的功能,因此减轻了此类问题的负担。

8
这些都是要点。我必须承认,我一直在为“保持简单”而努力。这似乎在不同的上下文中对不同的人意味着不同的事物,这使“简单”变得相当复杂(但是我确实有使事物复杂化的自然倾向)。
Kramii 2012年

3
我完全同意您的观点,尤其是“ KIS”。但是我看到一种趋势,越来越多的(年轻的)开发人员使用相当复杂的结构来描述最简单的上下文。
chrmue 2012年


8
嗯,然后说“ 8.保持简单”。
达伍德·伊本·卡里姆

7
#6值得+10。
Jim G.

55

单元测试是你的朋友。实施它们会降低耦合度。这也意味着可以很容易地识别和重构程序的“ hacky”部分。这也意味着可以快速测试所有更改,以确保它们不会破坏现有功能。这应该鼓励您的开发人员修改现有方法,而不是因为担心破坏代码而重复代码。

单元测试还可以作为代码的额外文档,概述了每个部分应该做什么。通过广泛的单元测试,程序员无需了解程序的整个体系结构即可进行更改并使用现有的类/方法。

作为一个好的副作用,单元测试也有望减少您的错误计数。


3
非常重要的一点。我接管了旧系统,许多类,许多行代码,没有文档,没有单元测试。在为所有代码修复和增强而努力地创建单元测试之后,系统设计已演变为更清洁,更可维护的状态。而且我们有“勇气”来重写重要的核心部分(由单元测试覆盖)。
山姆·戈德堡

40

这里的每个人都会很快提到code rot,我完全理解并同意这一点,但是它仍然怀念这里更大的图景和更大的问题。代码腐烂不只是发生。此外,还提到了单元测试,这很好,但是并不能真正解决问题。一个可以具有良好的单元测试覆盖范围和相对无错误的代码,但是仍然烂掉了代码和设计。

您提到开发人员在项目上的实现难以实现功能,并且错过了整个体系结构的整体图景,因此对系统进行了修改。负责实施和影响设计的技术领导者在哪里?此过程中的代码审查在哪里?

您实际上并没有遭受代码腐烂的困扰,但是却遭受了团队腐烂的困扰。事实是,软件的原始创建者不再在团队中也没关系。如果现有团队的技术主管完全,真正地理解底层设计,并且擅长担任技术主管,那么这将不是问题。


很好,您击中了靶心!说来可悲,但这正是这里发生了什么。没有技术领导者,似乎不可能改变一切……
chrmue 2012年

4
@chrmue我想事情发展的方向,但是我对此感到厌倦。从很多方面来说,当我不太了解周围的一切似乎有多么错误时,我希望自己能再次成为初级开发人员。看来我正处于职业中期危机的早期。但是我正在漫步...很高兴能提供帮助。
maple_shaft

1
@Murph为什么在维护阶段您不应该有一个全知的团队负责人?我曾经遇到过的每位老板都对团队领导的期望不低,而当我成为团队领导时,我对自己的期望也一样。
maple_shaft

1
@maple_shaft,因为a)我不认为有专门负责该项目的团队负责人,这或多或少是第一个要求,并且b)我认为您需要了解设计实现(所有这些),并且硬。一方面,我们所有人都争辩说,我们不应该在项目中使用所有知识的单一字体,但是在这里我们要说我们必须拥有一个字体?那不累加吗?
Murph 2012年

2
@maple_shaft可能让我成为一个脾气暴躁的老程序员(-:但是有一个问题,就是在现有代码库中经常需要遵循实现“样式”,这可能与编码器和领导者都不一样(很多现实世界中的原因)。
墨菲

18

我们可以做几件事:

让一个人全面负责建筑。选择该人员时,请确保他们具有开发和维护体系结构的远见和技能,并具有帮助其他开发人员遵循体系结构的影响力和权威。该人员应是经验丰富的开发人员,应得到管理层的信任,并应得到同行的尊重。

创建一种文化,所有开发人员都拥有该体系结构的所有权。所有开发人员都需要参与开发和维护体系结构完整性的过程。

开发易于传达架构决策的环境。鼓励人们谈论设计和架构-不仅在当前项目的背景下,而且在总体上也是如此。

最佳的编码实践使体系结构更容易从代码中看到-花费时间进行重构,注释代码,开发单元测试等。诸如命名约定和简洁的编码实践之类的东西可以在架构交流中起到很大的帮助,因此作为一个团队,您需要花一些时间来制定和遵循自己的标准。

确保所有必要的文档清晰,简洁,最新并且可访问。公开高层和低层架构图(将它们固定在墙上会有所帮助)并且可以公共维护。

最后(作为一个自然的完美主义者),我需要认识到架构完整性是一个值得追求的目标,但是可能还有更重要的事情-例如组建一个可以协同工作并实际交付有效产品的团队。


1
+1,特别是对于“组建一个可以一起工作并实际交付有效产品的团队”。
deworde 2012年

1
让一个人作为架构的根源是一个好主意。但是,如果经常使用该职责,则您会有“团队气味”:团队应该自然而然地达成共识,而不是依靠一个人来提供答案。为什么?该项目的全部知识总是共享的,将其钉在一个人身上最终会带来更大的问题:只有他的观点得到满足,才能有效地割裂团队其他成员的翅膀。而是雇用最优秀的人才,让他们一起努力。
卡斯珀2012年

1
@casper:是的。您表达的是我的想法,而不是我的想法。
Kramii 2012年

18

我处理此问题的方法是从根目录进行剪裁:

我的解释将使用Microsoft / .NET的术语,但将适用于任何平台/工具箱:

  1. 使用用于命名,编码,签入,错误流,过程流的标准-基本上是任何东西。
  2. 不要害怕与不遵守标准的团队成员道别。一些开发人员根本无法在一套既定的标准内工作,并且会成为战场上的第5列敌人,以保持代码库的清洁
  3. 不要害怕长时间分配技能低下的团队成员进行测试。
  4. 使用军械库中的所有工具来避免检入腐烂代码:这涉及专用工具以及用于测试构建文件,项目文件,目录结构等的预先编写的单元测试
  5. 在大约5至8名成员组成的团队中,请最好的人几乎不断地进行重构-清理其他人留下的混乱。即使您找到了该领域的最佳专家,您仍然会一团糟-这是不可避免的,但是它会受到不断重构的限制。
  6. 一定要编写单元测试并进行维护-不要依赖单元测试来保持项目的清洁,而不能。
  7. 讨论一切。不要害怕花几个小时来讨论团队中的事情。这将传播信息,并消除造成不良代码的根本原因之一:技术,目标,标准等方面的混乱。
  8. 顾问编写代码时要格外小心:几乎从定义上讲,他们的代码将是真正的卑鄙的东西。
  9. 最好在办理登机手续之前进行审核。不要害怕回滚提交。
  10. 除非在发布前的最后阶段,否则切勿使用开/关原理:这只会导致腐烂的代码闻起来很香。
  11. 每当遇到问题时,在实施解决方案之前都要花点时间充分理解它-大多数代码腐烂来自于对未完全理解的问题实施解决方案。
  12. 使用正确的技术。这些通常是成组出现的,而且是新鲜的:最好依靠将来可以确保获得支持的框架的beta版本,而不是依靠不受支持的极其稳定但过时的框架。
  13. 雇用最好的人。
  14. 解雇其余的人-您没有开咖啡馆。
  15. 如果管理人员不是最好的架构师,并且他们干扰了决策过程,请另谋高就。

1
现在,如果您必须在“业余时间”中进行C#重写时必须维护和增强具有100种形式和类的12年噩梦般的VB6应用程序,该怎么办?
jfrankcarr 2012年

7
与#3不同。测试不应被视为对未经培训的惩罚。实际上,它应该由所有开发人员完成,并且与编码和设计同样重要!如果您的团队中有未经培训的先生,那么请让他离开团队进行培训!。
NWS 2012年

1
“与#3不同。测试不应被视为对未经训练的人的惩罚。” -它不是我写的,也不是我写的。让我解释一下:测试是让您不知道的人信任所做的更改以进入代码的一种好方法。我发现最好的测试人员是那些渴望成为代码贡献者的人员,他们通过浏览代码,运行程序来证明自己的能力,并展示了将运行时的发现与源代码相关联的能力。这不是惩罚-它的训练。
卡斯珀2012年

1
“与#10不一致-如果正确完成,将有助于提高代码质量”在我的工作经验中,这绝对是错误的:无法重构锁定的代码,这意味着它将一直保持当前状态,直到被解锁为止。可以在某个阶段验证此状态是否正常,但是在以后的阶段,此验证是误报:应保留所有代码以进行重构,直到进行最终系统测试为止。
卡斯珀2012年

3
@casper:恕我直言,打开/关闭原则不应理解为“您无法更改源代码”,而应“设计代码使其变得冻结”。确保可以根据需要扩展代码,而不需要对其进行更改。其结果是,与普通代码相比,其耦合性和内聚性大大降低。当开发供第三方使用的库时,该原则也至关重要,因为第三方不能仅仅进入并修改您的代码,因此您需要适当地扩展它。
凯文·卡斯卡特

12

在编写单元测试时,通过重构清除烂掉的代码。只要您满足以下条件,就可以为您触摸的所有代码支付(此)设计债务:

  • 开发新功能
  • 解决问题

通过以下方法极大地加快了测试优先开发周期:

  • 重构以将代码模块转换为脚本语言
  • 使用基于云的快速测试机

通过以下方式重构代码以使用低耦合(具有高度内部凝聚力的单元):

  • 更简单(更多)的函数(例程)
  • 模组
  • 对象(以及类或原型)
  • 纯功能(无副作用)
  • 优先于继承而不是继承
  • 层(带有API)
  • 可以一起运行的小型单用途程序的集合

有机增长良好;大的前期设计是不好的。

拥有一个对当前设计知识丰富的领导者。如果没有,请阅读项目的代码,直到您有足够的知识。

阅读重构书籍。


1
+1好的第一个答案,是向我们介绍自己的完美方法!
尼斯

11

简单的答案:您不能

这就是为什么你的目标应该是写简单的软件。这并不容易。

仅当您对看似复杂的问题思考了足够长的时间,并以尽可能简单和简洁的方式对其进行定义时,才有可能。

真正大而复杂的问题的解决方案通常仍可以通过构建小而简单的模块来解决。

换句话说,正如其他人指出的那样,简单和松散耦合是关键因素。

如果这不可能或不可行,则您可能正在进行研究(没有已知的简单解决方案或根本没有已知解决方案的复杂问题)。不要指望研究会直接生产可维护的产品,这不是研究的目的。


9

我为自1999年以来就一直在持续开发的产品开发一个代码库,因此您可以想象到现在它已经相当复杂了。我们代码库中最大的黑手根源是无数次,我们不得不将其从ASP Classic移植到ASP.NET,从ADO 移植到ADO.NET,从回发到Ajax,切换UI库,编码标准等。

总而言之,我们已经做了合理的工作来保持代码库的可维护性。我们所做的主要贡献在于:

1)不断进行重构-如果您不得不修改一些难以理解或难以理解的代码,那么您将需要花费额外的时间来清理它,并在计划中留有余地。单元测试使这件事不那么令人恐惧,因为您可以更轻松地对回归进行测试。

2)保持整洁的开发环境-警惕删除不再使用的代码,并且不要在项目目录中保留备份副本/工作副本/实验代码。

3)在项目生命周期中使用一致的编码标准-让我们面对现实,我们对编码标准的看法随着时间的推移而发展。我建议您在项目的整个生命周期中都坚持使用您开始使用的编码标准,除非您有时间回过头来对所有代码进行改造以符合新标准。很高兴您现在掌握匈牙利表示法,但可以将这堂课应用到新项目中,而不仅仅是在新项目上切换中游。


8

由于您已使用项目管理标记了该问题,因此我尝试添加一些非代码点:)

  • 营业额计划-假设整个开发团队在维护阶段就已经消失了-没有值得花时间的开发人员想要永远维护他/她的系统。有空时就开始准备移交材料。

  • 一致性/统一性不够强调。这将阻止“独自行动”的文化,并鼓励新的开发人员提出疑问。

  • 保持其主流地位-使用的技术,设计模式和标准-因为团队的新开发人员(任何级别)都将有更多的机会快速启动并运行。

  • 文档-特别是体系结构-制定决策的原因以及编码标准。还要保留参考/注释/路线图以记录业务领域-您会惊讶于公司业务向没有领域经验的开发人员解释他们所做的工作有多么困难。

  • 清楚地制定规则-不仅要为您当前的开发团队服务,还要考虑将来的维护开发人员。如果这意味着在每个页面上都提供指向相关设计和编码标准文档的超链接,那就这样吧。

  • 确保体系结构(尤其是代码层)明确划分和分开-随着新技术的出现,这将有可能允许替换代码层,例如,用HTML5 jQuery UI等替换Web Forms UI ,这可能买一年左右的长寿。


7

高度可获取的代码的一个特性是函数纯度

纯度意味着函数对于相同的参数应返回相同的结果。也就是说,它们不应依赖于其他功能的副作用。此外,如果它们本身没有副作用,这将很有用。

该特性比耦合/内聚特性更容易看到。您不必全力以赴地实现它,我个人认为它更有价值。

当您的函数是纯函数时,其类型本身就是一个很好的文档。另外,就参数/返回值而言,编写和阅读文档要比提及某些全局状态(可能由其他线程O_O访问)要容易得多。

作为广泛使用纯度来帮助维护的示例,您可以看到GHC。这是一个大约有20年历史的大型项目,正在进行大型重构,并且仍在引入新的主要功能。

最后,我不太喜欢“保持简单”的观点。在对复杂事物进行建模时,您不能使程序保持简单。尝试制作一个简单的编译器,您生成的代码可能最终会变得很慢。当然,您可以(并且应该)使单个功能简单,但是结果整个程序将不简单。


2
您所描述的另一个名称是确定性的属性
jinglesthula 2014年

6

除了其他答案之外,我还建议您使用图层。不是太多,但足以分隔不同类型的代码。

对于大多数应用程序,我们使用内部API模型。有一个内部API连接到数据库。然后是一个UI层。不同的人可以在每个级别上工作,而不会破坏或破坏应用程序的其他部分。

另一种方法是让每个人都阅读comp.risksThe Daily WTF,以便他们了解不良设计和不良编程的后果,并且如果看到自己的代码发布在Daily WTF上,他们将感到恐惧。


6

由于许多答案似乎都集中在庞大的团队上,甚至从一开始就如此,因此,我将把自己的观点作为一个由两人组成的开发团队(如果包括设计师在内,则为三个)组成一家初创公司。

显然,简单的设计和解决方案是最好的选择,但是当您真正付钱付薪的人时,您不一定有时间考虑最优雅,简单和可维护的解决方案。考虑到这一点,我的第一个重点是:

文档不是注释,代码应该主要是自我记录,而是设计文档,类层次结构和依赖关系,体系结构范例等。任何有助于新手甚至现有程序员理解代码库的内容。另外,记录最终弹出的那些奇怪的伪库,例如“将此类添加到用于此功能的元素中”,可能会有所帮助,因为它还会阻止人们重写功能。

但是,即使您确实有严格的时间限制,我也要记住另一件好事:

避免黑客和快速修复。除非快速解决方案是实际解决方案,否则总要找出某个问题的根本问题,然后再进行解决。除非您确实有一个“在接下来的2分钟内解决该问题,否则您将被解雇”的方案,那么立即进行修复是一个更好的主意,因为您稍后将不修复代码,而只是移至下一个任务。

我个人最喜欢的提示更多是引用,尽管我不记得来源:

“代码仿佛跟在你后面的人是一个知道你住在哪里的杀人心理变态者”


我一直发现函数和类注释是有用的,即使只是通过使用语法突出显示来将函数和类位置的代码段分开也是如此。我很少在函数代码中添加注释,但是我为每个类和函数(例如/** Gets the available times of a clinic practitioner on a specific date. **/或)写一行/** Represents a clinic practitioner. **/
尼克·贝德福德

5

开放/封闭原则是我尚未提及的但我认为重要的原则

您不应该修改已经开发和测试的代码:任何此类代码都是密封的。相反,可以通过子类扩展现有的类,或者使用它们编写包装器,装饰器类或使用您认为合适的任何模式。但是不要更改工作代码

只是我的2美分。


如果工作代码中表达的业务需求发生变化怎么办?从长远来看,不要轻描淡写但技术上“有效”的代码可能会伤害您,特别是当需要进行必要的更改时。
jinglesthula 2014年

@jinglesthula:开放扩展意味着您可以将新功能添加为现有接口的新实现(例如,类)。当然,结构不良的代码不允许这样做:应该有一个类似于接口的抽象,允许通过添加新代码而不是修改现有代码来“更改”代码。
乔治,

5
  • 做个侦察兵。始终让代码清洁器保持原状。

  • 修复破损的窗户。当您使用3.0版时,所有这些注释都会“在2.0版中进行更改”。

  • 当存在重大黑客攻击时,请作为一个团队设计一个更好的解决方案,然后再做。如果您不能作为一个团队来修复黑客,那么您对系统的了解就不够。“请大人帮助。” 周围的最年长的人可能以前见过。尝试绘制或提取系统图。尝试以交互图的形式绘制或提取特别难用的用例。这不能解决问题,但至少您可以看到它。

  • 将设计推向特定方向的不再是什么假设呢?某些混乱背后可能隐藏着一个小的重构。

  • 如果您解释了系统的工作原理(甚至只是一个用例),并且发现自己不得不一遍又一遍地向子系统道歉,那就是问题所在。行为将使系统的其余部分变得更简单(无论实现起来看起来有多困难)。要重写的经典子系统是一种会以其操作语义和实现污染所有其他子系统的子系统。“哦,在将值输入到froo子系统之前,必须对这些值进行涂灰,然后在从froo获得输出时再次取消对它们的涂灰。也许在从用户和存储中读取所有值后,应该对它们进行涂灰,而系统的其余部分是错误的吗?当存在两个或多个不同的粉化时,这会变得更加令人兴奋。

  • 花一个星期的时间来团队消除警告,以便可以看到真正的问题。

  • 将所有代码重新格式化为编码标准。

  • 确保您的版本控制系统已绑定到错误跟踪器。这意味着将来的更改是不错且负责任的,您可以找出原因。

  • 做一些考古。查找原始设计文档并进行审查。它们可能位于办公室角落的那台旧PC上,废弃的办公空间或文件柜中,没人打开过。

  • 在Wiki上重新发布设计文档。这有助于使知识制度化。

  • 为发布和构建编写类似清单的过程。这使人们不必思考,因此他们可以专注于解决问题。尽可能自动构建。

  • 尝试持续集成。构建失败的时间越早,项目花费的时间就越少。

  • 如果您的团队负责人不做这些事情,那对公司不利。

  • 尝试确保所有新代码在覆盖范围内进行正确的单元测试。因此问题不会变得更糟。

  • 尝试对一些未经单元测试的旧位进行单元测试。这有助于减少对变更的恐惧。

  • 如果可以的话,使您的集成和回归测试自动化。至少有一个清单。飞行员很聪明,可以拿到很多薪水,他们使用清单。他们很少也搞砸。


4

阅读然后重新阅读史蒂夫·麦康奈尔的《代码完成》。从最初的项目设计到单行代码以及介于两者之间的所有内容,这就像是一本优秀的软件著作的圣经。我最喜欢它的是它得到了数十年可靠数据的支持;这不仅是次佳的编码风格。


3

我来称它为“温彻斯特神秘屋效应”。就像房子一样,它的开始非常简单,但是多年来,许多不同的工人在没有总体计划的情况下增加了如此多的奇特功能,以至于没人真正了解它。为什么这个楼梯无处可去,为什么那扇门只能以一种方式打开?谁知道?

限制这种影响的方法是从一个良好的设计开始,该设计要具有足够的灵活性以应对扩展。已经对此提出了一些建议。

但是,通常您会从事已经造成破坏的工作,而且对于一个好的设计而言,如果不执行昂贵且有潜在风险的重新设计和重写,为时已晚。在这种情况下,最好尝试找到方法来限制混乱,同时将其拥抱到一定程度。一切都必须经过巨大的,丑陋的,单例的“经理”类,或者数据访问层与UI紧密耦合,这可能会烦恼您的设计敏感性,但要学会处理它。在该框架内进行防御性代码编码,并尝试在程序员的“鬼魂”过去时出现意外情况。


2

代码重构单元测试非常好。但是,由于这个长期运行的项目正在遭受黑客攻击,因此这意味着管理层不会放下脚步清理腐败。该团队必须引入黑客手段,因为有人没有分配足够的资源来培训人员和分析问题/请求。

维护长期运行的项目与单独的开发人员一样,是项目经理的责任。

人们不会引入黑客,因为他们喜欢它。他们是受环境所迫。


迫于环境?人们之所以介绍骇客,是因为(a)他们不了解 =>需要辅导;(b)他们没有看到大局面 =>需要沟通,文档和纪律;(c)他们认为自己更聪明 =>那是最大的事情克服由环境造成的障碍(d) =>在有时间压力的情况下,可以快速修复此错误,但是必须有人负责并随后清理代码。任何其他“情况”就是BS。该经验法则有例外,但最常见的例外是“懒惰”。
JensG 2014年

2

我只想提出一个非技术性问题和(也许)务实的方法。

如果您的经理不关心技术质量(可管理的代码,简单的体系结构,可靠的基础结构等等),那么就很难改善项目。在这种情况下,有必要对上述经理进行培训,并说服他们“投入”精力进行可维护性和解决技术债务

如果您梦with以求这些书中的代码质量,那么您还需要一位对此感到担忧的老板。

或者,如果您只是想驯服“ Frankenstein项目”,这些是我的提示:

  • 组织和简化
  • 缩短功能
  • 优先考虑可读性而不是效率(当然,在可以接受的情况下,有些效率提升实在是太惨了而无法保持)

以我的经验,编程是熵而不是新兴的(至少在流行的命令式结构范例中)。当人们编写代码以“正常工作”时,趋势就是失去组织。现在组织代码需要时间,有时甚至还不止于工作。

除了功能实现和错误修复之外,还请花费时间进行代码清理。


“……这个项目注定要失败” -以我的经验来看,不一定如此。另一种方法是教育所说的经理,并说服“投入”精力进行可维护性和解决技术债务
gna 2014年

抱歉,我无法坚持自己的看法,因为当经理忽略了我所有的技术债务建议时,我已经有了经验。但是我认为您是对的:在我放弃该项目大约一年后,经理因无法管理项目而失去了对技术团队的所有权限。
Eric.Void 2014年

1

令我惊讶的是,众多答案中没有一个突出了显而易见的内容:使该软件包含众多小型独立库。使用许多小型库,您可以构建大型而复杂的软件。如果需求发生变化,则不必扔掉整个代码库,也不必研究如何修改大型honking代码库来执行除当前正在执行的操作之外的其他操作。您只需要确定需求更改后这些库中哪些仍然有用,以及如何将它们组合在一起以具有新功能即可。

使用那些库中的任何编程技术,使该库的使用变得容易。注意,例如,任何支持功能指针的非面向对象的语言都支持实际上的面向对象的编程(OOP)。因此,例如在C语言中,您可以执行OOP。

您甚至可以考虑在许多项目之间共享那些小的独立库(git子模块是您的朋友)。

不用说,每个小型独立的库都应进行单元测试。如果某个特定的库不可进行单元测试,则说明您做错了。

如果您使用C或C ++,并且不喜欢拥有许多小.so文件的想法,则可以将所有库链接到一个更大的.so文件中,或者可以进行静态链接。Java也是如此,只需将.so更改为.jar。


从我的角度来看,这似乎有点过于理论化。当然,我在问题中提到的项目是由多个库和模块构成的。我在过去26年的软件开发中的经验是,该项目越老越会得到最初的组织
chrmue

0

简单:将大部分代码的维护成本降低到零,直到您拥有可维护数量的活动部件为止。无需更改的代码不会产生维护成本。我建议旨在使代码真正具有维护成本,而不是试图在许多小的繁琐的重构迭代中降低成本。立即使其成本为零

好吧,诚然,这比听起来要难得多。但是开始并不难。您可以获取一部分代码库,对其进行测试,如果接口设计一团糟,则可以在其上构建一个不错的接口,并同时开始扩展代码库中可靠,稳定(如无需更改的原因)的部分缩小不可靠和不稳定的零件。感觉像是噩梦般维护的代码库通常不会将需要更改的活动部分与不需要更改的部分区分开,因为认为所有内容都不可靠且易于更改。

我实际上建议一路将代码库的组织分为“稳定”部分和“不稳定”部分,而稳定部分是要重建和更改的巨大PITA(这是一件好事,因为它们不需要如果它们确实属于“稳定”部分,则进行更改和重建)。

导致可维护性困难的不是代码库的大小。这是需要维护的代码库的大小。每当我说使用操作系统的API时,我就依赖数百万行代码。但这并不会增加产品的维护成本,因为我不必维护操作系统的源代码。我只是使用代码,它可以工作。我只使用而不需要维护的代码不会对我造成任何维护成本。

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.