【问题标题】:Best practices: Many small functions/methods, or bigger functions with logical process components inline? [closed]最佳实践:许多小功能/方法,还是内联逻辑流程组件的更大功能? [关闭]
【发布时间】:2018-12-01 03:45:37
【问题描述】:

是编写许多小方法(或函数)更好,还是简单地将这些小进程的逻辑/代码直接写入您将调用小方法的地方?即使暂时只从一个地方调用它,将代码分解成一个小函数怎么样?

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

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

【问题讨论】:

  • 拆分有助于代码的可读性。 if(Convert.ToBoolean(row["IsActive"])) 的可读性不如“if(obj.IsActive)”。 :)
  • 嗯。相关 SOF 问题:stackoverflow.com/questions/20981/…
  • 我个人不喜欢代码有很多非常小的函数(1-3 行)只能从一个地方调用(像int foo(){ return do_foo(); } int do_foo(){ /*actual code*/ } 这样的东西是最糟糕的,IMO)然后,要了解实际由这些部分组成的有用功能,我必须追逐每个子功能,它a)很容易迷失在b)容易忽视可能的优化。我会说如果它很好地适合一个屏幕并且没有重复使用的潜力,请不要拆分它。
  • @PSkocik 我发现(使方法更小)的主要好处是它们更容易测试,因为它们的范围/责任更小,并且更容易“融入”人类思维.
  • @Pistos 这是一个平衡。大型单体函数绝对是禁忌,但太多不必要的微函数也会损害可读性——至少对我来说是这样。

标签: language-agnostic function


【解决方案1】:

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

Fowler 的 Refactoring 就是关于这个主题的,我强烈推荐它。

这是我在重构中使用的一个方便的经验法则。如果一段代码有注释,我可以将它改写成方法名称,将其拉出并使其成为方法。

【讨论】:

  • 不能再同意了!! (你的回答救了我一次)
【解决方案2】:

方法的大小直接链接到它的cyclomatic complexity

保持方法体积小(这意味着将一个大方法分成几个小方法)的主要优点是:

  • 更好的单元测试(由于低圈复杂度)
  • 由于更明确的堆栈跟踪(而不是一个巨大方法中的一个错误)而更好地调试

【讨论】:

  • 同意。换句话说,块的深度嵌套使代码难以理解。减少块深度嵌套的一种方法是将一个方法分解为多个更小的方法。还有其他方式,例如提前退货和多次退货。
  • 我不确定功能故障是否会使堆栈跟踪更加明确。 “而不是一个巨大方法中的一个错误” - 错误带有行号以及错误类型和消息的上下文。
  • @methodsignature 14 年后,我认为我当时的意思是,如果较小的方法命名得当(本身就是一个挑战),阅读堆栈跟踪将有助于“讲故事” “我们是如何到达那里的”。与更平坦的堆栈跟踪和巨大函数的代码页面中间的一行相反。
【解决方案3】:

一如既往,您可以说:视情况而定。这更多的是命名和定义方法任务的问题。每种方法都应该完成一个(而不是更多)定义明确的任务,并且应该完整地完成它们。方法的名称应该指明任务。如果您的方法名为 DoAandB(),最好使用单独的方法 DoA() 和 DoB()。如果您需要 setupTask、executeTask、FinishTask 等方法,将它们组合起来可能会很有用。

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

  • 一种方法不能单独使用,而不使用其他方法。
  • 您必须小心以正确的顺序调用一些依赖方法。

一些点表明,方法的拆分可能是有用的:

  • 现有方法的某些行具有明确的独立任务。
  • big 方法的单元测试会出现问题。如果为独立方法编写测试更容易,则将大方法拆分。

作为对单元测试参数的解释:我写了一个方法,它做了一些事情,包括 IO。 IO部分很难测试,所以我考虑了一下。我得出的结论是,我的方法做了 5 个合乎逻辑且独立的步骤,其中只有一个涉及 IO。所以我将我的方法分成 5 个较小的方法,其中 4 个很容易测试。

