Comment by pradn
5 years ago
I tried to write code with small functions and was dissuaded from doing that at both my teams over the past few years. The reason is that it can be hard to follow the logic if it's spread out among several functions. Jumping back and forth breaks your flow of thought.
I think the best compromise is small summary comments at various points of functions that "hold the entire thought".
The point of isolating abstractions is that you don't have to jump and back and forth. You look at a function, and you understand from its contract and calling convention you immediately know what it does. The specific details aren't relevant for the layer of abstraction you're looking at.
Because of well structured abstractions, thoughtful naming conventions, documentation where required, and extensive testing you trust that the function does what it says. If I'm looking at a function like commitPending(), I simply see writeToDisk() and move on. I'm in the object representation layer, and jumping down into the details of the I/O layers breaks flow by moving to a different level of abstraction. The point is I trust writeToDisk() behaves reasonably and safely, and I don't need to inspect its contents, and definitely don't want to inline its code.
If you find that you frequently need to jump down the tree from sub-routine to sub-routine to understand the high level code, then that's a definite code smell. Most likely something is fundamentally broken in your abstraction model.
> I think the best compromise is small summary comments at various points of functions that "hold the entire thought".
I think this is the best, honestly, it reaps most benefits of small single-use functions, without compromising readability or requiring jumping.
This is also how John Carmarck recommends in this popular essay: http://number-none.com/blow/john_carmack_on_inlined_code.htm...
Check out the try/catch and logging pattern I use in the linked post. I added that specifically so I could identify where errors were ocurring without having to guess.
When I get the error in the console/browser, the path to the error is included for me like "[generatePasswordResetToken.setTokenOnUser] Must pass value to $set to perform an update."
With that, I know exactly where the error is ocurring and can jump straight into debugging it.
Good grief, that pattern looks like it's effectively building a stack trace by hand. Does node not provide stack traces with errors?
It provides a stack trace but it's often unintelligible. This makes the location of the error much clearer in complex code.
Yeah, there really need to be a good reason to use catch(), and that's not it.