4 ms·
This is probably a bit of a cheap dismissal.... but I think this article misses the forest for the trees. They set a standard which they manage to meet - but do
by Pannoniae 2y ago
This is probably a bit of a cheap dismissal.... but I think this article misses the forest for the trees. They set a standard which they manage to meet - but do not really introspect on whether the standard is appropriate or not.
All of these metrics (except variable liveness) are on a method/function level. Guess what this encourages? Splitting everything into three-line methods which makes the codebase a massive pile of lasagna full of global or shared state.
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.
- LandR 2y ago> 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.
- _dark_matter_ 2y ago100%. 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.
- rudasn 2y agoWhat are talking about?! That's my favourite part when reading code! :P
- dijksterhuis 2y ago> [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:
- jabiko 2y agoI think you are making a good point but if this function is only used in one place I would personally prefer to just use a variable: something_is_valid = something > 0 and something != foo and something > bar if something_is_valid: # do stuff That way you can document the intention of the condition using the variable name while at the same time keeping the locality of the check.
- robert_dipaolo 2y agoI mostly agree, but for short one liners and where there will be no reuse elsewhere, instead of a function I prefer; something_is_valid = something > 0 and something != foo and something > bar if something_is_valid: # .... It achieves the same thing without needing to scroll.
- jodrellblank 2y ago> can also do it the grug-brained way This way reads like: x = 1 // set variable x equal to 1 in that gt_zero echoes what the > operator does and says nothing about intent. Comparing, e.g. gt_zero = space > 0 // there is some space I guess? space_for_logfile = space > 0 // oh, logfiles need space > 20 there's the mistake.
- mpweiher 2y agoI 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.
- jghn 2y agoFor 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.
- deleted 2y ago[deleted]
- hobs 2y agoI would use the term irreducible complexity - you can move it around but you cant get rid of it, and spreading it all over your code smoothly and evenly makes it 10x harder to change or reason about it.
- michaelcampbell 2y ago> the answer isn't always splitting it into 5 smaller ones To someone who just read a book about it, it is. I've heard this called "rabbit hole" programming; it's function after function after function, with no apparent reason for them other than the line count. It's maddening.
- LandR 2y agoI think the whole Uncle Bob clean code movement has a lot to answer for.
- bluGill 2y agoWhile then Uncle Bob clean code movement has a lot of answer for, it is far far better than much of what came before. I've had to work with 60,000 line functions where #ifdefs worked across brace boundaries ... #ifndef foo break; case SomeCondition: doSomething(). #endif moreCode(); break; I'll take the worse uncle Bob can throw at me over that mess.
- dsego 2y agohttps://github.com/johnousterhout/aposd-vs-clean-code https://github.com/johnousterhout/aposd-vs-clean-code
- cardanome 2y agoWhile I think that there is no harm in longer functions as long as the code is linear, I think the the problem is that people abstract the wrong way. The main issue I see is people writing functions that call functions that call functions. No. Don't. Have one main function that is in control and that calls all the sub-functions. Sub-functions do not call functions on their same level, ever. Yes, those sub-function could have their own helper function and so on but the flow always needs to be clearly one-directional. Don't go across and create a spaghetti mess. Trees not graphs. Keep your code structure as flat as possible. > massive pile of lasagna full of global or shared state. Yeah, the skill is to avoid shared state as much as possible. Handling state centrally and opting for pure functions as much as possible.