如何知道自己创建的代码是否易于阅读,理解和维护?当然,从作者的角度来看,该代码具有可读性和可维护性,因为从一开始,作者就对其进行了编写和编辑。但是,必须有一个客观且可量化的标准,我们的专业人员才能测量代码。

如果在没有原始作者的专业建议的情况下可以对代码执行以下操作,则可以达到这些目标:


可以阅读代码并从基本层次上理解逻辑流。输出和算法。
其他开发人员可以对原始代码进行有意义的更改,例如错误修复或重构。
可以编写新代码,例如利用原始代码的类或模块。

我们如何量化或衡量代码质量,以使我们知道代码的可读性,可理解性和可维护性?

评论

强制性链接(一次不链接至xkcd):osnews.com/images/comics/wtfm.jpg

我只是轻描淡写地说,当您看到它时就知道它,但是该论点从根本上来说是有缺陷的,甚至以其原始形式令人尴尬,没关系将其应用于源代码。

“当然,从您的角度来看,您的代码是可读的”-不太明显!

写完几个月后,我会说你知道它。

@asfallows:我给妻子看了一些代码,她认为这是很糟糕的代码,因为她可以阅读! (其中有很多英语单词,但没有足够的@ [!^ $&*)字符...)

#1 楼

您的同伴在查看代码后会告诉您。

您不能轻易确定自己的位置,因为作为作者,您不仅了解代码本身。出于无法分辨绘画是否为艺术品的相同原因,计算机无法告诉您。因此,您需要另一个能够维护该软件的人员来查看您所写的内容并给出他或她的意见。该过程的正式名称是同行评审。

评论


没有什么比经验测试更胜一筹。

–世界工程师
2012年3月22日17:39

+1您最重要的听众是与您一起沉浸在了解您正在研究的问题的原因和方式及其解决方案的同龄人。好的代码反映了您的同龄人小组当前对此的理解。假设团队是有能力,有思想的并且愿意接受新的想法,那么根据我的经验,“您的同事告诉您它的好/可维护”是迄今为止其他任何人都更好的定义。

– Doug T.
2012年3月23日在0:55



以我的经验,这仅在您的同事知道什么是好的和什么是坏的时才有效。否则,听起来会像这样:“您应该使用相同的方法编写这些代码,这样更容易找到代码”

–林吉angi
2012年3月23日5:30

@RangiLin,好吧,您的同事可能是正确的。

–user1249
2012年3月23日14:25

@Rangi您必须与自己的同事一起工作。如果他们发现您的代码很困难,那就是您的代码有问题。从长远来看,您可以教育他们,或者尝试结交更好的同事(可以搬家,也可以影响招聘过程)……哦,是的,并且始终记住他们可能是正确的。

– MarkJ
2012年3月27日22:57

#2 楼

有时,最好的了解方法是回到六个月前编写的代码,然后尝试了解它的编写功能。

如果您很快理解它-就是可读的。 >

评论


是的,这听起来不错(而且确实如此),但这并不是决定今天做什么/如何做的好方法。

–迈克尔·杜兰特(Michael Durrant)
2012年3月22日18:05

解剖表明这需要一段时间,您必须仔细做...

–deworde
2012年3月23日在9:06

我可能会将重新访问的时间降低到一个月或更短的时间,以便进行第一次重新访问。我认为这取决于项目和领域的复杂性以及您的思维方式。我发现六个月后,我因看到使用自我首次编写代码以来所学到的工具或技术进行重构或优化的机会而分心,而不是真正的可读性。

–克里斯·拜
2012年3月23日15:14

@MichaelDurrant每次您查看旧代码时,都会发现应该以不同的方式编写的代码,然后您将考虑到“今天”编写的代码。是的,学习如何编写好的代码确实需要时间。

– dj18
2014年3月17日在16:19

@MichaelDurrant仍然是一种,因为您可以了解六个月前所做的不清楚的事情,而今天却不去做。

–djechlin
2014年9月2日14:22在

#3 楼

它是:


可以维护,如果可以维护的话。否则,在阅读时,正确理解了设计,布局和意图。

1.的真正测试是(如Alex in Paris和quant_dev所说的),您可以在几个月的工作后将其取回

