
Function Length - type0
http://martinfowler.com/bliki/FunctionLength.html
======
Murk
I don't agree entirely with what the article says because it can be a problem
to have to sift though a lot of small functions in order to determine what is
going on. Sometimes, I think it's easier to read a moderately sized, but
"clean" function that you can read from top to bottom, rather than a spiders
web of references to other functions which may contain the nuance or bug you
are looking for. What he has said reminds me of what the Forth community
necessarily espouse, though.

People tend to take the length guidelines far too seriously though. Instead it
requires thought and experience. The main Principe I try to follow is make it
readable, it doesn't matter how it's written or if you've decided to use a
goto in there, so long as it is one of the more readable alternatives.

~~~
mishkovski
There is a less chance to have a bug in a very small function than moderately
sized, but "clean" function.

It is also easier to write a test for a smaller function.

Having the implementation in many smaller functions also makes the code more
readable if their naming is good.

~~~
AnimalMuppet
> There is a less chance to have a bug in a very small function than
> moderately sized, but "clean" function.

Maybe so. But you need _several_ of the very small functions to do the same
work as the moderately sized function, and those several very small functions
have to interact with each other. So did the total chance of a bug go up or
down? It's not clear, but I lean toward the one moderately-sized function
being more likely to be bug-free.

~~~
spronkey
I think realistically in many cases the buggedness will still favour many
smaller functions - if for no other reason than they must all be named.

The higher level function is then easy to read. The lower level functions get
a name that can be checked more easily against an implementation if needed.

------
Terr_
IMO people are mistaking the map for the territory. "Function length" is
actually a proxy for the real things you want to improve, like:

(A) Simplified flows of data in/out rather than a huge complicated input and a
huge complicated output complicated parameter/return data flow

(B) Reusability, since bigger functions are more likely to be "custom fitted"
to a particular purpose.

If your huge function has very simple parameters/returns, and no subparts you
want to reuse, then odds are there's no need to break it apart.

~~~
hellofunk
It's a lot more than these two things, in fact I think these two things are
not as important as the main benefit of smaller functions, which is making
code that is easy to understand at a glance. Good naming with proper
separation of logic into small pieces can make even c++ read almost like
prose. It's hard to find, but when you see it, it always blows me over.

~~~
mannykannot
While I do not disagree with Fowler's criterion as being one of several to
consider, The ability of function (and identifier) naming to make code "easy
to understand at a glance" is frequently overstated, including in this
article. Once code reaches a size where it is moderately complicated, the
reasons for some action being done in a particular way are not necessarily
locally obvious (or obvious at all.) One common reason for this is that things
are being done in a particular way to conform to a contract that is relied
upon in multiple, disparate parts of the program (and any reasonably large
program does have such contracts, even if it was not produced by an explicitly
design-by-contract methodology.)

For a flavor of how this works, read the article [1] below, in response to Tom
Cargill's classic article 'Exception Handling: A False Sense of Security'.
Even though the code example here is small enough to be understood in one go,
I doubt that the reasons for it being the way it is are immediately obvious to
most programmers, unless they have been primed by exposure to the issue before
(note that the first answer given was not entirely correct.)

