29

Imagine a long and complicated process, which is started by calling function foo(). There are several consecutive steps in this process, each of them depending on result of the previous step. The function itself is, say, about 250 lines. It is highly unlikely that these steps would be useful on their own, not as a part of this whole process.

Languages such as Javascript allow creating inner functions inside a parent function, which are inaccessible to outer functions (unless they are passed as a parameter).

A colleague of mine suggest that we can split up the content of foo() into 5 inner functions, each function being a step. These functions are inaccessible to outer functions (signifying their uselessness outside of the parent function). The main body of foo() simply calls these inner function one by one:

foo(stuff) {
    var barred = bar(stuff);
    var bazzed = baz(barred);
    var confabulated = confabulate(bazzed);
    var reticulated = reticulate(confabulated);
    var spliced = splice(reticulated);

    return spliced;

    // function definitions follow ...
}

Is this an anti-pattern of some sort? Or is this a reasonable way to split up long functions? Another question is: is this acceptable when using OOP paradigm in Javascript? Is it OK to split an object's method this way, or does this warrant another object, which contains all these inner functions as private methods?

See also:

Stas Bichenko
  • 3,689
  • 4
  • 24
  • 32
  • 4
    How is this different from the earlier question? Just by being in JavaScript with its peculiar object model? – Kilian Foth Aug 11 '14 at 09:06
  • 1
    @KilianFoth The previous question was motivated by perceived "callability" of the smaller methods into which the original method was split up. When using inner functions, the programmer seems to be able to indicate a more narrow scope for a function. I wanted to see whether there are significant drawbacks to this. In particular, janos notes that these functions may be hard to test. – Stas Bichenko Aug 11 '14 at 09:15
  • 1
    Your specific example has hints of an anti-pattern called [sequential coupling](http://en.wikipedia.org/wiki/Sequential_coupling), but it may be the correct way to go given the specific algorithm involved - or there could be a better way to split your code into different functions that reads better. – Izkata Aug 11 '14 at 13:55
  • The stacktrace let you faster find the Problem. – Grim Aug 11 '14 at 16:17
  • Break them up. But do it by re-ordering lines of code to minimize the scope of variables; then extracting into a function name that serves as a comment. If you have a giant function, then diffs and merges get disturbed for no good reason; such as pointless white-space changes due to re-indentation. Functions can have clear preconditions, postconditions, mutability and functional guarantees, and a clear name. When I first started programming, I also used to believe what the poster suggests; but big functions are very good at hiding long lived bugs. – Rob Aug 11 '14 at 19:26
  • If the code should be in multiple functions, then put it in multiple functions. Otherwise, don't. Splitting code into multiple functions when it belongs in one function, because someone arbitrarily decided on a function length limit, is definitely an anti-pattern. – user253751 Aug 12 '14 at 10:05

8 Answers8

51

Inner functions are not an anti-pattern, they are a feature.

If it doesn't make sense to move the inner functions outside, then by all means, don't.

On the other hand, it would be a good idea to move them outside so you can unit test them easier. (I don't know if any framework lets you test inner functions.) When you have a function with 250+ lines, and you make any changes in the logic, are you sure you're not breaking anything? You really need unit tests there, and it won't be feasible with one giant function.

Splitting up long functions to smaller ones is a good idea in general. It's a common refactoring technique to replace a comment with a function named after the comment, called "extract method". So yes, do it!

As @Kilian pointed out, see also this related post:

Should I place functions that are only used in one other function, within that function?

janos
  • 1,829
  • 13
  • 30
  • 2
    [See also](http://programmers.stackexchange.com/questions/252532) for where to put the smaller functions. – Kilian Foth Aug 11 '14 at 09:19
  • 2
    The big problem with inner function is scope. You cannot Unit-Test them individually, you can not easily reuse them and you have no overview what side-effects they have. Inner functions are like GOTO-Labels, and name shadowing can become horrible... – Falco Aug 11 '14 at 13:38
  • 2
    @Falco: Inner functions are not goto's, they are functions, just like any other function. They are gosubs, if you like. Side-effects are part and parcel of OOP; if you don't like them, the answer is to write in functional style; merely making your methods public won't get it done. Inner functions are encapsulated, so naming problems should be *less* difficult, not more. – Robert Harvey Aug 11 '14 at 15:42
  • 1
    @Janos: Visual Studio's Unit Testing Framework can test inner functions. It would surprise me if it's the only testing framework that can. – Robert Harvey Aug 11 '14 at 15:44
  • But, you are acheiving nothing other than a decrease in readability (because now you have to look around a lot) and *pushing the stack* when you don't need to. You're creating a performance problem that doesn't need to be there - it's small, but it's completely unnecessary. Scale that up to thousands of machines and you have a serious issue. – user1068 Aug 11 '14 at 17:26
  • 3
    @user1068: If this is the sort of application where function calls negatively impact performance, something else is wrong. Also, it hurts readability in no way; you know from good naming whether or not you need to look into a function. Your way, taken to extremes, results in having no functions , which is generally considered to be a bad idea. – Magus Aug 11 '14 at 18:43
  • Taking anything to extremes is probably always a bad idea. I'm just playing devil's advocate. Experienced programmers know you can't apply a rule here. You must consider the effects of pushing the stack, and creating more jumping around in the code to read things - if you need to understand this function, you now have a tree to understand on top of that. If we're talking about some complicated math, I would not appreciate that. It's a trade off, and I just didn't like the fact nobody seems to consider what we're trading. – user1068 Aug 11 '14 at 18:58
  • @user1068: As with most people who take that stance, you assume one must understand the whole tree because it is still one method, just moved around. This is not true. You now have several named methods. They should all be black boxes. You should only read into them if needed. – Magus Aug 11 '14 at 19:12
  • I would not test private functions: you only want to test the externally visible behaviour of a piece of code. On the other hand, it is likely that a 250-line function does not follow the single-responsibility principle, and therefore (at least some of) its internal functionality should actually be in public (and therefore testable) functions. – Giorgio Aug 11 '14 at 19:20
  • Right, but where is the mention of that in the answer? The answer is saying "always do this if it can be tested" but that's far from correct. I could list a bunch of cases where extracting a function isn't the right way to go and the answer gives no guidance on that issue. One of the primary cases for not creating a function is the exact situation the OP mentioned, and to say the OP's feeling is completely wrong is missing the point. He's totally correct in having this feeling and this is the time for an intelligent decision, not application of an "always" rule. – user1068 Aug 11 '14 at 20:55
  • I paraphrase, but yes, the answer reads as if it should always be done if it's logically sound. – user1068 Aug 11 '14 at 22:28
15

It's not an anti-pattern. It's the right way to do it.

It's easier to read, to maintain, to test. It helps avoid duplication.

See : clean code (the bible for devs) and this answer

Maxime ARNSTAMM
  • 307
  • 1
  • 4
  • 5
    This is part of the Single Responsibility Principle. Each method should only have a single responsibility - in this case, breaking a long method up into smaller methods is exactly the right thing to do. – Steve Hill Aug 11 '14 at 08:41
  • 15
    this reads more like an opinion, lacking an explanation. Links don't help either, first one is to the book at Amazon (it's large, do you suggest one to read it all to answer specific question?) and link labeled "answer" actually leads to a question. Consider [edit]ing into better shape. See [answer] – gnat Aug 11 '14 at 08:58
  • 3
    I would say that breaking a large method up into various small methods and then invoking all of those methods inside of the large method - and assuming the small methods are private - is not adhering to the SRP because the large method *is still performing multiple responsibilities*. If you refactored the small methods out into dependencies then you could argue that the method is then being a facade, but if the small methods are encapsulated inside the large one, you are really still violating SRP – Dan Aug 11 '14 at 10:48
  • 3
    If you think Clean Code is "the bible for devs", you should read [Code Complete](http://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670). – Mike Partridge Aug 11 '14 at 12:56
  • 1
    IMHO you missed the point of the OP - he is not asking if a big function should be split up into smaller functions, he is asking if this should be done by using *inner* functions. – Doc Brown Aug 11 '14 at 14:40
  • 1
    Code Complete is indeed a great resource, and it suggests doing the same thing as Clean Code, in this instance. See [Valid Reasons to Create a Routine](http://www.stevemcconnell.com/cchqsub.htm), especially the section called "Making a section of code readable". – Eric King Aug 11 '14 at 15:28
  • This doesn't even attempt to answer the question at hand. The question is about inner functions, not splitting large functions/methods into multiple smaller ones. – Davor Ždralo Aug 12 '14 at 10:45
5

The most important issue is to manage complexity. Inner methods are one of the solutions, but I'm not convinced that a best one.

You want to split the method because it's long, but with inner methods the method is still long, just divided into "chapters". It's better than "comment chapters", though.

A better solution is to use an inner class that gathers all of the helper methods and - what is also important - data. Additionally, this class can be unit tested separately.

This is a variation of Fowler's "Replace Method with Method Object" refactoring.

andrew.fox
  • 535
  • 3
  • 14
  • "Replace Method with Method Object" doesn't make sense in Javascript, since methods are functions and functions are objects. Also, there are no classes; although some people approximate them using functions. Your suggestion sounds like it would introduce a bunch of boilerplate for no gain. – Warbo Aug 12 '14 at 15:59
  • @Warbo I disagree. Classes are easily and routinely implemented in Javascript. Properly declared, a method object would provide better encapsulation and testability. – Stas Bichenko Aug 13 '14 at 07:16
  • 1
    @Warbo - The question was about OOP paradigm in JavaScript. It's true that in JS "everything" is an object and it's rather prototype based language than a classical OO one. But it shouldn't stop anyone from using proven OO techniques. Proven patters are easy to maintain. – andrew.fox Aug 13 '14 at 10:10
3

It's not an anti-pattern, but it's a questionable move. If those functions are not valuable outside their parent function, there is no benefit of separating them, just more code. You could just put some comments in code saying "now we confabulate previously buzzed thingy", and it would have same value in less lines of code.

EDIT: I'd rephrase my answer, because I've used not very careful wording there, and, apparently, community didn't accept it, based on downvotes. What I really wanted to say is that one should take into account the amount of extra code and attention breaks while reading. When the original function is small enough (how small is opinion-based), it could be easier to read it as one stream of text with some helping comments, than jumping back and forth between inner functions. It could easily be that one chunk of code is easier to read and understand than a collection of several functions.

On the other hand, when the original function is big enough to understand as one piece, it totally makes sense to split it. Principle of lesser scope definitely comes into play here. It's just important to understand when the function is "big enough" for that. It's easy to make such judgement when the original one is 10k LOC, as was commented, but what about the OP's example, 250 LOC? I'd say it's becoming opinion-based to give as an answer.

Haspemulator
  • 456
  • 2
  • 7
  • 5
    Disagree. That's like saying "oh don't split up this 10k LOC function into smaller ones because you only call each one once". And about whether inner functions are better than external ones, you need some really good arguments for why "smaller scope is better" shouldn't hold here. – Voo Aug 11 '14 at 09:48
  • In case of bigger functions the argument of adding up lines of code for inner functions doesn't matter anymore, because the ratio of "wasted" lines on function declaration is small. But in case of smaller ones one should carefully weigh the benefits of readability against deficiencies of extra code. It's opinion-based and the programmer should decide every time by him- or herself what to do. I'm just adding amount extra code lines into consideration by my answer. – Haspemulator Aug 11 '14 at 09:59
  • 1
    The benefit is to make code easier to read and more maintainable. following logic through a large function is more difficult than tracing through several small functions. – Jaydee Aug 11 '14 at 10:00
  • 3
    @Jaydee, I'd argue that. Following one stream of text is easier than jumping around several functions back and forth, trying to understand their meaning and relations. Of course, it's again the matter of the actual size. If the function text small enough (say, fits your display height, but that's opinion based again), it's easier to just read it as one piece. – Haspemulator Aug 11 '14 at 10:03
  • 2
    "jumping around several functions back and forth, trying to understand their meaning and relations"-in that case the problem is how you split up the functions, the naming and possibly documentation. You should be able to understand each function on its own, considering the other ones as blackboxes with documented behavior. Having to understand 3 small functions that do a single thing, is just plain easier than understanding one giant function even if it fits on one screen (hey I have a 30" monitor, so that's actually really long). Cost? Overhead of 2 line per function declaration - negligible. – Voo Aug 11 '14 at 10:26
  • 16
    Reading a series of meaningful function names {loadData(); doCalculation(); printData();} is far more readable than figuring out what each section of code does each time you read it. Most compilers will inline the functions during optimization so there is no performance loss. – Jaydee Aug 11 '14 at 10:53
  • 1
    To follow-up on what @Jaydee said, once you find the problem function, you can focus your attention and testing just on that piece. There would be no need to "jump back" to the main function. – JeffO Aug 11 '14 at 12:51
2

It is certainly better to keep each "inner function" separate: small, combinable parts are much easier to maintain than monolithic "big balls of mud". Be careful with your terminology though: functions and methods aren't the same thing, from a stylistic point of view.

Methods tend to favour one object ("this") above others, which limits their usefulness to that object. Functions are independent of any particular value, which makes them more flexible and easier to combine together.

In this case, your "foo" function is clearly the composition of those "internal functions", so you might as well define it that way and avoid all of the intermediate boilerplate ("stuff", "barred", "bazzed", "confabulated", "reticulated", "spliced", "function(stuff) {" and "return ...; }"):

var foo = [splice, reticulate, confabulate, baz, bar].reduce(compose, id);

If you haven't already got "compose" and "id" functions, here they are:

var compose = function(f, g) { return function(x) { return f(g(x)); }; };
var id = function(x) { return x; };

Congratulations, you've just gained two incredibly useful, reusable parts out of the supposedly "useless" internals of foo. I can't do much more without seeing the definitions of the "internal" functions, but I'm sure there's more simplification, generalisation and reusability available waiting to be discovered.

Warbo
  • 1,205
  • 7
  • 11
  • I wouldn't say it's "radically" different, it's just Don't Repeat Yourself applied to foo's repetitive "call this with the result of that" pattern. – Warbo Aug 13 '14 at 08:56
1

I think this type of code can be easily be converted to a chaining. Like this :

foo(stuff)
{
  return    
    stuff
      .bar()
      .baz()
      .confabulate()
      .reticulate()
      .splice()        
}

From my humble point of view, it's easy to read, keeps the separation of concern and limit the error rate (if one of the step fails, all the process fail).

eka808
  • 204
  • 1
  • 5
  • 4
    For this to work, your chained methods have to be a part of the *public* API of the `stuff` object; they can't be inner functions. – Robert Harvey Aug 11 '14 at 15:49
1

It is not an anti-pattern to split a big function into smaller functions.

However declaring all these functions inside the main one presents a certain risk: because the inner functions have access to all the variables of the outer function, and because in JavaScript variables are mutable, you cannot guarantee that the inner functions won't modify the outer function's state.

In this sense, by nesting them you lose most of the benefits of having small functions. Since they all share a common mutable state, you cannot easily reason about each one independently.

So, keep a flat structure. If you want to hide the private functions, you can use the module pattern or one of the many available JavaScript module libraries.

lortabac
  • 1,442
  • 13
  • 21
0

Yes, splitting is good, may it only be for better readabilty and testability.

Another approach might be to call the functions within each other, you start with:

foo(stuff) {
   var spliced = splice(stuff);
   return spliced;
}

Since the spliced function needs reticulated data, you can call that function first:

splice(stuff) {
    var reticulated = reticulate(stuff);
    //do splicing of reticulated
    return spliced;
}

So all functions would pass stuff through and work with the results they receive.

gnat
  • 21,442
  • 29
  • 112
  • 288