2.和3.的测试是其他人可以选择它,并弄清楚如何在遵循设计原则的同时扩展或修复代码。如果他们不了解设计,它与问题空间的关系或打算如何使用您的代码,则他们会跨各种方法破解解决方案。

有一些规则大拇指,原则(即,某人很好地写下并给出了一个名字的经验法则)以及各种建议,这些建议可能会引导您朝正确的方向发展,或者远离常见的陷阱。但是,它们都不能保证您所要求的质量。

评论


考虑将花费在修复错误或修改现有行为上的时间量作为可维护性的因素如何?一段需要较少时间来完成相同更改的代码应该更具可维护性,对吗?

–VCD
18年1月4日在1:25

依靠;有时修改得很好将需要重构(您可以告诉我们,因为清晰的代码可以清楚地表明它并非旨在那样使用),这比黑客在特殊情况下花费的时间更长(难以理解的代码鼓励这样做,因为意图不明确) )。

–没用
18年1月4日在11:07

#4 楼

如果您的代码遵循SOLID和DRY的原理,并且围绕它进行了很好的单元测试,则它可能是可维护的。

可读吗?阅读。方法和变量名有意义吗?您可以毫无问题地遵循程序逻辑吗?如果答案是肯定的,则代码是可读的。

评论


...阅读完之后,将其交给其他人尝试阅读。

– jcmeloni
2012年3月22日在17:01

这不是一个特别好的测试。这些规则的许多应用都是主观的,并且几乎总是可以在编写代码后立即阅读自己的代码。

– DeadMG
2012年3月22日17:39

“如果答案是肯定的,那么代码是可读的”……您。要查看其他人是否可读,其他人必须尝试阅读它。

–user1249
2012年4月5日下午6:54

IMO,SOLID被高估了。特别是“ S”那或每个人都误读了它。

–埃里克·雷彭(Erik Reppen)
13年6月16日在2:34

我已经花了无数次去处理DRY和SOLID但又可怕的代码。遵循原则可能会给人错误的印象,即您所写的内容不是胡扯。

–雅库布·阿诺德(Jakub Arnold)
17年9月19日在8:13

#5 楼

阅读如何编写无法维护的代码-通过Roedy Green,大笑和学习确保终身工作。


...如何编写难以维护的代码,以至于您之后的人们将花费数年才能做出最简单的更改。此外,如果您虔诚地遵守所有这些规则,您甚至可以保证自己一生的工作,因为没有人但是您希望在地狱中维护代码...


这篇文章使用大量有趣的示例,为您提供了许多如何编写不良代码的示例。它继续说明如何利用创造性的拼写,名称的重用,广受赞赏的将全局名称重用为私有的技术。

本文以幽默的方式教您如何避免所有无法读取和无法维护的代码示例。

实际上,我发现很难相信有人会编写与文本示例相似的代码。那是我刚从学校毕业的时候。但是,工作了几年之后,我每天都会从文本中看到代码……

评论


另请参见Waterfall2006.com/gorman.html Refuctoring是一段经过精心设计的代码的过程,并且通过一系列小的,可逆的更改,使除您以外的任何人都无法维护它。

– Sjoerd
2012年4月18日在13:48

#6 楼

不管看起来如何,您都可以考虑一些相当客观的措施。诸如C ++编码标准,重构和整洁代码之类的书都有很长的标准,可用来判断代码,例如,有意义的名称,函数大小,耦合和内聚性等原则,对象设计,单元测试,逐项改进等。 br />
列表太大,无法接受清单,但是您读了这本书并挑选了一些要处理的关键事项,然后在几个月后再次阅读以进一步改进。

评论


+1为增量学习,而不是在一夜之间变得完美

– dj18
2014年3月17日下午16:21

#7 楼

证明在布丁里。将其交给合理胜任的人员后,观察发生的情况。如果他们不需要问很多与代码难度有关的问题,那么您做得很好。

这是我职业生涯的早期课程。一位导师说:“记录所有内容,以便以后可以退出程序。如果您在脑海中浮现新答案时就没想到问题,那么您就必须找出答案。” br />

评论


注意,由于害怕暴露自己的无知,人们可能会避免提出问题。您甚至可能一开始就认为这些人“具有合理的能力”,因为他们倾向于不公开这些信息。因此,除非您知道双方都真诚,否则缺少问题可能不是一件好事。

