Live data from Hacker News

Small functions considered harmful

medium.com

41–50 of 121 posts

Re: Small functions considered harmful

#41
post #2

I find a lot to agree with here. It's all very conceptually neat and (if you're lucky) easy to read from the top down, where you enter one function and read off a list of other functions which are called in order. But then if you look into any of those other functions they also call more functions and so on, several levels deep. And when you have to debug someone else's code because the data after function 15 of 17 i…

Wouldn't the compromise be unit testing?

Re: Small functions considered harmful

#44
It seems like the author's idea of the term abstraction is limited to substituting procedures with functions (or worse, class methods). The claims that "all abstractions leak" and that adherence to DRY makes code "hard to follow" is what gives me this impression. This line of thinking happens if you think of code in procedural terms.

And if your sense of abstraction is to hide procedural side-effects behind function applications then yes... I can see where you might get the idea.

A real abstraction like lambda doesn't leak. Using Monads to compose side effects doesn't leak. These are mathematical abstractions and we use them all of the time: even in programming and even if you don't identify as someone who's any good at maths. Learning the lambda calculus, algebra, and first-order logic will take you much farther than thinking in procedural steps.

Composing more interesting functions from smaller ones removes so many errors that procedural code has: removal of superfluous bindings, a more declarative style, and it makes code more more easy to reason about during refactoring: using familiar tools from mathematics we can manipulate expressions and types. This is where abstractions really shine: you can manipulate higher-level expressions without caring about the details of those at the lower level. This only really happens if you care about purity in languages that don't do it for you and can reason using such tools.

Re: Small functions considered harmful

#45
post #39
post #21

Earlier quoted context omitted.

> I have yet to see these dogmatic Clean Coders blindly applying Martin's advice. You're lucky. I've seen it plenty of time. In one extreme case we even had to let go a perfectly (formerly) competent dev after he read that book and went crazy (yeah, seriously).

That is a blog article I would read. Doubly so if it was on Coding Horror.

Or The Daily WTF

Re: Small functions considered harmful

#46
post #5

> The idea that functions should be small is something that is almost considered too sacrosanct to call into question Errr... Really?! I thought we all agreed that the first rule of programming style is that "it depends"... When they say "small functions", they mean "not the 5000 loc VBA macro that has 50 Boolean arguments, and 30 side effects". Breaking a function that does 1 thing into sub functions just so that ea…

My linter throws up a warning if there are more than N lines, M private variables, P branches, or Q return calls (or more than 80 characters in a line. Grr).

So, yeah. People have definitely internalized these as the law and no longer question it.

Re: Small functions considered harmful

#47

This discussion is predicated on the concept that function size is calculated by the number of lines which is completely wrong. function size (function complexity actually) is measured primarily by indent levels not length and when there are multiple indent levels with nested branches and loops this is when you are supposed to create functions. length is not really an issue in most cases.

Most of the arguments in the article are agnostic to the size metric - offhand, I cannot think of any claim that is invalidated by changing to your measure. Furthermore, it is the proponents of short functions quoted in the article who are using line count as a metric, so it is not as if the author of this article has created a straw man by choosing a misleading metric.

Most of the arguments in the article seem agnostic to the size of the function altogether, which is hilariously ironic given the complaint about the "long functions are bad" example at the start of the book.

Re: Small functions considered harmful

#48
If you want to have an easy time refactoring code later, forgo OO patterns that have properties and methods in the same class. Instead, make classes for your data, and make sure to give each class a deep clone method.

Then, your logic goes in static functions that do not alter the input, but rather spit out new or cloned versions of the data in the output. Then you can reason and refactor at the method layer and not worry about hidden side effects.

Re: Small functions considered harmful

#49
post #21
post #20

Earlier quoted context omitted.

Clean Code can be harmful? Or the person dogmatically applying the advice? Martin warns against such blind dogmatism. He even goes so far as to explain the thought process behind most of his recommendations so that one may consider whether the rule applies or not. On balance, Clean Code does far more good than it does bad. I have yet to see these dogmatic Clean Coders blindly applying Martin's advice. Not in industry…

