编码指南:方法不应包含超过7个语句?


78

我一直在浏览《AvSol编码指南》(C#),我几乎同意所有内容,但我真的很想知道其他人对一个特定规则的看法。

AV1500

方法不应超过7条语句需要7条以上语句的方法执行的操作过多或职责过多。它还需要人的头脑来分析确切的语句,以了解代码在做什么。用不明原因的名称将其分解为多种小型且重点突出的方法。

你们大多数人都遵循这个规则吗?即使可以大大提高可读性,即使创建新方法(您的代码仍然是DRY)几乎没有什么余地?而且您的电话号码仍然低至7吗?我倾向于10。

我并不是说我到处都违反了这条规则,相反,我的方法体积小且专注于95%,但我说你永远不应该违反这条规则,这真的让我感到震惊。

我真的只是想知道每个人对永不违反此规则的看法(在编码标准上为“ 1”-永不这样做)。但是我认为您很难找到没有的代码库。


48
他们也算case单单switch吗?无论如何,这只是一个白痴,无用的要求。那些写它的人对编程一无所知。
SK-logic

86
编码标准上唯一应为'1'的规则应为规则“您应将所有编码准则都加一粒盐”。
Mike Nakis 2012年

6
@ SK-logic 1027也不错-如果必须将空字符串等同于空字符串,编写必须处理丢失数据的代码一定很有趣。
quant_dev

25
阅读本指南时,我希望看到一个完整的代码库:void DoSomething(){DoSomethingFirstSevenLines(); DoSomethingSecondSevenLines(); DoSomethingThirdSevenLines(); 等等; }
拖船2012年

12
尝试反映大部分.NET Framework并查看有多少种方法的语句少于7条...
David Boike 2012年

Answers:


195

对我来说,这是“标准气味”。每当我看到编码标准中有特定限制时,我都会担心。您几乎总是遇到一种方法需要大于标准允许的情况的情况(无论是行长/计数,变量数,出口点数等)。标准应更像准则,并留有足够的回旋余地以行使良好的判断力。不要误会我的意思,拥有标准是很好的,但是它们不应该成为“代理的微观管理”。


25
为“通过代理进行微管理” +1。我怀疑有人读过“ 7加减2”规则(en.wikipedia.org/wiki/…),并将短期事实保留与长期存储(如代码编辑器)混淆了。
蓬松的2012年

25
有任何经过深思熟虑的标准禁止在代码中使用幻数,对吗?您会认为编码标准也将遵循该标准。数字7绝对具有一定的“魔术”品质。
亚当·克罗斯兰

2
你的回答会更有意义,如果该文档的标题不是“编码Guidlines为C#3.0和4.0。
安迪

+1在我看来,您应该遵循编码标准的唯一原因绝不是教条地遵循任意数字,而是要确保您不会在版本控制中引起不必要的合并问题(例如,在团队中工作时相关的问题)。通常,较短的文件和更多的组件意味着合并代码更改时出现问题的机会较小。
Spoike 2012年

3
我下载了此文档并开始浏览。在1.6中,它指出:“该文档没有说明项目必须遵守这些准则,也没有说哪个准则比其他准则更重要。但是,我们鼓励项目自己决定哪些准则重要,项目会有哪些偏差使用,如果出现疑问,谁是顾问,以及源代码必须使用哪种布局。” 即使1表示“切勿跳过且应适用于所有解决方案的准则”,也可以选择对其进行修改。
克里斯

83

通常,将内容拆分为小方法是个好主意。但是重要的是在合理的地方进行拆分。

如果拆分没有意义,请不要拆分。对于某些过程或GUI代码,通常是这种情况。

史蒂夫·麦康奈尔Steve McConnell)在《代码完整》中指出,使用简短方法时,您的工作效率并不总是更高。如果在没有意义的情况下进行拆分,则会给代码增加复杂性而没有任何好处。

像往常一样,最好记住为什么存在约束,以便您可以在不适用约束时学习。在大多数代码中,这些方法会很简短,或者您可能对DRY或关注点分离有疑问。但是,如果不是这样,那很好。


1
好答案。最后两行特别指出这一点。
Xonatron 2012年

6
我认为重要的经验法则是检查子方法是否正交。如果它们是独立的,则可以按任何顺序调用并尊重类不变性,那么最好将它们分开。如果方法紧密耦合,中断类不变式和/或需要按特定顺序调用,那么将它们保持在一起可能更好。
hugomg

4
代码完整,充满了好东西。每个程序员都应该每天在午餐时吃一部分。
deadalnix

29

应该将其视为经验法则。