– Fzs2
2012年11月10日12:03

@HermannIngjaldsson-足够公平。当然,如果他们不称职并且遇到了问题,您会很快听到有关它的消息。 “救命!!!!”

–MathAttack
2012年11月11日13:59

这似乎只是重复在最高答案中所述

– gna
15年7月21日在0:44

#8 楼

我通读了所有答案,但没有发现任何人提到代码复杂性。代码复杂度评分算法有很多,但我只讨论McCabe复杂度评分的工作原理。

基本上,McCabe评分会读取您的代码并计算通过它的唯一“路径”数。如果使用McCabe作为分子,并使用代码行作为分母,那么您还将获得与“可读性”相当好的近似值。

如果您有10行代码,并且该代码有300条路径,那是一些非常难以维护的代码(很难安全,轻松地进行更改),并且它可能不太可读。相反,如果您有300行代码,但是只有1条路径(没有条件),那么它既可读又易于维护。

McCabe失败的地方是后一个例子。如果我有300行无条件的代码,那么我很有可能完成了“复制/粘贴重用”,这显然也不是一件好事。因此,除了McCabe之外,您还可以应用系统范围内的指标-例如重复或接近重复的代码检测。

评论


这应该是答案。测量。其他答案多于观点,多于事实,如果我能理解,那一定好吗?首先使用复杂度分析进行度​​量,然后进行人工重构以查找重复等。

–乔恩·雷诺(Jon Raynor)
2014年6月20日14:36

您的最后一段提到McCabe分数除以LOC的弊端,反而会使整个想法失效。如果您的代码需要300条路径,那么为什么您认为使用更多行将使代码更易于维护?这就像是说如果一本书提出了复杂的想法,那应该是一本非常大的书,而不是试图进行简洁的交流。 -1。

–通配符
17年1月5日,下午3:20

#9 楼

我要分享的一点是,代码是否内置在“模块”中,当我说我的意思是,您可以更改模块中的一件事并轻松地使其与整体配合使用。它消除了不相关的事物之间的影响。 >干-不要重复自己

我强烈建议您阅读《实用程序员》。

#10 楼

一言以蔽之。

首先,您需要进行基础工作,因此我不建议程序员多花些时间阅读诸如Refactoring之类的书。将在程序员库中提供一些更基本的工具,这些工具将提高您的代码维护能力,以及由我们领域中一些最知名的专家编写的“干净代码”,它几乎描述了您需要了解的所有内容为了确保您的代码清晰易读。为了充分理解对代码质量的影响,您确实需要使用代码一段时间。通过体验使用整洁,因子分解的代码的乐趣以及使用代码面条的痛苦,您将学会更好地理解这些书的作者真正想教给您的内容,但是您需要在更广泛的背景下进行操作真正的实时生产代码,您所做的工作的质量真正重要,这会影响您每天轻松使用代码的能力。一个有经验的同行来确认您正在努力编写高标准的代码。这只是代码审查如此有用的原因之一。使用代码检查和格式设置工具也可以非常有用,可以确保您保持环境整洁。但是,没有什么比得上多年编写软件所获得的经验,因此,您会自动发现自己编写的代码干净,可读性强,结构简单,只是为了易于维护,而这一切都是因为您已经习惯了为此应用最佳实践长。

#11 楼

一些测试/指标:


关闭IDE。您还能阅读自己的代码吗?当存在错误时,手动查找它很容易并找出需要断点的类以找出问题所在?还是当您使用IDE时,您甚至都没有打扰甚至只是从头开始?
调试是否经常成为一堆麻烦的游戏,其中修复一个bug会产生2个以上的错误。
从触发器拉到实际发生的有用事情,需要多少次方法调用?有多少个方法将完全相同或大部分相同的参数传递给另一个方法调用?
要给一个类添加一个简单的新方法,您需要打开多少个文件?
思考一下模式和您采用的做法。您之所以这样做,是因为它们很合理,还是因为有人说服您“这是唯一的方法”?或者是因为您想在履历表中使用它,或者是因为某个摇滚明星开发者这么说。


评论


在没有IDE的情况下阅读代码似乎很愚蠢,尤其是作为一种可读性度量。这种类型的度量标准导致产生了匈牙利符号样式的“解决方案”,这最终破坏了可读性。

