4 ms·
> Keeping code "clean" is more about how it represents the concepts and relationships it is dealing with and less about whether it follows any specific style ru
by dcolkitt 7y ago
> Keeping code "clean" is more about how it represents the concepts and relationships it is dealing with and less about whether it follows any specific style rules.
I really disagree. To take a prime example, short functions are almost always better than long functions. Regardless of the content, codebases that are refactored into smaller, more self-contained functions almost always improve in reliability, performance, readability, and extensibility.
I think the reason for this largely comes down to reducing the surface area of interactions. A 100 line function can introduce subtle interactions between the first and 99th line. Whereas a three line function, the graph of potential dependencies is much smaller.
A similar logic extends to smaller, more self-contained code blocks, classes, modules and even applications.
- iampims 7y agoBut some other function will need to stitch all the small functions together, and you’re kind of back to square one, no?
- jasonwocky 7y agoNot really, since the dependencies between them are now explicit. Yes the stitching is its own complexity, but divide-and-conquer is a pretty time-honored approach to effective problem solving.
- jcelerier 7y ago> but divide-and-conquer is a pretty time-honored approach to effective problem solving. only if you can also divide and conquer the amount of persons that will dev, because now when there was one name to learn and assign meaning to, there are ten different names. I am speaking as someone who used to have a hard limit on function length (20 lines, in Allman style :-) ) - this ended up being really harmful and creating way too complex code sometimes.
- aluth 7y agoOf course it was harmful, you were focusing on the wrong thing. The point of having methods with no more than [insert number] lines isn't because having a method with more than [insert number] lines is inherently bad. It's because long methods are usually an indication that the method is breaking the single responsibility principle. I get the impression that a bunch of programmers read Robert Martin's work, put no thought into what he was saying about short methods, concluded that the line count was the problem, and began proliferating that idea. To give you an example, when using Java's stream functionality, I tend to insert every method call in the chain after stream() in a new line, for readability: ... entityIds.stream() .map() .filter() .collect(); ... When I scan the method to see if it should be broken down, the fact that this code occupies 4 lines doesn't really contribute much to my decision to refactor the method into several methods, because those 4 lines are accomplishing one thing.
- Floegipoky 7y agoFunction application is THE killer feature
- heisenbit 7y ago> A 100 line function can introduce subtle interactions between the first and 99th line. Whereas a three line function, the graph of potential dependencies is much smaller. Interesting. And what happened with the other 97 lines of code? A fair comparison would be a 100 line function and maybe 20 functions of 5 lines and maybe 20 additional lines for function signatures plus maybe 20 lines coordinating the 20 functions. We also then have introduced 20 function names.
- mumblemumble 7y ago> To take a prime example, short functions are almost always better than long functions. This one is so very disputed, though. My own sense is that it's not the length of the function, it's the length of the loops and the complexity of the branching. Short functions help when they prevent those from occurring. But, in cases where neither is present, I haven't seen a refactoring to short functions that I thought was an unambiguous improvement. Even that variable from line 1 influencing line 99 doesn't end up being particularly difficult to see or understand as long as the control flow is linear.
- dcolkitt 7y agoEven without branching or loops, it's still a problem. Every line in a code block shares a namespace and state-space with each one another. If there's one very consistent lesson in the history of software engineering, it's that state is a necessary evil to be minimized. Stateful code almost always is less reliable and harder to reason about than pure code. Small functions keep the surface area of stateful interactions strictly delineated by the arguments and return parameters. The more lines of code that exist in a block, even with linear control flow, the exponentially higher chance that one line inadvertently clobbers something that subsequent line depends on. Consider a function like def foo (msg: str): head_index = find_header(msg) ... # 50 lines of code log(msg, head_index) ... # 50 lines of code return msg[head_index] Now say somebody adds some chunk of logic in the middle def foo (msg: str): head_index = find_header(msg) ... head_index += offset_digest(...) # Needed for log formatting log(msg, head_index) ... return msg[head_index] A seemingly innocuous change to the function, has inadvertently clobbered the value of a variable we're relying on in a slightly different context. With 50 lines of code separating each reference to the variable, it's very easy for this bug to fly under the radar unnoticed. An engineering culture that emphasized small functions avoids this problem, because the change would instead move the logic to its own self-contained function. That avoids the problem of new code accidentally clobbering the old code. def foo (msg: str): head_index = find_header(msg) ... log_offset(msg, head_index) ... # 50 lines of code return msg[head_index] def log_offset (msg, head_index): head_index += offset_digest(...) log(msg, head_index)
- Silhouette 7y agoTo take a prime example, short functions are almost always better than long functions. This is a popular claim in some circles, but I don't think it stands up to scrutiny. As others have observed, while you may gain locally through having simpler individual functions, you may also lose globally because you now need to manage the complexity of how all those functions relate. There seems to be very little evidence to support the argument that shorter functions are objectively better, and if anything the evidence we do have suggests that extremely short functions are objectively worse in terms of things like defect density. I would rather argue that functions should do one thing well. This will tend to correlate with shorter functions rather than 100+ line behemoths, but the important thing is that a function represent a single, coherent idea. Maybe that idea can be expressed as some neat one-liner in a functional programming language. Maybe it's some 200+ line ordered sequence of conditions that systematically determines how to shift between states in a state machine that is modelling a fundamentally complicated situation.
- Floegipoky 7y agoHot take: the "short functions are better" camp is really just accidentally arguing for pure functions and immutable data. If that 100 line function has 3 side effects and ends up broken into 10 smaller functions, you probably now have at least 7 pure functions.