it-swarm.cn

被证明是好的函数最大长度是多少?

函数长度会影响程序员的生产率吗?如果是这样,为避免生产率损失,最大的最大行数是多少?

由于这是一个高度自以为是的主题,请备份索赔并提供一些数据。

47
Gaurav

自从我从1970年开始使用这种疯狂的球拍以来,我已经确切地看到一个真正需要需要的模块可以打印多个页面(大约60行)。我见过很多更长的模块。

为此,我编写了更长的模块,但是它们通常是写为大型开关语句的大型有限状态机。

问题的一部分似乎是这些天程序员没有被教导如何模块化事物。

最大化垂直空间浪费的编码标准也似乎是问题的一部分。 (我有至今认识一位读过 Gerald Weinberg 的“ 计算机编程心理学 ”的软件经理。Weinberg指出,需要进行多项研究证明程序员的理解力基本上仅限于程序员在任何给定的瞬间所看到的内容。如果程序员必须滚动或翻页,他们的理解力就会大大下降:他们必须记住并抽象化。)

我仍然坚信 [〜#〜] forth [〜#〜] 带来的许多有据可查的程序员生产力的提高是源于FORTH源代码的“块”系统:模块很难限制为最多16行,每行64个字符。您可以无限分解,但是在任何情况下都不能编写一个17行的例程。

47
John R. Strohm

正确的尺寸是多少?

取决于您使用的语言,但总的来说(根据我个人的喜好):

  • 理想情况下,少于25行。
  • 可接受,少于35行。

如果更多,那是我需要稍后再做的工作。

但是实际上,当您需要交付某些东西时,它需要的任何大小,并且在像这样将它们吐出来的那一刻变得更有意义了,有时甚至有人在运输之前进行审核就更容易了。 (但稍后仍会重新讨论)。

(最近,我的团队在我们的代码库上运行了一个程序:我们发现类中有197个方法,另一个类中只有3个方法,但其中一个是600行。可爱的游戏:这2种弊端有何危害?)


现在,要获得一个更禅宗的答案...通常,引用一个或两个伟人被认为是一种好习惯(TM),因此,这里是:

应该使一切都尽可能简单,但不要更简单。- 爱因斯坦

最终的完美不是在不再需要添加任何东西时,而是在不再需要去除任何东西时才实现的。- A 。de SaintExupéry


评论样式附录

作为此的补充,您的函数应具有清晰的名称,以说明其意图。关于注释,我通常不在函数内部进行注释:

  • 评论“为什么?”
  • code“怎么样?”

每个功能顶部的注释块(需要说明)就足够了。如果您的函数很小,并且函数名称足够明确,那么您只需要说出要实现的目标以及原因。我仅对某些语言的字段使用内联注释,或者对于意图不明确的违反25-35行规则的函数,在块开头使用内联注释。当发生特殊情况时,我在代码内使用块注释(例如,在您不需要或不想做任何事情的catch块中,应添加注释以说明原因)。

有关更多信息,请阅读 我的回答注释代码的样式和建议

31
haylem

我认为,每个功能都应尽可能小。每个功能只能做一件事,并且做得很好。这并不能真正回答最大长度问题,但更多是我对函数长度的感觉。

要使用鲍伯叔叔的话, “提取,直到无法提取为止。提取直到下降。”

12
Jason

建筑物的最大高度应该是多少?取决于构建的位置或所需的高度。
您可能从不同城市来的不同人得到不同的答案。
某些脚本函数和内核中断处理程序很长。

10
Huang F. Lei

一个对我有用的方法是:是否可以让一个较长的函数的一部分给出有意义的名称。我认为方法的长度并不像好的命名那样重要。该方法应该做到的就是名称所说的内容,不要多也不少。而且您应该能够给出一个好名字。如果您不能将您的方法命名为好方法,那么将代码组合在一起可能就不好了。

10
Mnementh

只要它需要做它需要做的事情,就不再需要。

10
Paul Nathan

我认为这是一个权衡。如果您有很多短方法,那么调试它们通常比长方法要难。如果您必须在编辑器中跳出20或30个不同的时间来跟踪一个方法调用,那么很难将其全都牢记在心。同时,如果有一种写得很好的清晰方法,即使是100行,通常也更容易掌握。

真正的问题是为什么项目应该采用不同的方法,并且上面给出的答案是代码的重用。如果您不重复使用代码(或不知道),则可以将其保留在一个易于遵循的巨型方法中,然后在需要重新使用时,将需要重新使用的部分分开即可。使用较小的方法。

实际上,好的方法设计的一部分是制作功能一致的方法(本质上说,它们只能做一件事)。方法的长度无关紧要。如果一个函数做一个定义明确的事情,并且有1,000行,那么它是一个好方法。如果一个函数执行3或4件事并且只有15行,那么这是一个不好的方法...

6
Cervo

圈复杂度(维基百科):

一段源代码的循环复杂性是通过源代码的线性独立路径数的计数。

  • 我建议您以一种方法将该数字保持在10以下。如果达到10,那么该重新构造了。

  • 有一些工具可以评估您的代码并为您提供圈复杂度数字。

  • 您应该努力将这些工具集成到构建管道中。

  • 不要从字面上追逐方法的大小,而是尝试着看它的复杂性和责任。如果它承担的责任不止一个,那么重构是一个好主意。如果其圈复杂性增加,那么可能是时候进行重构了。

  • 我敢肯定,还有其他工具可以为您提供类似的反馈,但是我还没有机会对此进行研究。

5
CodeART

对我来说,函数的长度是任意的。在大多数情况下,我会重新使用代码。

基本上,我会坚持原则“高内聚,低耦合”,并且长度没有限制。

5
Ross

问题应该是一个函数应该执行多少操作。通常,很少需要100行来完成“一件”事情。再次取决于您查看代码的级别:哈希密码是一回事吗?还是散列和保存密码是一回事?

我会说,首先将密码保存为一项功能。当您觉得哈希不同时,您便重构了代码。我绝对不是专家程序员,但是恕我直言,函数的整体思想从小开始,就是您的函数越原子化,代码重用的机会就越高,而不必在一个以上的地方进行相同的更改等.

我看过 [〜#〜] sql [〜#〜]存储过程 可以运行超过1000行。存储过程的行数是否也少于50?我不知道,但是它使阅读代码变得很糟糕。您不仅需要不断向上和向下滚动,还需要给几行代码起一个名称,例如“ thisvalidation1”,“ this update in database”等,这是程序员应该完成的工作。

5
Narayana

如果可以一次看到整个功能,我发现跟踪自己的工作更容易。因此,这就是我更喜欢编写函数的方式:

  1. 足够短,以适合我的显示器的合理字体。
  2. 如果需要比#1长,则应足够短以便以合理的字体在纸上打印。
  3. 如果需要比#2长,请足够短以在纸上进行2张打印。

我写函数的时间很少超过此。其中大多数是巨大的C/C++开关语句。

5
Bob Murphy

足够短以便正确优化

方法应该简短到可以做一件事。原因很简单:因此可以适当地优化代码。

在Java或C#)这样的JIT语言中,重要的是您的方法必须简单,以便JIT编译器可以快速生成代码。更长,更复杂的方法自然需要更多的JIT时间。而且,JIT编译器仅提供少数优化,只有最简单的方法才能从中受益,甚至在Bill Wagner有效的C#中也提到了这一事实。

在较低级的语言(例如C或C++)中,使用短方法(大约十几行)也很重要,因为这样可以最大程度地减少将局部变量存储在RAM但是请注意,在这种不受管理的情况下,每个函数调用的相对成本可能会很高。

甚至在Ruby或Python)之类的动态语言中,拥有简短的方法也有助于编译器优化。在动态语言中,功能越“动态”,它就越难以实现。例如,一个长方法需要一个X并可能返回一个Int,Float或String,它的执行速度可能会比三个单独返回一个单独类型的方法慢得多,这是因为,如果编译器确切地知道哪种类型函数将返回,它也可以优化函数调用站点(例如,不检查类型转换)。

4
Chris Smith

通常,我尝试使方法/功能保持在1680x1050显示器的屏幕上。如果不合适,请使用辅助方法/函数将任务打包。

它有助于提高屏幕和纸张的可读性。

4
Jason

我对任何事物都没有强加限制,因为某些函数实现的算法本质上是复杂的,任何使它们更短的尝试都会使新的较短函数之间的交互变得如此复杂,以至于最终结果不会降低简单性。我也不相信函数只能做“一件事情”的想法是一个很好的指导,因为在较高抽象级别上的“一件事情”在较低层次上可能是“很多事情”。

对我来说,如果函数的长度引起DRY)的细微违规,则函数肯定会太长,而将函数的一部分提取到新函数或类中可以解决此问题。只要不是这种情况,就可以很容易地提取一个函数或类,这会使代码更加模块化,从而在面对可预见的变更时可能很有用。