– rubenvb
17年6月15日在11:22

#12 楼


怎么知道他创建的代码是否易于维护且易于阅读?


通过查找以下属性,可以发现易于维护和可读的代码:


对象,方法和/或函数总是做一件事。
方法和/或函数很简洁(如“简短而全面”)。 ,方法和/或函数实际上会根据名称执行您认为应该做的事情。
注定要重用的代码实际上是可重用的。可以立即对代码进行单元测试,您至少可能已经编写了单一职责的模块化代码。 />代码?是否有任何结构或准则可以知道我们是否开发了
凌乱的软件?是,这充其量是不好的,最坏的情况是可能无法维护的。 >如果整个代码库缺乏对称性(一致性),那么您可能正在查看无法维护的代码。


评论


我不同意您的重构示例更清楚。我同意原始代码需要工作,但纯粹是在清晰度和传达意图方面,我认为原始代码要好得多。我非常怀疑有任何重构声称在引入正则表达式时可以提高清晰度。

–罗伊
2014年10月1日在11:17

@罗伊,是的,很公平。我可能永远都不会添加该代码示例。当然,那是大约3年前的事了,但是即使到那时,我可能也不应该使用PHP(我现在只是想看看它),而且我不应该使用正则表达式,因为它是某些人所喜欢的东西之一可以查看并立即获得它,但是对于其他人来说,无论多么简洁,正则表达式都会立即关闭。我将编辑答案并删除代码示例。感谢您的评论。

–威尔·摩尔III
2014年10月1日在17:09

对象如何做一件事?

–科雷·图吉(Koray Tugay)
2015年5月5日17:09

@KorayTugay这样想。如果一个对象描述的不仅仅是一个内聚的概念,那么您就有一种嗅觉。

–威尔·摩尔III
2015年5月7日在6:37

#13 楼

可读且可维护的代码:
程序员一眼就能理解的代码,可以很容易地做到:


通过其界面重用它,或者
调试它,或
更改其行为。 (添加/删除功能),或者
对其进行优化
对其进行测试

可以归结为“清晰度”。例如,程序员在确定自己“了解它的功能足够好”以完成当前任务而不会引起意外副作用之前,必须对特定代码段询问多少个问题。

“史蒂夫·麦康奈尔(Steve McConnell)编写的“代码完整”(Code Complete)一书对此进行了详细介绍。

他会检查各种指标,您可以使用这些指标确定代码的质量。

在此处查看示例:
http://books.google。 co.uk/books?id=3JfE7TGUwvgC&lpg=PT376&pg=PT389#v=onepage&q&f=false

评论


这似乎并没有为先前的回答中提出和解释的观点增加任何实质性内容

– gna
15年7月21日在0:54

我认为它添加的最重要的内容之一是对Code Complete的引用,以前的答案都没有提及。那本书是最重要和最有影响力的书之一,专注于编写可读和可维护的代码。阅读该书的任何人都不需要问“您怎么知道您是否编写了可读且易于维护的代码?”。

– JW01
15年8月26日在11:35



...因此,我认为,如果他们真的对编写可维护的代码感兴趣,那么任何人都能得到的最好的东西就是阅读这本书。因此,经过几分钟的仔细思考(通常比SO主持人多花几分钟的思考时间),我认为这不仅是对OP问题的充分答案,而且是最好的答案。

– JW01
15年8月26日在11:45

#14 楼

无需清教徒:更喜欢功能样式。如今,大多数语言(.NET,Ruby,Python,Javascript等)都支持和推广它(例如LINQ,underscorejs)。

它非常易于阅读。

var recentTopCustomers = OrderList
    .Where(o => o.Date >= DateTime.Now.AddDays(-5))
    .Where(o => o.Amount > 1000)
    .OrderBy(o => -o.Amount)
    .Take(10)
    .Select(o => o.Customer);


它强制每个节点具有单一的,有重点的意图贷款,以达到目的明确的目的。而且由于每个离散任务都是孤立弹出的,因此插入节点并将节点(操作)重新排列到不同的端部是微不足道的。这样可以简化维护。

#15 楼

最小化副作用(理想情况下没有副作用)

