5 ms·
It occurs to me that author refutes one dogma (make functions as small as reasonably possible) only to propose another dogma (small functions are harmful). No t
by manmal 9y ago
It occurs to me that author refutes one dogma (make functions as small as reasonably possible) only to propose another dogma (small functions are harmful). No thanks, I will continue improving my style such that it matches my abilities, and hopefully also the abilities of people reading my code.
Since I'm in the position to use Swift, I often define small functions WITHIN functions, in order to give the behavior of a code block a name. I'm also using LOTS of immediately executed closures (is that the correct term?) to reduce scope and profit from slightly easier control flow. And I don't see how this would be bad.
Meta: I thought we were over this dogma thing. I watched the TDD thing become popular, and then fall from grace - why do people still need to pretend they know better than me, the reader? Do they want to become gurus, or do they soothe their own feeling of "doing it wrong"?
- falcolas 9y ago> why do people still need to pretend they know better than me, the reader Perhaps they do? Or perhaps they just see a trend starting up in their day-to-day work and want to try and nip it in the bud? I see this exact same trend forming: in my last code review I saw a function which had exactly one line of code in it - a string format operation. It was called twice, and had no likelihood to be called more. That was the most gregarious, but not the only, example. > And I don't see how [lots of small functions] would be bad. Well, I am not sure about Swift's implementation, but functions are typically expensive to execute. They require pushing values onto the stack, switching control, executing code, popping values off the stack, switching control back, etc. Lots of CPU operations and memory manipulation (not to mention cache misses, etc). There's also the possibility of blowing out your stack if you store too many values on it, or nest too deeply. From a cognitive point of view, you have to interrupt your current flow of reading, move to a different spot in the current file (or another file entirely), to track down the behavior of a certain function. As the functionality of that function mutates over time, its name is rarely changed to reflect the updated functionality, which means it can create confusion and require even more time to consider the corner cases.
- Tarean 9y agoYou are not going to blow your stack without recursion, even with a fairly small stack size. Iirc swift has huge stacks for objective-c interop by default so even that shouldn't be a problem. Overhead is a fair point for jit/interpreted languages if you want to write performance critical code in a jit/interpreted language for some reason. Tiny functions are almost certainly going to be inlined if the compiler does its job, though, so it isn't a huge deal for compiled languages. And the point is that the function can be so tiny that you would just replace it with a new function. Then you can reason locally about behavior. This is a very functional approach, though, and can break horribly in imperative languages so there definitely is a balance.
- falcolas 9y ago"Almost certainly" means that there will be a number of times where they "almost certainly" will not. Inlining is hard (especially with languages which allow for overriding functions), and is not done perfectly (or at all). The LLVM compiler toolchain in particular has a lot of properties which can inhibit inlining code; and in some cases you even have to explicitly tell the LLVM compiler when it can inline a function.
- timrichard 9y agoI know exactly where you're coming from... I worked at one place where, during pairing, there was pressure to place a single line of code in its own function. Just so that function name could be coerced into being a sort of comment, as comments themselves anywhere under any circumstances were "bad practice". I put it down at the time to Uncle Bob Cargo Cultism, but found it a bit irritating nonetheless. Similarly annoying that the linter would reject a commit because a function had more than 14 lines of code in it. Under any circumstances. However, I've been recently delving into some styleguides, and thought I'd refactor a web app server according to principles in the styleguide. So the first pageful is more of an Executive Summary of the module, and everything happens in functions below the fold. As everything wasn't nested more than a couple of levels deep, I was quite pleased with the results. Unlike the crazy level of nesting on the previous project, where I was doing as much branching as the CPU just in order to read the stuff. I suppose it's the same old, same old; a little is great, a lot is harmful.
- majewsky 9y ago> Since I'm in the position to use Swift, I often define small functions WITHIN functions, in order to give the behavior of a code block a name. I'm also using LOTS of immediately executed closures (is that the correct term?) to reduce scope and profit from slightly easier control flow. And I don't see how this would be bad. You don't need a language with closures even. Many C-style languages [1] allow you to add curly braces around a couple of statements without using any other control structure (if, for, while, etc.), just to force variables declared inside this block to go out of scope at the end of the block. I've used this for complex functions that do not lend itself to useful modularization, to indicate which variables are short-lived, and which are carried forward to later parts of the function.) [1] e.g. C++, Perl; not sure about C itself