59 comments

[ 0.24 ms ] story [ 128 ms ] thread
output arguments are a special case of side effects?
The best thing about functions with no side effects and no output arguments, is they often get optimized out by the compiler.
Nice article! But I have to disagree with these:

- Minimize the number of arguments

- Avoid output arguments

Basically, you're arguing against some principles of functional programming, advocating the use of state. There's no good or wrong with state, I think, there's only a trade-off. Heavy use of state = easier/faster to code, harder to debug/read.

IMHO these kinds of generalizations are pretty dangerous. We should always try to understand the problems lying underneath in order to correctly assess the trade-offs. A quote from Elon Musk that goes something like "don't rely on analogies, try to understand the problem" popped up on HN some other day, but I'm too lazy to go look for it now. :-)

And also this:

- Comments are fails

Sometimes you rewrite code for performance, making it fast but awful to understand. Comments are very useful in this case.

Unless your performance optimizations specifically avoid method invocation, you can always extract the nasty bits to a well-named method. This is what is meant by comment avoidance: it is better to isolate the dirty stuff and pick good, specific names for what they do than to write an explanatory comment wherever possible.
Hmm, true. But a lot of performance optimizations (and the example I had in mind) avoid method invocation. Inside a critical loop, for instance, stacking function calls can make a big difference on a dynamic language. Macros could solve this problem though.
It's good practice to comment when necessary. Sometimes, even a "well named" method will not be expressive enough. Other times, you need to do something non-obvious (eg, work around a bug in another system). Comment when necessary.

I've also found that comment tend to be both easier to maintain (due to the smaller amount of code) and more necessary (due to the higher density of information) when using more powerful languages (eg, Haskell).

I tend to comment working around bugs in third party code.
Another way would be to instead wrap the third party code (and hence isolate yourself against such bugs) and use the language of choice to highlight the design decision.
But you still need to comment about why you wrapped the code in the first place.
This was my reflex as well but then I remembered that Clean Code serves mostly as advice to OO programmers. In OO programming you can consider an object's attributes to be implicit parameters to a function.
This won’t win me any friends, but I personally think that Clean Code is one of the most dangerous programming books to be released in the last decade.

