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.
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. :-)
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.
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.
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.
"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 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.
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.
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.
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).
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.
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).
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.
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.
[+] [-] jacques_chester|13 years ago|reply
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
[+] [-] mercurial|13 years ago|reply
[+] [-] mion|13 years ago|reply
- 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. :-)
[+] [-] halostatue|13 years ago|reply
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.
[+] [-] mion|13 years ago|reply
- Comments are fails
Sometimes you rewrite code for performance, making it fast but awful to understand. Comments are very useful in this case.
[+] [-] wonderzombie|13 years ago|reply
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.
[+] [-] miloshadzic|13 years ago|reply
[+] [-] retrogradeorbit|13 years ago|reply
"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?
[+] [-] programminggeek|13 years ago|reply
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.
[+] [-] jcampbell1|13 years ago|reply
> 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.
[+] [-] jasonlotito|13 years ago|reply
[+] [-] dack|13 years ago|reply
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.
[+] [-] gizmo686|13 years ago|reply
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.
[+] [-] jacques_chester|13 years ago|reply
2. Some functions are queries that don't require an arguments. Eg. getVariable().
[+] [-] galaktor|13 years ago|reply
[+] [-] jmcdonald-ut|13 years ago|reply
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.
[+] [-] halostatue|13 years ago|reply
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).
[+] [-] rluhar|13 years ago|reply
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.
[+] [-] jrydberg|13 years ago|reply
[+] [-] cocoflunchy|13 years ago|reply
[+] [-] spc476|13 years ago|reply
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).
[+] [-] tdonaghe|13 years ago|reply
[+] [-] skatenerd|13 years ago|reply
[+] [-] mc-lovin|13 years ago|reply
[+] [-] xkcdfanboy|13 years ago|reply
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.
[+] [-] spc476|13 years ago|reply
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_).
[+] [-] mercurial|13 years ago|reply
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.
[+] [-] losethos|13 years ago|reply
[deleted]