Ask HN: How to deal with the short vs. long function argument
The short-functions camp holds that functions should be short, tend toward the declarative, and use abstraction/implementation-hiding to increase readability (i.e. separable subsections of the function body should often be broken out into well-named helper functions). As an example, look at Peter Norvig's beautiful https://github.com/norvig/pytudes. For a long time I thought that this was how all "good programmers" thought code should be written. Personally, I spent over a decade writing in a dynamic and untyped language, and the only way that I and my colleagues could make that stuff reliable was to write code adhering to the tenets of the short-function camp.
The long-functions camp is, admittedly, alien to me, but I'll try to play devil's advocate and describe it as I think its advocates would. It holds that lots of helper functions are artificial, and actually make it _harder_ to read and understand the code. They say that they like "having lots of context", i.e. seeing all the implementation in one long procedural flow, even though the local variables fall into non-interacting subsets that don't need to be in the same scope. They hold that helper functions destroy the linear flow of the logic, and that they should typically not be created unless there are multiple call sites.
The short-function camp also claims an advantage regarding testability.
Obviously languages play a major role in this debate: e.g. as mentioned above, untyped dynamic languages encourage short functions, and languages where static compilation makes strong guarantees regarding semantics at least make the long-function position more defensible. Expression-oriented and FP-influenced languages encourage short functions. But it's not obvious, e.g. Rust could go both ways based on the criteria just mentioned.
Anyway, more qualified people could and have written at much greater length about the topic. The questions I'm asking are
- Is it "just a matter of taste", or is this actually a more serious matter where there is often an objective reason for discouraging the practices of one or other camp?
- How can members of the different camps get along harmoniously in the same team and the same codebase?
11 comments
[ 3.3 ms ] story [ 38.4 ms ] threadMy personal preferences is to keep the code base as small as is needed for the moment. I avoid creating functions/methods that are only called once. If possible, (like in C#) I prefer using local methods and lambda expressions. I try to avoid code dupplication (beyond the trivial). I am carefull with introducing abstractions as often it makes it harder to navigate and/or debug the code.
Or do you immediately perform a git blame and confront the developer who wrote the code to lecture them or force them to rewrite the code?
Or do you think: I would not have written it like that and it might result in some technical debt, but at the moment it just works, and I just forget about it for the time being?
If not, then a bit like your last option (forget about it).
But if it is important, then... that's the problem. I consider it a real problem. But it punctures colleagues' egos to have it pointed out that their code, while correct and effective, is actually not very well written. And colleagues in programming tend to have large egos that put up a forceful defense when they are being punctured.
Some languages have block scopes that can make this better; my position is against long functions in languages that lack block scopes or written by programmers that do not avail themselves of block scope.
I really struggle to see why anyone is not attracted to that form of abstraction: if local variable foo is computed in 10 lines using local variables bar, baz, and qux, and those 3 are not used for anything else, then clearly matters are improved in a 100-line function by replacing those 10 lines with
Authors of long functions are not embracing appropriate modularity, but that seems inexplicable, since modularity is the basis of the software revolution.