There’s a lot of good advice in the book, but it is written by and for Java programmers, and it comes with its share of risks if you take its advice. If you’re developing in a dynamically typed OO language like Ruby, it’s almost always bad advice to follow Clean Code. There are performance considerations even with Java to following some of the advice given. With Objective C, the suggestions are just silly. With languages that emphasize some level of functional programming (including Ruby and even C# to a degree), the suggestions are counter-productive and produce code that is unnecessarily obfuscatory.

Yes, it’s good to have short, readable, meaningful methods. Reducing method size too much, though, can result in code that you have to follow through many objects in order to understand the logic. If you follow Martin’s advice enough, you will end up with lots of very short methods on lots of very small objects—and have a hard time understanding just how your program fits together.

If Martin were a better writer, or had expanded his horizons beyond Java when he had written this book, he may have written something profound—still dangerous, but profound. Instead, he wrote Clean Java and either he or his publisher thought it would sell more as Clean Code. My advice is to ignore the book—unless Martin comes out with a second edition that takes what he has learned in the last few years since leaving behind Java and applies it to really make a book that describes clean code.

I agree with your premise that Clean Code is not a suitable book for all programmers / and or all languages. But a good amount of "enterprise" software is written in Java. And, in "enterprise land" (where I currently live), there are lots of mediocre, inexperienced or untrained programmers for whom the advice in Clean Code is useful.

I have had to try and clean up functions that were two thousand lines long (in Java), had lots of side effects, and took in seven parameters. Oh boy did I wish the developer had read Clean Code.

I agree with your premise that the book is not relevant to those who work in dynamic or functional programming languages. Frankly, I don't think they are not the intended audience. I think it is a little hyperbolic to call it the "one of the most dangerous programming books released in the last decade".

> those who work in dynamic or functional programming languages ... are not the intended audience

I don't understand how a book that professes to be top-down advice about software craftsmanship as a discipline can be intended only for a specific subset of programmers. Shouldn't choosing a language be as much a part of software craftsmanship as how you use that language?

It's like writing a book entitled "Good Woodworking" which implicitly assumes you'll be using only double-clawed hammers[1]. Wouldn't you expect a book called "Good Woodworking" to start with a chapter on good tools?

[1] http://me.veekun.com/blog/2012/04/09/php-a-fractal-of-bad-de...

Which is why I’ve said (ever since I read it the first time) that Clean Code wouldn’t annoy me half as much if it were simply called Clean Java.

It wouldn’t sell as many copies that way, though. Probably.

I came here to say something similar, but you took the words out of my mouth. My experience reading through it was it was a mix of good advice with some questionable advice, some advice that was really only good for Java, and some advice that was terrible. The problem is it's pitched at an audience that may not be able to discern the differences between the above. The multiple authors (on a per-chapter basis) doesn't help.

Generally speaking, the earlier chapters were better, but my advice would echo yours: give it a miss, especially if you're not working in Java.

> If you follow Martin’s advice enough, you will end up with lots of very short methods on lots of very small objects—and have a hard time understanding just how your program fits together.

I have never found this to be the case. Quite the contrary, in fact. Far too many objects that do way to much, or functions that do X and Y.

Indeed, I'm puzzled by your statement:

> Yes, it’s good to have short, readable, meaningful methods. Reducing method size too much...

Which directly contracts this:

> If you follow Martin’s advice

I guess the key word is 'enough', which is really just bad wording. "If you don't follow Martin's advice" is better. The qualifier here is you don't make short methods for the sake of having short methods. You make methods as short as they need to be to do that thing they promise to do.

So then we come to it: either you support having your methods do more than they should, doing more than one thing and having side effects, or you support Martin's suggestions. And yes, it really is that black and white. Sure, you could suggest that following his advice "enough" leads you to nothing but one line methods, but that would be silly.

No, it isn’t that black and white. Many of Martin’s suggestions are silly, especially when applied to languages that are more expressive (like Ruby, CoffeeScript) or otherwise have no relationship to Java.

I distinctly remember arguments with people who were reading Clean Code at the time who really believed that one-line methods really were the ideal.

The trick is knowing what does “doing more than they should” actually mean? If you follow Clean Code as I’ve seen some people follow it (including the Ruby dev shop I mentioned elsecomment), you will end up having substantially larger interfaces at the cost of understanding just what it is that your program is supposed to do in the first place.

I’ve dealt with programs written the Clean Code way (an explosion of methods, classes, and objects), as well as programs written with too much going on in one place (e.g., 2+kloc functions). Neither is fun to deal with, but it’s generally easier to assimilate the basic business purpose of the 2+kloc function than something that has a larger interface surface than it needs to have.

Your assertions are interesting. I'd like to see some concrete examples of where you've seen this actually play out to make not well understood code.

Having recently read Clean Code as a C# dev, I feel the missing piece in this conversation is that the advice of small methods needs to be taken together with the idea that things should do one thing, and should be composed of items at the same level of abstraction. I feel the idea is hard to defend on its own, but with the other ideas quite easily defended.

I'm also curious about the performance problems you've mentioned above.

I’ll address the performance problems first. Following the advice of Clean Code, you can exponentially increase the size of your object model and the number of methods on those objects without even trying. This can cause memory pressure and increased dispatch times. If you're incautious and don't pay attention to your object creation/destruction cycle in a tight loop, you're in for a world of hurt (no surprise there). The (potentially much) larger object model of many little things that do Just One Thing makes it harder to effectively reason about the system and understand how those object allocation/deallocation cycles can be killing your performance. This is precisely the sort of thinking that leads to FactoryFactoryFactories: some things can't meaningfully be broken down without losing the point of the abstraction.

The problems with Clean Code are legion. It makes axiomatic arguments and then drives them further in the name of purity—which is anathema to shipping code, clean or otherwise. It is deeply rooted in the Java available in 2007–2008 and shows no awareness of just how broken Java was as a programming language at the time in comparison with many other languages. It makes prescriptions of things that are merely good advice.

By all means, simplify your code. That does not mean making lots of little objects and lots of little methods. It means that your code should be as simple as possible and no simpler. Sometimes this means that you’re going to have methods that are a few dozen lines long, because splitting them apart increases the state you need to carry around between those methods. Sometimes it means taking advantage of features in your language that Clean Code (being an Old Java book, despite its grandiose title) exhibits no awareness of (even though, with generics, it could).

It’s been a few years since did this, but to introduce the C# developers at a previous job to the ideas provided by C#’s functional constructs, I wrote a particular piece of code four or five times and wrote a substantial email about it describing the simplifications that the constructs provided at each step of the way, and ended it with the equivalent Ruby code, which was more or less:

   return container.any? { |e|
     e.subcontainer.any? { |f|
       f.boolean and f.subcontainer.any? { |g|
         g.boolean
       }
     }
   }
Written iteratively, it took about 50 lines to achieve this, and required state to know when you had broken out of a particular loop (#any? is short-circuiting; as soon as anything matches, you’re clear). Written with several smaller methods each acting iteratively, it also took about 50 (you lose state tracking because you can break out with a return from each function), and you lose readability at the call-site (you now have to jump to a different function for each item to understand the logic). Written with named delegates, it took about 40, but was harder to understand since the logic was separated from the call-site. Written with anonymous delegates in C#, it took about 30—and was fairly understandable (readily understandable if you already understand anonymous delegates). The equivalent Ruby code was a third of that. The most readable code kept the logic at the call-site and used powerful features in the language; the next-most readable code was the iterative code.

The above code clearly violates the rules of Clean Code; your method at object level D ('container') knows something about objects at level F and G, but making (and naming) methods at levels D, E, F, and G to return truth when you do not need those methods anywhere else? Foolish inconsistency, and Clean Code is full of examples like that where, given a better language (or even a better use of the Java language and generics), you don’t need or want to do those things.

Clean Code is a dangerous book because it takes generally good ideas and applies them as Truth, and many of the people who should be reading a...

Basically, you're arguing against some principles of functional programming, advocating the use of state.

Is that true? "Minimize the number of arguments" nudges you towards datatypes or maps instead of lists of implicitly related variables. No state there, just keeping functions relatively simple in terms of their inputs.

In the latter case, "avoid output arguments" is absolutely a principle of functional programming; it says use arguments for input and return values for output. You can't do this in Haskell. I don't think you can do it in Clojure, either, or if you can, it's not really idiomatic b/c immutable. I can't speak to other Lisps with any certainty, but I've never seen it as an idiom.

No state there, just keeping functions relatively simple in terms of their inputs.

Yes, yes! I definitely agree but what I meant is "principles of functional programming outside functional languages". When you understand the trade-offs that these principles bring to the table, you can apply them in OO languages -- in some cases. But here he's banning it for good with that statement!

With which statement?

There is one which explicitly encourages side effects -- the one which says "write bar.doFoo() instead of doFoo(bar)" -- but I think it's orthogonal; you can keep your inputs and outputs simple without rewriting your code to have a lot of state.

I agree. Especially with the 'always' part:

"Anyway, it is always a good programming advice to minimize the number of arguments. Zero or one argument is easiest to understand and maintain."

How is one to minimize the number or arguments in a purely functional language with immutable state? How can I do tail recursion without any arguments?

I think the OP is spot-on on his takeaways from Clean Code. I work with a number of people who do not have a CS or Software Engineering background but are assigned to the team as "programmers". They can hack together something that will work, but often end up with a convoluted design and an almost guaranteed maintenance nightmare.

Robert ("Uncle Bob") Martin's book has been really useful for us. We have been going through the book section by section and comparing the ideas in "Clean Code" to our implementations. It has been a most effective way of getting the team up to speed.

I would recommend anyone who is getting started on their first software engineering job to go through the book. It is excellent study material for an inexperienced team.

I would argue that computer scientists (academia) is the biggest offenders when it comes to writing "non-clean" code. They normally don't have any incentive to create reusable and maintainable code.
> Comments are fails

As the article mentions, I agree that it's good to make sure that you're naming conventions and code itself is expressive. Furthermore, if you approach coding with this philosophy you will most likely write much better code the first time around. Still some comments, written in plain (INSERT YOUR NATIVE LANGUAGE HERE), which give an executive summary of the class or method can be useful.

> Avoid output arguments / Have No Side Effects

This can be difficult to do in a language like C. It is convention to pass pointers to arrays, structs, etc and allow the method to change it or operate on it. Also it is normal for a method to adjust a pointer's position. With all the grief this caused me though, I do think that this is great advice for a language like Java, Ruby, etc.

It’s horrendous advice for Ruby. As I said in a different comment, this book wouldn’t annoy me if it had been called Clean Code.

There’s a Ruby shop in Toronto that I interviewed with a couple of years back. As soon as I learned that they considered Clean Code a good book to be learned from, I knew that I didn’t want anything to do with their software development process (and I write very good, clean, and readable software, thank you very much).

As someone who is just diving into Ruby, I'm curious what specifically you think is bad advice for Ruby?
I’m going to have to go from memory here—I borrowed someone’s copy to read a few years ago, realized that it was not a very good book, and didn’t bother buying a copy for myself (and I’m not going to “borrow” an electronic copy, either). If I don’t have some of the specifics correct, please forgive me.

One of the things that stands out in my mind is a few related pieces of advice, most of which are fairly good in isolation:

- prefer composition to inheritance

- prefer more smaller methods (as I said elsewhere, I believe that there’s even a point where it’s suggested that a one-line method is “ideal”)

- prefer smaller objects

In isolation, each of these things is fairly good—but when combined, you change from a codebase of large, unreadable functions, to an unreadable codebase of lots of little, tightly-coupled, smaller objects with smaller methods all composed into doing something that would be simpler to understand as a few medium-size objects and medium-size methods.

In Ruby, all of this is…fungible is the best word I can think of for this. Because of Ruby’s duck-typing, mixins, and most importantly, lambdas and blocks, the best place for your logic to reside is as close as possible to where it’s being used. This doesn’t mean write large methods—it means that all of the advice that’s given for Java written before late 2008 (when lambdas were barely a twinkle in the JSR process and Sun still mattered) doesn’t apply when you have anonymous blocks of code that you can apply immediately and functionally.

The best description I’ve got for this ultimately is related to many of the things said about Gamma, et al.’s Design Patterns: in other languages, design patterns are just features that the language gives you, rather than something you have to implement. Iterators? Built into Ruby, and better because of blocks. In Ruby, you don’t need to learn the lessons given to Java programmers in 2008, because the language gives you more power and expressiveness already. Add a little bit of metaprogramming (in the same way that attr_reader/attr_writer/attr_accessor is implemented, for example) and you’ve got programs that express your intent clearly, but are nearly impossible to apply Clean Code to because you’re doing something smarter (not clever, but smart).

To address the three points that I mentioned a couple of paragraphs ago:

- prefer composition to inheritance: good advice, but composition in Ruby also means considering how blocks and mixins can help you understand your code better.

- prefer more smaller methods: I’m not as sold on this; the more methods you have, even if they’re private, the harder it is to understand just how your code works because you now have a larger API to understand. (And, like someone else in this conversation, I’ve had to deal with 2+kloc functions in other languages; I just haven’t had that happen in Ruby, where the largest functions that I’ve dealt with are in the low hundreds—and those are very rare but focussed functions (e.g., a lot of error handling where you don’t necessarily want to introduce state that lives outside of the function).

- prefer smaller objects: As with smaller methods, I’m not as sold on this. The more objects you have, the more interface you have to remember, the harder it is to remember how to compose everything back into the logic you’re trying to implement.

By all means, extract code—DHH’s advice on what they’re calling “concerns” in Rails is very good (I’ve already done that with more than a small bit of our current Rails application; I’ve also done it with other code over time).

As someone who has had to deal with huge methods in PHP - high-level dynamic languages are not immune from incompetent programmers. "Prefer smaller methods" is usually good advice (or as I prefer to think about it, methods with smaller logic). Especially when you feel tempted to put comments inside your bigger method - it's a sign that it's getting too big.
> Zero or one argument is easiest to understand and maintain.

> Have No Side Effects

Can someone explain how you use zero argument functions that doesn't have side effects? I am trying to wrap my head around these two statements.

1. They're not orthogonal rules.

2. Some functions are queries that don't require an arguments. Eg. getVariable().

I just find that minimizing parameters makes a mess with tons of side effects. When I see nothing but 0 and 1 parameter functions, the code is typically doing the logical equivalent of refactoring `add(a,b);` into `push(a);push(b);add();` which makes a mess when there is more than the trivial case.

jQuery.ajax is a 33 parameter function. No one complains, and it is nice that it doesn't have side effects.

Sure. Usually when you find a strict rule, it's a rule to be considered ceteris paribus -- when all other things are fixed in place. So while thinking about parameters, I think about minimising them and ignore other considerations. When thinking about side-effects, I think about minimising them and ignore other considerations.

It's when the rules conflict that mere rule-following ends and professional judgement begins.

Basically, as noted legal scholar Captain Barbossa observed, they're less like laws and more like guidelines.

You could have a method on a class that uses it's own fields to do some calculation. So, although it does have access to the fields on the class, it takes no arguments and has no side effects.

You could certainly argue that a class's fields are a form of input arguments to a method, and I would agree - which is why another good rule of thumb is to not have too many of those either!

Obviously, it's a balance, so none of the rules can be taken without context to the situation - they are all just smells that you should "back away from" if you're finding yourself breaking any given rule too much.

And what is it doing with that calculation?
I think it is all suggestions, not hard rules. Also, given that the quote allows you to use up to 1 argument, it is actually trivial to do (assuming you are fine with the no side effects part). The trick is that instead of taking 2 parameters, you take 1 parameter, than generate and return a function that takes 1 parameter. Probably not what the author has in mind.

Anyway, in the context of the rest of the post, it looks like object oriented programming is being discussed, in which case I think the implicit 'self' does not count as a parameter.

Or just make the function take two arguments. And then use currying (if your language supports it). A lot of this depends on language.

I definitely agree with you saying its suggestions, not hard rules. Unfortunately the author of the page keeps saying 'always' as if it's hard and fast rules.

Understand why and when first, then use where appropriate.

>Just make the function take two arguments. And then use currying.

Isn't that what I said?

Having no side effects doesn't mean it can't do something. Only that it shouldn't do anything unexpected.

    storeItem.makeAvailable();
That should only make the store item available. It shouldn't re-enable a sale that was on the storeItem when it was made unavailable.
That's a zero-argument method but not a zero-argument function. That is, if you view makeAvailable as a function, storeItem is an implicit argument to it. In fact, storeItem is probably an object with several fields, so there are arguably several implicit arguments. To my eye, the name "makeAvailable" suggests a side-effect too.

In any case, it's fine for two rules such as "avoid side effects" and "prefer zero- or single-argument functions" to be in tension with one another. I don't buy that zero-or-one idea, though. A function should have as many arguments as it makes sense for it to have.

Isn't that a side effect?
That is more of an effect, not a side effect, no? Something still happens, but nothing very unexcpected. If a doctor gives you medicine for an ailment, you don't want it to have many side effects, but it intended effect is still desired (theoretically). Prehaps it should effect only what it needs to in order to give you or the next step it's output, not changing some finite machine state (unless...)
That's not how I've usually seen the term side effect used in CS: http://en.wikipedia.org/wiki/Side_effect_(computer_science)

In jasonlotito's example, he's definitely modifying state.

(Mind you, I don't think side effects should be banned outright or anything like that. But minimizing them is frequently a nice idea.)

Sorry, I was wrong. I did not read the comment closely nor was I familiar with the CS definition. Thank you for the information.
A method that acts as a "getter" by querying some sort of state wouldn't take arguments and shouldn't have side effects.
As an uncontroversial remark, I preferred Code Complete (I have both editions). McConnell has a gift for distilling research[1] into chatty, easy-to-read material.

It's been nearly 10 years since the 2nd edition, which sat uncomfortably athwart the tectonic shift to agile practices.

If I had a magic wand there'd be a 3rd edition based on what's been learned since 2004 (and a 2nd edition of Rapid Development, which he is at least considering[2]).

[1] Yes, I know most software engineering research sucks. But a lot of it is better than stuff found in The Journal of Gross Oversimplifications Conveyed in 140 Characters or Less.

[2] http://www.stevemcconnell.com/projects-newbooks.htm

Agreed. Illustrating a point with the results of an experiment is more instructive than "you should do this, because it works for me".
Don’t Pass Null? This is idiotic if you want performant code and don't want to have to use static empty object constants littered throughout your code.

Null is perfectly fine in place of an object. The author mentions this saves you debugging time. No, it will cause you pain later because you won't see errors that should happen. Instead they are masked by operating on some dummy object that you don't give a rats ass about.

Don't pass NULL (but do collect $200).

For modules I write in C, I only have one function that can return NULL---the function that creates a new structure. All other functions that work with that structure assume (backed by an assert()) that the passed in pointer will not be NULL. For the code I write, there is no reason for functions to accept a NULL pointer. And it's less painful that it sounds. I got the idea from _Writing Solid Code_, one of only two books that fundamentally changed how I write code (the other being _Thinking Forth_).

I'm sold on "don't pass null" for collections. Return empty collections instead of null, this saves you from a world of pain, and it reduces the code size.

The right way to work around null for scalar variables is to use Maybe/Option, preferably in a language with pattern matching, as opposed to using "magic values" like 0 or the empty string. This means removing null pointer errors by construction.

I haven't read "Clean Code", but I grokked through a bunch of Uncle Bob's stuff in creating Obvious Architecture and I have to say that I think that many programmers don't/won't get what Uncle Bob is going on about because many programmers want to take the parts they agree with and throw away the rest in the name of "pragmatism".

In reality, Uncle Bob's stuff is actually better when taken holistically and when applied together, but it's hard to do and when taken to their logical conclusion, it is so outside the norms of OOP, that people freak out about it not being "proper OOP" as they were taught in university and in mainstream things.

No other book has had as large an impact on HOW I write code than Clean Code. My code today looks radically different from how it looked 3 years ago.

    Flag arguments are ugly
    Perhaps the only exception is for specific setters that 
    directly set the value of an object property (flag?) 
    itself. But I have to agree that flags implicitly mean 
    that the method is probably doing too much (e.g. there is 
    no Command Query Separation).
Can someone elaborate on this (I'm not sure what he means by 'flag argument') ?
Take the Unix system call open(). It accepts multiple flags, to open the file read-only, write-only, read-write, append (only meaningful if writing), truncate (only meaningful on a write-only open), create (again, only really meaningful on a write-only open) along with about half a dozen other flags that can be looked up.

The sheer number of flags can lead to weird issues (what does it mean to open a file for read-only and truncate it? The man page I'm reading leads me to believe it does something other than return an error) and hard to test (I count fifteen flags, which gives 32,768 paths through the code).

This is retarded.

People talk about programming instead of doing it. Best advice is to do it and do it more. You learn.

I hate all the gurus. They want to explain how to take a shit.

Why don't you tell your boss to make the problem simpler so you can use one or two arguments.

----

God says...

2:25 The children of Kirjatharim, Chephirah, and Beeroth, seven hundred and forty and three.

2:26 The children of Ramah and Gaba, six hundred twenty and one.

2:27 The men of Michmas, an hundred twenty and two.

2:28 The men of Bethel and Ai, two hundred twenty and three.

2:29 The children of Nebo, fifty and two.

2:30 The children of Magbish, an hundred fifty and six.

2:31 The children of the other Elam, a thousand two hundred fifty and four.