Language agnostic 最佳实践:许多小函数/方法,或者更大的函数与逻辑流程组件内联?

Language agnostic 最佳实践:许多小函数/方法,或者更大的函数与逻辑流程组件内联?,language-agnostic,function,Language Agnostic,Function,编写许多小方法(或函数)更好吗,还是简单地将这些小过程的逻辑/代码编写到调用小方法的地方更好?如果把代码分解成一个小函数,即使暂时只从一个地方调用它,那又如何呢 如果一个人的选择取决于一些标准,它们是什么;程序员应该如何做出正确的判断 我希望答案可以普遍应用于多种语言,但如果必要,给出的答案可以针对一种或多种语言。特别是,我想到的是SQL(函数、规则和存储过程)、Perl、PHP、Javascript和Ruby。我总是将长方法分解为逻辑块,并尝试从中生成较小的方法。我通常不会将几行代码转换成一个

编写许多小方法(或函数)更好吗,还是简单地将这些小过程的逻辑/代码编写到调用小方法的地方更好?如果把代码分解成一个小函数,即使暂时只从一个地方调用它,那又如何呢

如果一个人的选择取决于一些标准,它们是什么;程序员应该如何做出正确的判断


我希望答案可以普遍应用于多种语言,但如果必要,给出的答案可以针对一种或多种语言。特别是,我想到的是SQL(函数、规则和存储过程)、Perl、PHP、Javascript和Ruby。

我总是将长方法分解为逻辑块,并尝试从中生成较小的方法。我通常不会将几行代码转换成一个单独的方法,直到我在两个不同的地方需要它,但有时我这样做只是为了提高可读性,或者如果我想单独测试它的话

Fowler's就是关于这个话题的,我强烈推荐它


下面是我在重构中使用的一条简便的经验法则。如果一段代码中有一条注释,我可以将其重新命名为方法名,请将其拉出并使其成为一个方法。

您可以像往常一样说:这取决于具体情况。这更多的是一个命名和定义方法任务的问题。每个方法都应该完成一个(而不是更多)定义良好的任务,并且应该完全完成它们。方法的名称应指示任务。如果您的方法名为DoAandB(),则最好使用单独的方法DoA()和DoB()。如果需要setupTask、executeTask、FinishTask等方法,将它们组合起来可能会很有用

一些观点表明,不同方法的合并可能有用:

  • 如果不使用其他方法,则不能单独使用方法
  • 您必须小心地以正确的顺序调用某些依赖方法
一些观点表明,拆分该方法可能有用:

  • 现有方法的某些行具有明确的独立任务
  • 大方法的单元测试有问题。如果独立方法的测试更容易编写,那么将大方法拆分
作为对单元测试参数的解释:我写了一个方法,它做了一些事情,包括IO。IO部分很难测试,所以我考虑了一下。我得出结论,我的方法有5个逻辑独立的步骤,其中只有一个涉及IO。因此,我将我的方法分为5个较小的方法,其中4个很容易测试。

一些经验法则:

  • 功能的长度不应超过屏幕上显示的长度
  • 如果可以使代码更具可读性,则将函数拆分为更小的函数
就我个人而言,我明显倾向于选择更多、更小的方法,但没有达到宗教上追求最大行数的目的。我的主要标准或目标是保持代码干燥。当我有一个被复制的代码块时(无论是精神上的还是实际上是由文本复制的),即使它可能有2或4行长,我也会将代码分解成一个单独的方法。有时,如果我认为将来很有可能再次使用它,我会提前这样做

另一方面,我也听到有人争辩说,如果你的中断方法太小,在一个开发团队的环境中,一个团队成员可能不知道你的方法,要么写内联方法,要么写他自己的小方法来做同样的事情。无可否认,这是一个糟糕的情况


有些人还试图争辩说,将内容保持在内联状态更具可读性,因此读者可以自上而下地阅读,而不必在方法定义(可能是多个文件)之间跳转。就我个人而言,我认为堆栈跟踪的存在使得这不是什么大问题。

方法越大,测试和维护就越困难。我发现,当一个大过程分解成原子步骤时,理解它是如何工作的要容易得多。此外,这样做是使类具有可扩展性的第一步。您可以将这些单独的步骤标记为虚拟的(用于继承),或者将它们移动到其他对象(组合),使应用程序的行为更易于自定义。

我让每个函数只做一件事,并且我尽量不嵌套太多的逻辑级别。一旦您开始将代码分解为命名良好的函数,它就变得更易于阅读,并且实际上是自文档化的。

方法的大小直接与它的属性相关联

保持方法规模小(即将一个大方法划分为几个小方法)的主要优点是:

  • 更好的单元测试(由于圈复杂度低)
  • 由于更显式的堆栈跟踪(而不是一个巨大方法中的一个错误),因此调试效果更好

我发现拥有许多小方法可以使代码更易于阅读、维护和调试

当我阅读实现某些业务逻辑的单元时,如果我看到一系列描述流程的方法调用,我可以更好地遵循流程。如果我关心该方法是如何实现的,我可以查看代码

这感觉像是做了更多的工作,但最终节省了时间


我认为,知道封装什么是一门艺术。每个人都有一些细微的不同意见。如果我可以用语言来表达的话,我会说每个方法都应该做一件可以描述为一个完整任务的事情。

我通常会将函数拆分为更小的函数,每个函数都执行一个单独的原子任务,但前提是该函数足够复杂,足以完成它

这样,我就不会为简单的任务使用多个函数,而且我提取的函数通常可以在其他地方使用,因为它们不会试图实现太多。这也有助于对每个功能进行单元测试(作为逻辑的atomi)