Function Length
martinfowler.com
martinfowler.com
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.
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.
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.
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.
After all, software development is still a engineering process, in which personal coding style is far less important.
(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.
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.)
A good name also helps a lot.
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.
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.
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.
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.
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.
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.'