函数应该多短?

发布于 2024-10-12 02:43:07 字数 828 浏览 5 评论 0原文

我在这里做了一些搜索,但没有找到类似的东西,所以我要继续询问。这实际上更多地是关于语义而不是实际的编程问题。我目前正在用 C++ 写一些东西,但语言并不重要。

我很清楚,保持函数/方法尽可能短是良好的编程习惯。然而,你如何真正知道函数是否太长呢?或者,是否有可能过度分解功能?

我学的第一种编程语言(Applesoft BASIC 除外,这不算……)是 6502 汇编语言,速度和优化就是一切。如果几个周期计数搞乱了整个程序的时序,通常最好直接设置内存位置或寄存器,而不是跳转到另一个子例程。前一个操作可能需要 3 或 4 个周期,而后者总共可能需要两到三倍的时间。

虽然我意识到现在如果我向一些程序员提及周期计数,他们只会茫然地看着我,但这是一个很难改掉的习惯。

具体来说,假设(再次使用 C++)我们有一个私有类方法,如下所示:

int Foo::do_stuff(int x) {
    this->x = x;
    // various other operations on x
    this->y = this->x;
}

我已经看到一些论点,至少每组操作都应该是它自己的函数。例如,do_stuff() 理论上应该命名为 set_x(int x),应该为对类成员 x 执行的操作集编写一个单独的函数,并且应该编写第三个函数来分配类成员的最终值x 给班级成员 y。但我看到其他论点认为每个操作都应该有自己的功能。

对我来说,这似乎是错误的。再说一遍,我是从内部的角度来看待事物的。每个方法调用都会将一个地址压入堆栈,执行其操作,然后从子例程返回。对于相对简单的事情来说,这似乎是很大的开销。

这类事情是否有最佳实践,还是更取决于个人判断?

I did some searching on here and haven't found anything quite like this, so I'm going to go ahead and ask. This is really more about semantics than an actual programming question. I'm currently writing something in C++ but the language doesn't really matter.

I'm well aware that it's good programming practice to keep your functions/methods as short as possible. Yet how do you really know if a function is too long? Alternately, is it ever possible to break functions down too much?