与仅输入某些内容并输出其他内容的功能相比,一种导致3种状态变化超出其自身范围的状态的功能要难得多。您不能只知道函数的功能,还必须记住它的功能以及对所有其他相关功能的影响。可以修改类状态的成员,因为成员函数可以修改其自身之外的状态并具有副作用(例如,它们可以操纵类的内部)。这也意味着类拥有较少的数据成员,因此这些方法被篡改的状态更少,并且它们可能导致的副作用也更少。该结构可以维持sorted状态,用于确定是执行二进制搜索还是线性搜索。在这种情况下,将设计分为两类可能会很有用。然后在未排序的类上调用sorted可能会返回另一个始终保持其内容排序的类的数据结构。现在,您将具有更少的副作用(因此更少的容易出错且更易于理解代码)以及更广泛的应用代码(对于不需要排序的小数组,前一种设计在处理和人类智能效率上都是浪费的)。

避免过多的外部依赖性

通过使用13个不同的库来完成一个相对简单的任务,您也许能够以最大的代码复用率实现最简洁的代码。但是,这样一来,您不得不使读者至少了解13个不同库的一部分,从而将知识开销转移给您的读者。任何试图构建和理解第三方库的人都应该立即意识到这种固有的复杂性,而这需要引入并构建其他十二个库才能起作用。

这可能是一个很有争议的观点,但是我会如果最终结果是经过充分测试的,则更喜欢将一些适度的代码重复用于相反的极端(没有比多次重复的未经测试的错误代码更糟糕)。如果是在三行重复的代码之间进行选择以计算向量叉积,或者在史诗般的数学库中进行剃光以减少三行代码,那么我建议使用前者,除非您的整个团队都在使用此数学库,此时,如果它足够琐碎以换取去耦的好处,那么您可能仍然考虑只写3行代码而不是1行。

代码重用是一种平衡行为。重复使用过多,您就会以一对多的方式转移知识的复杂性,因为上面保存的那三行简单代码的代价是要求读者和维护人员比三行代码了解更多的信息。这也会使您的代码不稳定,因为如果数学库发生更改,您的代码也可能会更改。重复使用太少,您的知识开销也会倍增,并且代码也无法从中央改进中受益,因此这是一种平衡行为,但是值得一提的是,这是一种平衡行为,因为尝试消除每种小形式的适度复制会导致结果很难维持,甚至比相反的极端情况要难得多。

测试废纸C这是给定的,但是如果您的代码不能处理所有输入情况并且错过了一些边缘情况,那么您如何期望其他人维护您编写的代码,甚至在转移到他们的眼睛和手上之前,您甚至还没有做好准备?很难更改能正常工作的代码,更不用说一开始就永远不正确的代码了。更改。这关系到稳定性,而不是可维护性,这比实现稳定性更是一个圣杯,因为无需更改的稳定代码不会产生维护成本。如果您不能将相同的时间记录在文档中,那么“做什么”而不是“如何做”。一个清晰的界面,其意图是在所有可能的输入情况下将要执行的操作(或至少要执行的操作),这将为其自身的实现提供清晰的上下文,这不仅将指导理解

同时缺少这些特性的代码是SOL,无论其实现细节的文档化程度如何,人们甚至都不知道它应该做什么。长达20页的有关如何实现源代码的手册对于甚至无法弄清楚一开始应该如何使用它以及在所有可能的情况下甚至应该做什么的人来说都是毫无价值的。 br />对于实施方面,请优先记录与其他人不同的工作。例如,英特尔为其光线跟踪内核具有一个边界体积层次结构。由于我从事这一领域的工作,因此我一眼就能认出他们代码的大部分工作,而无需仔细阅读文档。但是,它们做了一些独特的操作,即遍历BVH并使用射线包并行执行相交的想法。那是我希望他们优先考虑其文档的地方,因为代码的这些部分与大多数历史BVH实现是异乎寻常的和不寻常的。我不太关心那种类似于人类思维过程的可读性。如果作者使用奇异而费解的思维过程来解决问题,那么对于我来说,仍然很难遵循最高程度文档化的最高级别描述事物的代码。同时,如果逻辑很简单,使用2或3个字符名称的简洁代码通常可以使我更容易理解。我想您可以同行评审,看看其他人喜欢什么。没有理由更改的代码就是维护成本为零的代码。