4
dsimcha

这很大程度上取决于代码中的内容。

我看过一千行的例程,没有问题。这是一个巨大的switch语句,没有选项超过十几行,并且任何选项中唯一的控制结构是单个循环。如今,它本来是用对象编写的,但那不是当时的选择。

我还在前面的交换机中查看120条线。案件不超过3行-一名后卫,一名任务和一名休息。它在解析文本文件,没有对象。任何其他选择都很难阅读。

3
Loren Pechtel

大多数编译器不介意函数的长度。一个功能应该是有功能的,但对人类来说既易于理解,更改又可以重用。选择最适合您的长度。

2
LennyProgrammers

函数长度可能不是一个很好的指标。我们也尝试在方法上使用 (圈复杂度 ),并且是将来的源代码控制检入规则之一,即类和方法上的圈复杂度必须低于X。

对于方法,X设置为30,这非常紧密。

1
Antonio Bakula

我的一般规则是,功能应适合屏幕。我发现只有三种情况倾向于违反此规定:

1)调度功能。在过去,这些很常见,但是如今大多数都被对象继承所取代。不过,对象仅在程序内部运行,因此,在处理从其他位置到达的数据时,您仍然会偶尔看到调度功能。

2)执行一整套步骤以实现目标的功能,而这些步骤缺少很好的细分。您最终得到的功能只是简单地按顺序调用一长串其他功能。

3)像#2一样,但各个步骤是如此之小,以至于它们只是内联而不是单独调用。

1
Loren Pechtel