But if you don't put it in a separate function, then all that code becomes something that you have no choice but look at as part of this function, because the text of it is right there in the function.
Sticking part of the code in a sub-function gives you the choice: Do I trust that this function does what it says, with no other effects that I have to worry about? Or do I go look at it to make sure?
But not sticking the code in a sub-function gives you no choice - it's right there as part of the function you're looking at, and you have to see what that code is doing as part of understanding the function. And having that code not in a separate function makes it more likely that it has side effects that can mess up the rest of the function (separate functions is a firewall against side effects).
Perhaps it would not be quite as bad if there was a clear distinction between "this is a function for reuse" and "this is a function that's naturally just elaborate code folding", but that does not really exist. Just stick to single-assignment variables and keep their scopes short and enjoy the good parts of sequential code.
"Better names" is a good answer for a sloppy pattern that looks like this:
fun saveRecord(record){
wireRecord = record.toWireRecord();
innerSaveRecord(wireRecord)
}
fun innerSaveRecord(wireRecord){
log("saving record " + wireRecord)
saveWireRecord(wireRecord)
}
That's a stupid level of nesting instead of a reasonably-named "convertAndLogAndSaveRecord()" - then you get into debates about if logging should be in that name, otherwise it's happening despite the name not saying it, etc.
So all that to say that moving into functions alone can be good, or can be bad.
The easiest-to-define benefit of the verbosely-named "convertAndLogAndSaveRecord()" is that it becomes easily testable vs having those lines inlined somewhere. (I'm often much more ambivalent on "reuse" benefits - if your function is specific it can't be made reusable without making it less well defined.)
But as far as I know, the world doesn't offer me a way to test that the function not only does what it says but doesn't do what it doesn't say. And it's similarly hard to talk other programmers out of shoehorning new logic into existing functions - now making them harder to reason about - rather than new functions that are composed differently or with the existing ones.
Because if "checkAccountingProcessResultsAgainstAudit" is going to give you readability benefits, it damn well better do what it says every time you call it instead of becoming a maze of conditionals and optional behavior.
Someone that applies "MORF" to their code winds up nearly inventing their own language in the file that they're writing. All that takes up more memory when you're reading their code, because due to leaky abstractions the actual implementation of whatever the function name that you replace it with is often important.
I have an actual track record of taking code that someone had MORF'd to hell and rewriting it, and making it about 40% shorter, with much fewer concepts to process.
Inventing a term like "MORF" is probably illustrative of the problem itself. Without looking at the blog post what exactly was that acronym again? That is just one more thing for you to try to memorize. The author is riffing on things like "DRY" and "YAGNI" that are well-known, but it isn't really helping with readability when you lift it out of that context.