诸如“不超过80(100,120)列的文本”,“每个方法一个出口点”,“不超过2个嵌套级别”之类的东西,我称之为代码气味指示器的阈值。如果您偶尔违反它们,那并不一定意味着代码是错误的。如果发现自己始终违反它们,则代码中会有些气味,您不妨暂停一下并重新考虑您的方法。

对我来说,最重要的标准是:“此代码可理解吗?”,“是否重复?”,“是否在逻辑位置分解?”,“是否松散耦合?” 还有更多,但我认为可以通过记住Donald Knuth的建议来总结基本思想:“程序应由人类读取,并且只能由计算机执行。”


7
“ 80/100/120”列的限制是,因此我们可以阅读代码。大多数终端打开80列,使作者包装到80列要比让每个读者每次阅读代码时都要调整终端的大小要少。与其他限制不同,N列限制不影响代码的语义,这是一个纯粹的样式规则;与“使用4个空格标签”或“在自己的行上放置功能的开括号”相同的类别。
Dietrich Epp '02

4
当然,这是美学方面,而不是语义方面。但是,这就是我的最后一句话。找到超过80列规则的Java语句并没有“好”的地方来分隔行,这并不少见。这会影响代码的可读性和理解。这也可能表明违反了Demeter法
seggy

7
在21世纪,我的IDE具有称为“动态自动换行”的功能。
捷尔吉Andrasek

9
@GyörgyAndrasek:但是,并不是每个人都总是使用您的IDE:我们在GitHub中的代码中使用in less,in vimemacs; 自动包装充其量似乎是偶然的。编码标准不是为了您的利益,而是为了团队合作人员的利益。
Dietrich Epp '02

2
@DietrichEpp就我个人而言,我很难读取始终包装在第80列的代码。最近,我不得不在使用标准Eclipse格式化程序的Java项目上工作。在一种方法中,很难跟踪超过两行甚至三行的行(不过,我也为此归咎于其他格式化程序设置)。最重要的是,我认为80有点过时了。我个人使用的限制为120,设置编辑器以强制执行此限制,具有120列宽的控制台,而Github实际上显示125列。我认为这样更具可读性。

18

我从来没有花时间来实际计算方法中的语句数,但是我确实致力于编写干净地执行一个明确目标的方法。只要您的代码干净,可读并且遵循DRY和“ 单一职责”原则,您就可以完成工作。我认为,为了强制执行七语句限制而将方法任意分开可能会使您的代码难以读取/难以维护。


1
+1以提高可读性。方法的长度为20、30甚至50行甚至没有关系。如果DRY和SRP是您的目标,那么这些方法看起来似乎并不长久……尽管大多数情况下,您会发现尝试编写代码的可读性越高,方法越短会自然而然地变成。
S.Robins'2

11

大概

这类规则不应该从字面上理解。他们本可以说“ 方法应该简短 ”。但是,有些人将其解释为“少于1页”,而其他人则将其解释为“最多2行”。

我认为他们说“ 7句话”是为了给您一个大概的想法(尽管我认为他们应该说“大约7”)。如果您偶尔需要9点,请不要流汗。但是,如果您的目标是20,您将知道自己不在此规则的正确范围内。


那使它成为一个非常明显的近似值。它被标记为“准则,您绝不能跳过并且应该适用于所有情况”。
brian 2012年

1
@brian-指南编写者可能不小心忽略了“大约”一词,或者他们是疯狂的独裁者。我的观点是,OP应该以此为标准。编译器或解释器不执行的任何规则都只是一个建议。
内森·朗

“编译器或解释器不执行的任何规则都只是一个建议”不一定是正确的。我没有看过他的自定义“ resharper”或“ fxcop”规则以及它们是否确实执行了此特定规则,但是有一些公司强迫您根据所有样式准则进行验证。我遇到了一些人,他们的公司强迫他们编写可以通过严格的Microsoft编码准则的代码。
brian 2012年

我同意这是一个近似值,应该以一小撮盐来表示,将一段代码标准调高为任意数将不可避免地引起混乱。在大多数情况下,标准会脱离上下文,“人”将遵循这种任意近似作为教条。
Spoike 2012年

10

7是一个完全任意的数字,绝对没有意义。

循环复杂度是一个比语句数更大的问题。我见过在一个方法中有100条语句的代码(我认为这很糟糕),但是它的循环复杂度为1,实际上只做1件事。只有很多步骤。我们讨论了将其拆分为较小的方法,但是这些方法只能由这一方法调用。

尽管这是一个极端的情况,但关键是您需要保持代码DRY和较低的循环复杂度。这比方法中的行数更为重要。

以switch / case语句为例。如果您有7个以上的可能值,是否需要将评估分为多种方法?当然不是,那将是愚蠢的。

人为地将代码分成更多的方法,只是为了使语句数保持在7以下,只会使您的代码变得更糟。

