Comment by raverbashing
5 years ago
Yeah I agree with the author, and I would go further, it's a nice list of reasons why Uncle Bob is insufferable.
Because of stuff like this:
> Martin's reasoning is rather that a Boolean argument means that a function does more than one thing, which it shouldn't.
Really? Really? Not even for dependency injection? Or, you know, you should duplicate your function into two very similar things to have one with the flag and another one without. Oh but DRY. Sure.
> . He says that an ideal function has zero arguments (but still no side effects??), and that a function with just three arguments is confusing and difficult to test
Again, really?
I find it funny who treats him as a guru. Or maybe that's the right way to treat him, like those self-help gurus with meaningless guidance and whishy-washy feel-good statements.
> Every function in this program was just two, or three, or four lines long. Each was transparently obvious. Each told a story. And each led you to the next in a compelling order.
Wow, illumination! Salvation! Right here!
Until, of course you have to actually maintain this and has to chase down 3 or 4 levels of functions deep what is it that the code is actually doing. And think of function signature for every minor thing. And passing all the arguments you need (ignoring that "perfect functions have zero arguments" above - good luck with that)
Again, it sounds like self-help BS and not much more than that.
> Until, of course you have to actually maintain this and has to chase down 3 or 4 levels of functions deep what is it that the code is actually doing.
The art is to chain your short functions like a paragraph, not to nest them a mile deep, where the "shortness" is purely an illusion and the outer ones are doing tons of things by calling the inner ones.
That's a lot harder, though.
But it fits much better with the spirit of "don't have a lot of args for your functions" - if you're making deeply nested calls, you're gonna have to pass all the arguments the inner ones need through the outer ones. Or else do something to obfuscate how much you're passing around (global deps/state, crazy amounts of deep DI, etc...) which doesn't make testing any easier.
> Really? Really? Not even for dependency injection? Or, you know, you should duplicate your function into two very similar things to have one with the flag and another one without. Oh but DRY. Sure.
I'm not sure dependency injection has anything to do with boolean flags or method args. I think the key point here is that he is a proponent of object oriented programming. I think he touches on dependency injection later in the book, but it's been a while since I've read it. He suggests your dependencies get passed at object initialization, not passed as method options. That let's you mock stuff without needing to make any modifications to the method that uses that dependency easily.
> Until, of course you have to actually maintain this and has to chase down 3 or 4 levels of functions deep what is it that the code is actually doing. And think of function signature for every minor thing. And passing all the arguments you need (ignoring that "perfect functions have zero arguments" above - good luck with that)
I myself find it easier to read and understand simple functions than large ones with multiple indentation levels. Also, it definitely does not make sense to pass many arguments along with those many small functions. He recommends making them object instance properties so that you don't need to do that.
It may not be for everyone, but I'll take reading code that follows his principles instead of code that had no thought about design put into it any day of the week. It's not some dogmatic law that should be followed in all cases, but to me it's a set of pretty great ideas to keep in mind to lay out code that is easy to maintain and test.
> I'm not sure dependency injection has anything to do with boolean flags or method args.
DI can be abused as a way to get around long function signatures. "I don't take a lot of arguments here" (I'm just inside of an object that has ten other dependencies injected in). Welcome back to testing hell.
Yea... that could probably turn ugly in a lot of cases. I think the flow of object creation and dependency injection would be the important part to handle well in a case with a lot of dependencies. I think the dependencies should be passed down through objects in one direction. So if your object (a) that works on objects (b) that have a lot of dependencies, that first outer object (a) is responsible for injecting dependencies into those 2nd objects (b). So if you have a mocked dependency, you pass that when initializing object a, and object a is responsible for injecting that mocked dependency into object b.
A disclaimer, I'm an sre, so definitely not the most expert proponent of oop.
> I myself find it easier to read and understand simple functions than large ones with multiple indentation levels
A CRUD app might get away with this, but anything more complex needs a lot of different variables and has complex code.
It's actually a good marketing trick. He can sell something slightly different and more "pure" and make promises on it and then sell books, trainings and merchandises.
That's what the wellness industry do all the time.
The boolean issue is probably the one that's caused me the most pain. That contradiction with DRY has actually had me go back and forth between repeating myself and using a flag, wasting a ton of time on something incredibly pointless to be thinking that hard about. I feel like the best thing for my career would have been to not read that book right when I started my first professional programing job.
It's been a while since I've read it, but I think to handle boolean flag type logic well he suggests to rely on object subclassing instead. So, for an example that uses a dry run flag for scary operations, you can have your normal object (a) and all of its methods that actually perform those scary operations. Then you can subclass that object (a) to create a dry run subclass (b). That object b, can override only the methods that perform the scary operations that you want to dry run while at the same time using all of its non scary methods. That would let you avoid having if dry_run == true; then dry_run_method() else scary_method() scattered in lots of different methods.
It might make sense to divide your function with boolean flag into two functions and extract common code into third private function. Or may be it'll make things ugly.
I treat those books as something to show me how other people do things. I learn from it and I add it to my skill book. Then I'll apply it and see if I like it. If I don't like it in this particular case, I'll not apply it. IMO it's all about having insight into every possible solution. If you can implement something 10 different ways, you can choose the best one among them, but you have to learn those 10 different ways first.