> If a method is long to read from top to bottom, the answer isn't always splitting it into 5 smaller ones, sometimes life just has inherent complexity.
Yes! This.
I find it much easier to parse a long function where I can scroll down it and just read it top to bottom, then having a function which calls out to lots of other functions and I'm jumping around the code base, back and forward.
Just reading the long function top to bottom, where I can very easily just scroll up a bit is so much easier to keep in my head.
Even worse is when you go to definition on the method and you get 5 options, and you have to figure out which one would actually get called given the current path through.
I think the issue is whether the functions that are split out are actually useful abstractions.
If they are, you should not have to jump around the code-base, you should be able to just read the invocation and know what it does, without leaving the source function.
As an example, you probably don't whip out your kernel source code when you encounter a call to write(). At least not usually. You just know what it does and can keep going.
You probably also don't look at the generated assembly code, and maybe look up the instruction reference for your favorite microprocessor when you encounter an arithmetic operator. You just assume that you know what it does, even if that may not be 100% correct in every case.
Those are good, useful abstractions.
That's what we need to strive for when we crate code.
> [than] having a function which calls out to lots of other functions and I'm jumping around the code base, back and forward.
i agree with longer functions and less jumping around, but there's also some nuance i find. I sometimes find converting a complicated multi-line condition into something like the below is much easier for me to read, so long as the function is named in a clear way and the function definition is just above the big function it gets called by (never in a different file!)
def is_something_valid(something, foo, bar):
return something > 0 and something != foo and something > bar
if is_something_valid(something, foo, bar):
it's like a convenience reading shortcut so i don't have to parse the logic in my head if i don't want to. also makes the condition nice and easy to test.
then again, can also do it the grug-brained way
gt_zero = something > 0
ne_foo something != foo
gt_bar something > bar
if gt_zero and ne_foo and gt_bar:
100%. Worst is when the called function is in a separate file, and the most upsetting is when it's the _only_ function in the file. I really wish IDEs or tools like Sourcegraph could handle this better.
For longer functions vs bouncing between smaller functions my experience has been that this is one of those things where people are one way or the other. And they almost never change their preference. If your coworkers are all the same as you, that's great. If they're not, prepare for battle.
Yes! This.
I find it much easier to parse a long function where I can scroll down it and just read it top to bottom, then having a function which calls out to lots of other functions and I'm jumping around the code base, back and forward.
Just reading the long function top to bottom, where I can very easily just scroll up a bit is so much easier to keep in my head.
Even worse is when you go to definition on the method and you get 5 options, and you have to figure out which one would actually get called given the current path through.