> I have yet to see these dogmatic Clean Coders blindly applying Martin's advice. You're lucky. I've seen it plenty of time. In one extreme case we even had to let go a perfectly (formerly) competent dev after he read that book and went crazy (yeah, seriously).

I'd be interested to see what his code looked like and how the code reviews progressed before firing him. I think these discussions are important, however, we must ground them in a concrete reality. That's what I appreciated about Clean Code, it was grounded in addressing real live code. And the reader is able to choose whether they agree with the conclusions or not.

With that said, all too often, like in this article, we get caught up in cute hypothetical scenarios an examples. There were no real-world examples given, just a bunch of hand-waving.

So in the interest of moving the discussion forward in a concrete way, I'd ask you what you think of these three C lexers; one written in Go by yours truly, GCC's, and LLVM's:

1. https://github.com/denzel-morris/clex/blob/master/lex/lexer....

2. https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/c-family/c-l...

3. https://github.com/llvm-mirror/clang/blob/master/lib/Lex/Lex...

I always find it helpful to look at one problem solved different ways. Of course it's not always apples-to-apples but it's as close as you're going to get. Out of these three codebases, there is probably one you'd feel more comfortable working with. I merely threw mine in there because I wrote it as an exercise on what it'd be like to have a hand-written lexer read more like a story.

It has a focused interface, most functions are descriptively named and operate at a single-level of abstraction, and it's easy to intuit what a C lexer does even if you're not familiar with what they're supposed to do. I'm sure it'd be easy for most people to jump into my code and contribute.

Just like with LLVM's lexer. LLVM is far easier to jump in and contribute to than GCC.

However, and this is just an example that immediately jumps out to me since we're talking about it... doesn't it make sense to have this comment and code abstracted out into a respectively descriptive function instead:

  void Lexer::InitLexer(const char *BufStart, const char *BufPtr,
                     const char *BufEnd) {
    // ...
    // Check whether we have a BOM in the beginning of the buffer. If yes - act
    // accordingly. Right now we support only UTF-8 with and without BOM, so, just
    // skip the UTF-8 BOM if it's present.
    if (BufferStart == BufferPtr) {
      // Determine the size of the BOM.
      StringRef Buf(BufferStart, BufferEnd - BufferStart);
      size_t BOMLength = llvm::StringSwitch(Buf)
        .StartsWith("\xEF\xBB\xBF", 3) // UTF-8 BOM
        .Default(0);
  
      // Skip the BOM.
      BufferPtr += BOMLength;
    }
    // ...
  }
I mean think about it... we're concerned with initializing the lexer, why am I being bothered with this string manipulation minutia to determine whether there's a BOM or not? That could be extracted into a properly named function, the comment eliminated, and then I could trust that that function does exactly what it says on the tin can.

And there's plenty more places where this line of reasoning applies too.

Jekyll (https://github.com/jekyll/jekyll) is another example of a codebase that's very easy to read, work with, modify, etc. It's very well-written. It follows Clean Code like principles where it makes sense.

On the other side of the coin we have Kubernetes (https://github.com/kubernetes/kubernetes) which looks ready to collapse under its own complexity. It's supremely difficult to read and understand what's going on not because of the essential complexity of the problem but because of all the incidental complexity added by the code structure.

I could spend forever citing examples on both sides because I've spent a great deal of time thinking about this and talking with other seasoned developers.

If you (or anyone really) could, please offer up concrete examples grounded in real production code. I'm always interested to see more examples.

Specifically examples blind Clean Code dogmatism applied in the wild.

Re: Small functions considered harmful

#50

It seems like the author's idea of the term abstraction is limited to substituting procedures with functions (or worse, class methods). The claims that "all abstractions leak" and that adherence to DRY makes code "hard to follow" is what gives me this impression. This line of thinking happens if you think of code in procedural terms. And if your sense of abstraction is to hide procedural side-effects behind function…

Arguably lambda, monad, etc. are generalizations, not abstractions: http://www.emu.edu.tr/aelci/Courses/D-318/D-318-Files/plbook...

Abstractions that don't leak aren't abstractions, as the essense of abstraction is the simplification and removal of detail. Monad is a generalization of a pattern seen in many places, so it doesn't have to "leak".

Post reply on HN