准则应为:每个方法应做1件事,并使代码保持DRY。


1
+1:任意限制仅是任意有用的。方法应在单个抽象级别包含单个连贯操作。打破这种原子单位会使代码变得更加复杂,从而使代码理解变得更加困难。
Allon Guralnek'3

DRY被高估。通常,这意味着紧密耦合某些不应该紧密耦合的事物的两个方面。
布拉德·托马斯

4

好吧,这取决于一点。我写了很多访问数据库的代码。在许多情况下,用于异常处理的样板代码超过七个语句。我说最好的准则是确保您的功能具有一个目的


8
您不能将样板代码抽象为自己的方法吗?
erjiang 2012年

发布后我注意到这是C#而不是Java,但我在想这种事情。stackoverflow.com/questions/321418/...
杰德

@erjang:可以。在Java中,这非常丑陋,因为您必须将每个查询包装在一个匿名类中,但是仍然值得做。在C#中不那么丑陋,绝对值得一做。
凯文·克莱恩

就个人而言,我发现固定线代码的一些额外的行更易读。但是也许就是我。
贾德

@Jaydee链接的问题显示了常见但奇怪的做法:包装异常并记录日志。在下一个级别,您可以执行相同的操作...这样,单个异常会在日志中多次出现。最好声明抛出方法,然后保存3行。编写一个关闭两个方法psrs然后保存另一个方法。或者编写一个List<Row> readDb(String sql, Object... args)可以完成全部工作的方法(仅适用于适合内存的结果集,但是获取太多数据通常意味着无论如何都应在数据库中完成工作)。
maaartinus 2014年

4

一切都是权衡。提议的方法的问题-重构为几个方法和类,以使每个方法都简短-是尽管由于不同的原因,但如果将其极端化,则会导致无法阅读的代码。

想象一下一种方法foo()可以执行7件事。您可能会认为7件事太多了。在许多情况下,也许您是对的。另一方面,这7件事可能紧密相关。逻辑可以顺畅地流动并像散文一样阅读;实际需要时,您可能会很容易理解它。最终可能会更糟糕的是将这7件事分散在一个大型的源代码树中,因此,如果您foo()不看7个不同的地方,就不知道它的作用。

许多人脑子里有了这样的规则,结果就是我认为的OO面条。一切都是整齐的,以自己的小方法或类装箱,每个地方都发生原子的微交易。但是不可能重新了解这样的代码库并知道它在做什么。你迷路了。


4

这不是一个坏准则。只要将方法和类进行分组并且相互关联得很好,我就不会后悔将它们拆分开(我从来没有发现我有太多方法)。

诀窍是不要将其垂直拆分(只需将一种方法捏一点,然后再开始一种新方法即可)。就像单元测试一样,技巧是从一开始就牢记这样的规则,以便您实际上可以更好地进行设计,将3或4条语句从中间方法传递给另一种方法,因为进行方法调用比您描述的要好代码中间的那3或4条语句。

这种拆分,即使它是任意的并且仅使用一次,也可能由于新的代码清晰度而在以后导致更好的重构,对于较小的类也是如此。

像对待单元测试一样思考它。如果您尝试在事实之后添加单元测试很困难,有时似乎是不可能的,但是如果从一开始就进行设计,那么实际上会使所有代码变得更好。

摘要?如果将“使用少于7条语句”的设计气味与“我使用7条以上语句”的代码气味进行比较,则宁愿消除该代码气味。


4

哇!我从没想到会在一个简单的指南上找到如此激烈的讨论,该讨论粗略地说您的方法应该很小。因为他们一直是希望他们的准则明确的开发人员,所以我选择7是因为这听起来像是一个不错的门槛。

你们中有些人已经在文档开始处引用了免责声明。但需要明确的是,本文档代表了一些准则,旨在帮助您编写更好的代码和设计更好的系统。我从来没有说过,即使将准则标记为第1级,任何事情都应该成为规则。这些级别只是使用本文档一段时间的许多人的集体意见。

我也从未声称自己是专家。但是我从事该行业已有15年了,大约有4年C ++经验和11年C#经验。它最初基于Industrial Strength C ++,但是从那时起,我一直在社区的投入下对其进行完善。

无论如何,我要提出的观点是,您应该继续自己考虑。如果您认为这7条声明指南没有用,则可以延长它。哎呀,我什至不时违反该准则。我只是认真地违反它并接受后果。


3
你们很好,我想您提出合理的论据。就是说,我不同意您的理由“他们总是希望他们的准则明确的开发人员”:您不能总是迎合白痴,也不应该尝试。只要不使准则变得错误就可以使准则明确是一件好事:现在它不再是准则,而是一条任意规则。正如您所看到的那样,引入任意数字是被击落和证明是正确的死路。
Konrad Rudolph