The first programming language I learned (other than Applesoft BASIC, which doesn't count...) was 6502 assembly language, where speed and optimization is everything. In cases where a few cycle counts screws up the timing of your entire program, it's often better to set a memory location or register directly rather than jump to another subroutine. The former operation might take 3 or 4 cycles, while, altogether, the latter might take two or three times that.

While I realize that nowadays if I were to even mention cycle counts to some programmers they'd just give me a blank look, it's a hard habit to break.

Specifically, let's say (again using C++) we have a private class method that's something like the following:

int Foo::do_stuff(int x) {
    this->x = x;
    // various other operations on x
    this->y = this->x;
}

I've seen some arguments that, at the very least, each set of operations should be its own function. For instance, do_stuff() should in theory be named to set_x(int x), a separate function should be written for the set of operations performed on class member x, and a third function should be written to assign the final value of class member x to class member y. But I've seen other arguments that EVERY operation should have its own function.

To me, this just seems wrong. Again, I'm looking at things from an internal perspective; every method call is pushing an address on the stack, performing its operations, then returning from the subroutine. This just seems like a lot of overhead for something relatively simple.

Is there a best practice for this sort of thing or is it more up to individual judgment?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

心是晴朗的。 2024-10-19 02:43:07

自 6502 汇编时代以来,发生了两件事:计算机变得更快,编译器(在适当的情况下)变得更加智能。

现在的建议是停止花费所有时间担心各个周期,直到您确定这是一个问题。您可以更明智地度过这段时间。如果你向我提到周期计数,我不会茫然地看着你,因为我不知道它们是什么。我会看着你,想知道你是否在浪费你的努力。

相反,开始考虑让你的函数足够小,以便:

  • 可理解、
  • 可测试、
  • 可重用,也许,在适当的情况下。

如果稍后您发现某些代码运行得不够快,请考虑如何优化它。

注意:优化可能会提示编译器将函数内联移动,因此您仍然可以获得上述优点,而不会影响性能。

Since the days of 6502 assembly, two things have happened: Computers have got much faster, and compilers (where appropriate) have become smarter.

Now the advice is to stop spending all your time fretting about the individual cycles, until you are sure that it is a problem. You can spend that time more wisely. If you mention cycle counts to me, I won't look at you blankly because I don't know what they are. I will look at you wondering if you are wasting your effort.

Instead, start thinking about making your functions small enough to be:

  • understandable,
  • testable,
  • re-usable, maybe, where that is appropriate.

If, later, you find some of your code isn't running fast enough, consider how to optimise it.

Note: The optimisation might be to hint to the compiler to move the function inline, so you still get the advantages above, without the performance hit.

向日葵 2024-10-19 02:43:07

决定在何处分解函数时最重要的事情不一定是函数的功能。。它更重要的是确定你的类的 API。

假设我们将 Foo::do_stuff 分解为 Foo::set_xFoo::twiddle_xFoo::set_y >。单独进行这些操作是否有意义?如果我在没有先设置的情况下调整 x ,会发生什么不好的事情吗?我可以在不调用 set_x 的情况下调用 set_y 吗?通过将它们分解为单独的方法,甚至是同一类中的私有方法,您暗示它们至少可能是单独的操作。

如果情况并非如此,那么请务必将它们保留在一个函数中。

The most important thing about deciding where to break up a function is not necessarily how much the function does. It is rather about determining the API of your class.

Suppose we break Foo::do_stuff into Foo::set_x, Foo::twiddle_x, and Foo::set_y. Does it ever make sense to do these operations separately? Will something bad happen if I twiddle x without first setting it? Can I call set_y without calling set_x? By breaking these up into separate methods, even private methods within the same class, you are implying that they are at least potentially separate operations.

If that's not the case, then by all means keep them in one function.

も星光 2024-10-19 02:43:07

我很清楚这很好
编程练习以保持您的
函数/方法尽可能短

我不会使用上述标准将我的函数重构为更小的函数。下面是我使用的

  1. 保持所有功能处于同一水平
    抽象
  2. 确保有
    无副作用(对于特殊情况
    案例确保明确
    记录它们)
  3. 确保一个函数只做一件事(SRP 原则)。但您可以打破这一点以兑现 1.

其他方法设计的良好实践

  1. 让客户做任何事情
    模块可以
  2. 不违反最小原则
    令人惊讶的
  3. 快速失败——尽快报告错误
    发生过载后可能会
  4. 小心
  5. 使用适当的参数和返回类型
  6. 使用一致的参数顺序
    跨方法
  7. 避免长参数列表
  8. 避免要求的返回值
    卓越的加工工艺

I'm well aware that it's good
programming practice to keep your
functions/methods as short as possible

I wouldn't use the above criteria to refactor my functions to smaller ones. Below is what I use

  1. Keep all the functions at same level
    of abstraction
  2. make sure there are
    no side effects (for exceptional
    cases make sure to explicitly
    document them)
  3. Make sure a function is not doing more than one thing (SRP Principle). But you can break this to honor 1.

Other good practices for Method Design

  1. Don't Make the Client Do Anything the
    Module Could Do
  2. Don't Violate the Principle of Least
    Astonishment
  3. Fail Fast–Report Errors as Soon as
    Possible After They Occur
  4. Overload With Care
  5. Use Appropriate Parameter and Return Types
  6. Use Consistent Parameter Ordering
    Across Methods
  7. Avoid Long Parameter Lists
  8. Avoid Return Values that Demand
    Exceptional Processing
我的痛♀有谁懂 2024-10-19 02:43:07

阅读《干净的代码:敏捷软件工艺手册》 几乎涉及了本页上的每一条建议,我开始写得更短。不是为了拥有简短的函数,而是为了提高可读性和可测试性,将它们保持在相同的抽象级别,让它们只做一件事,等等。

我发现最有价值的是我发现自己编写的文档少了很多因为我 80% 的功能都不需要它。当函数只执行其名称所示的功能时,就没有必要重述明显的内容。编写测试也变得更容易,因为每个测试方法可以设置更少并执行更少的断言。当我牢记这些目标重新审视过去六个月编写的代码时,我可以更快地做出我想要的更改并继续前进。

After reading Clean Code: A Handbook of Agile Software Craftsmanship which touched on almost every piece of advice on this page I started writing shorter. Not for the sake of having short functions but to improve readability and testability, keep them at the same level of abstraction, have them do one thing only, etc.

What I've found most rewarding is that I find myself writing a lot less documentation because it's just not necessary for 80% of my functions. When the function does only what its name says, there's no point in restating the obvious. Writing tests also becomes easier because each test method can set up less and perform fewer assertions. When I revisit code I've written over the past six months with these goals in mind, I can more quickly make the change I want and move on.

冰雪之触 2024-10-19 02:43:07

我认为在任何代码库中,出于所有众所周知的原因,可读性比多几个时钟周期更重要,最重要的是可维护性,这是大多数代码花费时间的地方,因此大多数钱都花在了代码。所以我想回避你的问题,说人们不关心这个问题,因为与其他[更多企业]关注的问题相比,它可以忽略不计。

尽管如果我们把其他问题放在一边,有显式的内联语句,更重要的是,编译器优化通常可以消除与琐碎函数调用相关的大部分开销。编译器是一个非常智能的优化机器,并且通常会比我们更智能地组织函数调用。

i think in any code base, readability is much greater a concern than a few more clock cycles for all the well-known reasons, foremost maintainability, which is where most code spends its time, and as a result where most money is spent on the code. so im kind of dodging your question by saying that people dont concern themselves with it because its negligible in comparison to other [more corporate] concerns.

although if we put other concerns aside, there are explicit inline statements, and more importantly, compiler optimisations that can often remove most of the overhead involved with trivial function calls. the compiler is an incredibly smart optimising machine, and will often organise function calls much more intelligently than we could.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文