#16 楼

我想说的一种了解方法是,新团队成员是否可以相对轻松地掌握,理解并修改代码以修复缺陷/满足新要求。

#17 楼

这是我喜欢使用的一种技术:

向您的一位对等程序员展示代码,并让他们向您解释它的作用。注意这些事情。

1)如果他们不能轻易解释代码块重构的目的。
2)如果他们不得不跳到另一部分代码来理解
4)在过程中任何时候只要您想说话,都需要重构该部分代码。 (代码本身并不代表)。

评论


假设对等程序员至少具有同等的经验,并能读懂编程语言及其习语。诸如此类的所有常用技术可能会导致人们以一种语言表达能力的子集形式编写代码,这是一种误导性的尝试,使得即使是最初级的团队成员也可以理解int。结果是在笨拙的语言子集中增加了大量代码。而且,无论您对语言子集有多大的投入,与使用更具表现力的子集的200KLOC代码相比,维护500KLOC的小语言子集代码总是要付出更多的工作。

–user1703394
15年1月21日在10:44

这似乎只是重复在最高答案中所述

– gna
15年7月21日在0:48

#18 楼

最具可维护性的代码是不存在的代码。因此,代替增加LOC数量,“减少” LOC数量的新代码(即使在单独查看时,即使可维护性稍差)也可以通过减小其大小来使整个代码库更易于维护。因此,可维护代码的主要规则:



最大化DRY。因此,对于规则2:


使所有依赖项都明确。语言功能或习语。精简整个代码库将为您提供庞大的代码库,由于其大小难以维护。在整个代码中允许使用高级技术功能和惯用语将使所有代码仅可由高级开发人员维护,这也是不好的。可维护性的关键是基于技能级别的分层,例如:

跨项目库:高级开发人员,完整的技巧代码/习语/技术的完整反馈
项目特定的库和系统后端:中型开发人员,避免使用最高级且难以解释的内容。老年人将使用此代码来寻找DRY改进的机会。

前端:初级开发人员,使用严格的样式指南和一套技术来避免语言构造和习惯用法。 Medior开发人员将使用此代码来寻找DRY机会和隐藏的业务逻辑。

因此,对于规则3:


按开发人员的技术水平分层您的代码,相应地编写可维护的代码。

I

评论


这似乎并没有提供超过25个答案中所提出和解释的要点的实质内容

– gna
15年1月15日在21:01

@gnat,我希望在其他答案中为许多(可能有害的)过度简化添加“细微差别”。特别是第3点。

–user1703394
15年1月15日在21:21

@ user1703394这个问题及其答案是社区Wiki。如果您认为可以改善现有答案,则即使没有“编辑其他用户的帖子”特权,也可以对其进行编辑。

–user22815
15年7月21日在1:16

#19 楼

显然没有被重视的方面是命名。我现在想集中讨论。
一切都从命名事物以及它们在相关人员的思想中如何映射到现实开始。如果名称没有解释的余地​​,那就麻烦了。我了解到,不良的自然语言技能通常会导致不良的编码。
注意在现有环境中“固定”名称。如果许多人随着时间的流逝而学习并适应了一些愚蠢的术语,并且当他们听到这些声音时都想到同一件事,那么修复它可能会带来更多的麻烦。如果由于确实很糟糕而仍要执行此操作,请确保将其修复到域中的所有位置。不过,这可能是不可能的。
命名组件和类还有很长的路要走。里面有什么?它与其他组件和类有什么关系?所有这些决定都将受到名称解释的影响。
过快地定名只是为了与它相处永远不是一件好事。
本周我非常热衷于命名,因为我一直在努力更新协议实现,这需要我阅读规范文档并向现有代码添加新功能。事实证明,我的前任不喜欢规范文档中使用的任何术语,该文档是源自客户端的PDF。因此,他为以后不得不处理其代码的所有维护人员“修复”了该问题。如您所料,我在将规范映射到代码以及理解逻辑方面遇到了一些麻烦。他的名字比他们好得多。在开始做任何事情之前,我必须首先匹配所有内容并重新同步名称。
在软件开发中,没有“仅是名称”之类的东西。如果名称不完全正确,则需要知识才能获得正确的想法,这是一个障碍。