1. 31
  1. 17


    Function and line length are very weak proxies for complexity, and often counterindicated. For example, as danburzo notes, breaking up a long function into smaller functions purely to satisfy this rule, i.e. smaller functions that are only called by one other function, more often than not makes things worse, not better.

    1. 9

      I feel like “write small methods” has been drilled into so many engineers these days that it usually tends to go in the opposite direction, with tons of nested 5-10 line functions that make debugging difficult. As an alternative, I like John Ousterhout’s philosophy of writing deep modules/classes/functions (small interface, lots of functionality).

      1. 3

        That link is superb. I particularly like the emphasis on minimal interfaces. Committing to the fewest number of simple interfaces necessary really cuts down the design space to be considered.

      2. 9

        Obligatory link to John Carmack’s email on how you should do the exact opposite of what this post recommends.

        you should be made constantly aware of the full horror of what you are doing.

        1. 3

          you should do the exact opposite of what this post recommends.

          For effectful code, not as a universal maxim.

        2. 8

          I’m curious whether this sort of advice is more prevalent in languages more likely to be consumed in IDEs rather than simpler text editors. I tend to find small, one-off functions more frustrating than a longer function (with comments optionally dividing it into sections) when I can’t rely on code navigation to follow along.

          1. 7
            1. 4

              It bothers me when languages handle “break down code” as “make more function calls”. You just want to split fooBarBaz(); into foo(); bar(); baz();, but now you’ve got 3 function calls, stupidly-deep stacktraces, more jumps, more stack frame bookkeeping, &c. A function is overkill—I just want to write a subroutine of some sort. But if you actually use the preprocessor to keep it DRY, people look at you like you’re crazy (#define FOO ..). You want to inline it, but then you get told you’re doing the compiler’s job (and you’re not as good). I’ve always kinda been low-level frustrated by that, especially after first experiencing Java stacktraces then learning about x64 function call prologue/argument handling/register saving. I like having available the more straightforward replacement you see in assembler, like with NASM macros, where you can choose to write functions if you want to or stay funcall-free.

              EDIT: I should be clear, the Java VM does not necessarily obey x64 conventions, but spending in the DRY direction while expensing the funcalls as zero-cost doesn’t sit right w/ me

              1. 1

                Until we manage to define code readability objectively, with some kind of unit of measure directly corresponding to brain cycles or something, I don’t see the point following any rules like this.

                If a chunk of code took too much time or effort to understand, it probably wasn’t because it was 25 lines long. Size is a symptom and there’s always a less superficial reason. No code exists in a vacuum; you can’t just glance at it and tell how difficult it will be to grok. At $job, understanding inscrutable functions of “reasonable” size has often involved delving into up to half a dozen other projects!

                Also, seeing as F# was mentioned in passing, I’ve seen and written plenty of multi-dozen-line behemoths in F# that have remained reasonable to understand, often thanks to judicious use of nested functions and commentary.