3

首先:这是一个准则,而不是一条规则。它被称为准则,因此请按原样对待。这意味着您也需要自己的判断(一如既往)

除此之外,我可以想到许多不遵守此约束的良好代码示例。即使只是一个准则,也很糟糕。


2

我同意我上面的说法。这只是一个准则,在一个完美的世界中,所有东西都是对象,可以在每个程序中重复使用,而世界将是一个美丽的地方。并非总是如此,有时这会导致大量开销或资源浪费。您还需要记住这一点。


6
“我同意我上面的说法”在stackexchange网站中避免此类句子。请记住,答案贴出的顺序不一定是它们显示的顺序。
luiscubal

我知道,直到为时已晚,我才思考。但是,我还是会为您+1指出我的屁而+1。
Falcon165o 2012年

2

当您将异常处理添加到混合中时,这非常愚蠢。

在“尝试,捕获,最后”之后,每个方法剩下四个语句!

还要考虑一个20字段表单的方法“ validateForm”,即使您用单独的方法处理所有单独的验证,您仍然有20个字段验证方法要调用。根据这些指导原则,您将最终得到一些毫无意义的拆分,例如“ validateTopOfScreen”,“ validateMiddleOfScreen”和“ validateBottomOfScreen”。


我认为这是相当肯定地说,try/ catch/ finally是不是在C#语句。请参阅Ecma-334§12.3.3.15及其周围部分。(缩写)“以下形式的try-catch-finally语句:try try-block- catch(...)catch-block-n最终finally-block
CVn 2012年

好吧,正如我之前说的,这是一个决定,您必须一遍又一遍。但是,您的特定示例可能是未正确进行面向对象设计的示例。您可能需要将屏幕划分为多个控件,这些控件自己进行验证。
丹尼斯·杜门

@Dennis-是的,做HTML表单太久了!
詹姆斯·安德森

@James这就是该特定准则的目的。试图让您想到替代的,可能更好的解决方案。
丹尼斯·杜门

2

问题是将“规则”与“准则”混为一谈。必须遵守规则-准则是建议,旨在使您考虑自己在做什么以及是否真的可以以更好的方式完成。

我想说的是,平均而言,大多数编程可能会通过遵循准则得到改进,但总有一些情况是,严格遵循准则会导致比计划解决的问题更多。这就是为什么它们不作为规则呈现,而是准则的原因。

先前的答复者表明,指南的编写者从未打算将其原则用于教条,而是在其文档中包含对此的说明。


0

我同意上面的评论。7对我来说是任意的,在某些使用ruby的语言中可能有用,但是对于C#,Java,C ++等语言,我怀疑这种“ 7行”约定。让我举一个例子。我当前的应用程序有22个文本字段,我进行服务器端验证。该方法称为validateInput(),我的喜好是验证一个方法本身中的所有字段,除非我已经验证了诸如checkEmailFormat()之类的复杂对象。所以基本上我的validateInput方法代码是108行,偶尔会调用复杂的验证。

现在,假设我调用了25种方法来验证每个字段。如果有新的开发人员来,他将不得不进入和退出主要方法以跳过25种方法,而这些方法又可能会调用其他方法。他注定会在大型项目中迷路。

为了使代码清晰,我真正要做的是提供清晰的注释,这些注释基本上说出了这4行在做的事情-

validateInput(UserObj用户){

//验证名字.............

//验证姓氏...... ......

//验证电子邮件..... //太复杂,无法检查电子邮件格式的常规表达式checkEmailFormat(); .......

等等.. }


1
另请参阅我对詹姆斯·安德森(James Andersons)问题的回答。在您的特定情况下,我想知道该验证方法是否不会同时违反几个原则和准则。
丹尼斯·杜门

0

坏规则。有了用于异常处理,设置数据库字段,验证的代码,大多数方法怎么会在七个语句之下?我们不应该做内联lambda函数吗?

代码行是复杂性的任意计数。使用扩展方法,我可以创建如下代码

                Parallel.ForEach(regions, region => {   Console.Write(region.Resorts.Where(x => x.name == "Four Seasons").OrderBy(x => x.RegionId).ThenBy(x => x.ResortId).ThenBy(x => x.name).ToList());   });

再次是在单一方法中做太多事情的一个很好的例子。在几乎每一个反驳的争论中,人们都违反了单一责任原则(在一种方法的背景下)。
丹尼斯·杜门

-1

所有初级程序员都必须遵守这一原则。这将迫使他们考虑自己正在忙的事情的结构,而不是仅仅添加越来越多的行代码。

我目前正在寻找一种包含550行代码的方法,其中包含许多if else语句,然后继续并将其织入其中。废话 只是程序员被迫考虑自己在做什么...

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.