【讨论】:

    【解决方案4】:

    每次都是小方法。

    它们是自我记录的(呃,如果命名得当的话)

    他们将问题分解为可管理的部分 - 你就是 KeepingItSimple。

    您可以使用 OO 技术更轻松(并且明显地)插入行为。大方法在定义上更具程序性,因此灵活性较差。

    它们是可单元测试的。这是杀手锏,你根本无法对执行大量任务的大型方法进行单元测试

    【讨论】:

    • +1 以简化测试。添加可重复使用的,你就有了一份工作。 :-)
    • 关于“你是 KeepingItSimple”。算法中的方法调用是一种抽象形式,因此比做同样事情但没有这种抽象的算法更复杂。我认为也许将事情放在上下文负载方面是您论点的更好框架。
    【解决方案5】:

    我从 The Code Complete 一书中学到的东西:

    • 编写方法/函数,使其 实现一个块(或单元或任务) 的逻辑。如果这需要分解 进入子任务,然后写一个 为他们单独的方法/功能 并打电话给他们。
    • 如果我发现方法/功能 名字越来越长,然后我尝试 检查方法,看看它可以 分为两种方法。

    希望对你有帮助

    【讨论】:

      【解决方案6】:

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

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

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

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

      【讨论】:

        【解决方案7】:

        一些经验法则:

        • 函数的长度不应超过屏幕可显示的长度
        • 如果可以使代码更具可读性,请将函数分解为更小的函数。

        【讨论】:

        • 您的第一条评论在大多数情况下都会起作用,但我有一个 30 英寸的屏幕。另外,我看到一位同事的显示器垂直转动。所以我认为需要一个新的经验法则。
        【解决方案8】:

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

        【讨论】:

          【解决方案9】:

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

          【讨论】:

            【解决方案10】:

            我通常会将函数拆分为更小的函数,每个函数执行一个单一的原子任务,但前提是该函数足够复杂以保证它的安全。

            这样,我最终不会为简单的任务提供多个函数,而且我提取的函数通常可以在其他地方使用,因为它们不会尝试实现太多。这也有助于单元测试,因为每个功能(作为一个逻辑的、原子的操作)都可以单独测试。

            【讨论】:

              【解决方案11】:

              这有点...取决于心态。不过,这不是一个固执己见的问题。

              答案实际上取决于语言上下文。

              在 Java/C#/C++ 世界中,人们遵循 Robert Martin 所宣扬的“清洁代码”学派,那么:许多小方法是必经之路。

              一个方法有一个明确的名字,只做一件事。一层嵌套,就是这样。这将其长度限制为 3、5、最多 10 行。

              老实说:我发现这种编码方式绝对优于任何其他“风格”。

              这种方法的唯一缺点是您最终会得到许多小方法,因此文件/类中的排序可能会成为一个问题。但答案是使用一个体面的 IDE,它可以轻松地来回导航。

              因此,使用“所有东西都集中在一个方法/函数中”的唯一“合法”理由是当您的整个团队都这样工作并且更喜欢这种风格时。或者当你不能使用像样的工具时(但是导航那个又大又丑的功能也不起作用)。

              【讨论】:

                【解决方案12】:

                就个人而言,我明显倾向于使用更多、更小的方法,但并没有达到虔诚地追求最大行数的地步。我的主要标准或目标是保持我的代码干燥。一旦我有一个重复的代码块(无论是在精神上还是实际上是由文本),即使它可能是 2 或 4 行长,我也会将该代码干燥到一个单独的方法中。如果我认为将来很有可能再次使用它,有时我会提前这样做。

                另一方面,我也听说过,如果你的中断方法太小,在一个开发团队的环境中,一个队友可能不知道你的方法,要么会写 inline ,或者编写他的自己的小方法来做同样的事情。诚然,这是一个糟糕的情况。

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

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2013-05-08
                  • 1970-01-01
                  • 1970-01-01
                  • 2013-08-01
                  • 2012-09-10
                  • 1970-01-01
                  • 2017-08-30
                  • 1970-01-01
                  相关资源
                  最近更新 更多