Comment by ajuc
5 years ago
Well, if they were one function before they probably share some state.
Clean code recommends turning that function into a class and promoting the shared state from local variables into fields. After such a "refactoring" you get a nice puzzle trying to understand what exactly happens.
I've seen threads on this before but the "goto" (couldn' t stop myself) reaching of object oriented-ness to "solve" everything is really frustrating.
I've found the single greatest contributor to more readable and maintainable code is to limit state as much as possible.
Which was really hard for me to learn because it can be somewhat less efficient, and my game programmer upbringing hates it.
Sometimes eliminating state can also mean increasing complexity and lines of code tremendously.
A lot depends on what your language and its ecosystem can support. For instance, the kind of monadic stuff people do with Haskell and Scala can compress programs tremendously, but then I've worked in a codebase that tried the same things in C++ - and there, the line count expands, because the language just can't express some of the necessary concepts in a concise way.
> if they were one function before they probably share some state
and this is exactly why you refactor to pull out the shared state into parameters, so that each of the "subfunctions" have zero side effects.
In javascript I sometimes break up the behaviour of a large function by putting small internal functions inside it. Those internal functions often have side effects, mutating the state of the outer function which contains them.
I find this approach a decent balance between having lots of small functions and having one big function. The result is self contained (like a function). It has the API of a function, and it can be read top to bottom. But you still get many of the readability benefits of small functions - like each of the internal methods can be named, and they’re simple and each one captures a specific thought / action.
If you're calling those functions once each in a particular order then I can't possibly figure out what that does for you that whitespace and a few comments wouldn't. How does turning 100 lines of code into 120 and shuffling it out of execution order possibly make it easier to read?
I coded this way for a while and found it makes the code easier to read and easier to reason about. Instead of your function being
It becomes
When the func is doing something fairly complicated the savings can really add up. It also makes expressing some concurrency patterns easier (parallel, series etc...), I used to do this a lot back in the async.js days. The main downside seems to be less elegant automated testing from all the internal state.
No; I wouldn't do it if I was just calling them once each in a particular order. And I don't often use this trick for simple functions. But sometimes long functions have repeated behaviour.
For example, in this case I needed to do two recursive tree walks inside this function, so each walk was expressed as an inner function which recursively called itself, and each is called once from the top level method:
https://github.com/ottypes/json1/blob/05ef789cc697888802e786...
I don't do it like this often though. The code in this file is easily the most complex code I've written in nearly 3 decades of programming. Here my ability to read and edit the code is easily the most important factor. I think this form makes the core algorithm more clear than any other way I could factor this code. I considered smearing this internal logic out over several top level methods, but I doubt that would be any easier to read.
A recommended reading https://www.amazon.com/Refactoring-Improving-Existing-Addiso...
Aren't you creating new functions on each call to your parent function though? I imagine there must be a performance or memory penalty?
Now this is usually in my opinion not a good advice (it is like reintroduction of global variables) as unnecessary state certainly makes things more difficult to reason about.
I have read the book (not very recently) and I do not recall this but perhaps I am just immune to such advice.
I like his book about refactoring more than Clean Code but it introduced me to some good principles like SOLID (a good mnemonic), so I found it somewhat useful.