[1] [http://www.gotw.ca/gotw/008.htm](http://www.gotw.ca/gotw/008.htm)

------
slavik81
I think the thing that really determines whether I break something into a
separate function is state. The more state I have to pass into my function,
the more useful that function has to be to justify its existence.

A good name also helps a lot.

~~~
chillacy
I think refactoring to create a new class is a good solution to the state
problem. That is, if you have code like this:

    
    
        func drive(Engine e, Destination d)
        func park(Engine e)
        func start(Engine e)
    

You can create a new class

    
    
        class Car {
            constructor Car(Engine engine)
            func drive(Destination d)
            func park()
            func start()
        } 
    

Which accepts the shared argument in the constructor. That way within the Car,
you should have minimal state, and defining new functions can reuse the shared
argument that the Car was constructed with: no more long argument lists.

A Car was sort of an obvious example but applying that pattern allows me to
see less obvious examples, where a class is some abstract entity that I wasn't
aware of before.

I think there's still fear of undisciplined state management in large classes,
but that can be addressed with good SOLID class organization.

~~~
Veedrac
Multiple shared parameters up is a strong motivation to create a composite
type, yes, but one should not instantly jump to making the functions methods
of the class. In your example it makes sense, but there are equally many cases
it does not. Shared state and shared behaviour are two entirely independent
concerns.

~~~
chillacy
Yes, I was responding to what I assumed was the parent's concern that passing
state into a function was a hassle. One of the sources which influenced my
tastes is Robert Martin's Clean Code.

------
cdevs
I agree with all of this if the programmer understands when to break off these
functions into a object or abstraction. Other wise you are trying to figure
out how to create a car object and turn it on while passing by all the engine
functions that are parts of the implementation you simply don't care about.
I'm starting to think compiled languages have something else going for them
above interpreted languages as I start to miss reading and writing headers for
how to use my class.

------
melling
I like the small function practice. However, I'd like a better to organize my
code or be able to hide the extra small functions so that they are not visible
when I'm scanning a file to get an overview. I could place them at the bottom
of the file but I prefer to keep them close to where they're called.

~~~
Rotareti
> "I'd like a better to organize my code or be able to hide the extra small
> functions so that they are not visible when I'm scanning a file to get an
> overview."

Most of the _' extra small functions'_ make good reusable utility functions
from which you can build up an external utils lib with different categories
for different functions to keep your main code clean. Reasoning about those _'
extra small functions'_ makes you also become more aware of useful third-party
code, like standard libraries and popular utility libraries. So most of the _'
extra small functions'_ can go into an external lib and the rest goes into
'helpers' or alike. This way you can keep the files which contain the app
logic clean and readable.

------
k__
Once I thought a function should fit on a screen. I did small functions and
tried to use the function names as comment replacement.

But after coming back to old code for years now, I think one big function that
can simply read from top to bottom without any jumps is the way to go.

~~~
spronkey
Hmm. When API naming is good, you shouldn't need to be reading at the low
level much, so IMO whatever makes it easy to skim for maintenance is the way
to go.

------
benjaminjosephw
Garrett Smith did a talk on Writing Quality Code in Erlang[1] which highlights
this priciple of separating intention from implementation. He starts with a 20
line function and refactors it into 16 separate functions. The result is much
more verbose but it's much easier to read, understand and change. I think
terseness rarely does programmers any favours in the long-run.

[1]
[https://www.youtube.com/watch?v=CQyt9Vlkbis](https://www.youtube.com/watch?v=CQyt9Vlkbis)

~~~
lsaferite
It would be interesting to see an IDE that displayed tiny functions inline
(collapsable) in cases like this. This way I get both worlds. Small functions,
but the ability to read the program flow straight through.

------
dfischer
I like the takeaway on reasonability. I've heard mantras on "there's too many
lines of code here, break it up!" but if it reads well on its own then no
worries...

Break things up for reasonability. If there's a bunch happening within a
function body and you can give some semantic meaning to what's going on in
there then go for it.

------
dagw
Here's Carmack's 'counter argument': [http://number-
none.com/blow/blog/programming/2014/09/26/carm...](http://number-
none.com/blow/blog/programming/2014/09/26/carmack-on-inlined-code.html)

------
jpitz
I like this line of thought and to an extent, I agree with it pretty strongly.

I also think that if you are adhering to the notion of a "single level of
abstraction" per function, then you will naturally need to structure your
functions in the way Fowler recommends.

------
jbritton
I once had to work on someone else's function that was several thousand lines
long, written in 'C'. Some of the code blocks went on for pages. The code had
lots of loops and conditionals. The code was nearly impossible to understand.
My first instinct at trying to understand something like this is to break it
down into pieces that I can understand. I like to pull out the body of for
loops. for loops often represent either map(fun, sequence) or filter(fun,
sequence) or fold(fun, sequence). More generally though, I just look for large
code blocks, those delimited by {} and pull those out. If one is familiar with
functional programming, one may recognize the block as some common function,
maybe a partition or a grouping. Functional languages are very good at
abstracting away common patterns. I like to look at a block of code and see if
it matches one of these patterns. With the above large function, pulling
anything out was a huge chore. This was a time before refactoring tools. This
large function had tons of variables, all declared at the top. The scope of
these variables was huge. Pulling out a block requires an analysis of what
goes into the block and comes out of the block. What goes in, is not so hard,
and you can use the compiler to help. What comes out on the other hand was
near impossible. You need to determine if code below the block uses a variable
set inside the block. In a smallish function, no problem, but in the one I was
dealing with, near impossible. Essentially, you had to pass them all out. Only
after tons of further refactoring of pulling out code blocks could one begin
to see whether variables needed to be return values or were simply local temp
variables. By pulling out a block from a large function, one gains a function
that has defined input, defined output, a smaller state space of variables , a
smaller amount of code ranging over the variables, a name, maybe a comment,
and maybe some tests. This function is much more easily understood in this
context than it is as code block in a large function. This large function
showed me in great detail how horrible they truly are. Breaking the large
function into many small ones was the only way to actually understand it. It
turns out that the huge number of local variables were really a union of many
smaller sets. One set may have been completely local to a code block. What
became obvious to me is a kind of complexity measure. The more variables and
the more code ranging over these variables the higher the complexity. I
believe there to be a sort of exponential growth in complexity when adding
variables and code length. When broken down sufficiently, the complexity of
each function can become nearly trivial. One then needs to analyze how a bunch
of trivial functions combine to make the whole. This is a much simpler task
than analyzing the whole when it is one function. I can't prove it, but that
is my experience. I think if one does a little study of a library in a
functional programming language, like Haskell or LISP or Clojure to get a feel
for what makes for a good abstraction, and ever has to deal with a hugely
large function, I don't see how you could not come to the same conclusion that
smaller is better. Can a function be too small? Well, I like this discussion
of intent. Another piece of code that I once looked at had a fairly
complicated expression and involved some bit testing. It was a one liner. Its
purpose was determine if a door was outside of normal working hours. This was
something that could be given a meaningful name as a function, and it is much
better than seeing the ugly expression. So size alone cannot dictate if
something is too small. In general, I think you will instinctively know if
something is too small. If the calling function doesn't become simpler due to
the presence of this other smaller function, then the small function is not
helping. Usually, if I spot this situation, it is an indication that the
problem has not been factored very well. It is like doing a textbook math
problem and getting a weird fractional result. You know you goofed somewhere.
It is time to re-examine the problem for a better solution.

~~~
mavelikara
Is this satire?

------
goldenkek
This article is absolute humdrum. Functions are not the atoms of programs. We
now have classes, lambdas, generators, events, streams, etc.

There are ways to organize code without sticking every little one time used
code into a function.

Poor article by a pseudo computer scientist. Let him keep 'hacking.'

~~~
chillacy
I don't recall the article insinuating that classes/lambdas/etc don't exist,
only that you can break up long functions into smaller functions. Also these
functions are already presumably within a class, since Martin Fowler writes a
lot about Java.

