
My takeaways from "Clean Code" - webpro
https://medium.com/on-coding/a70ca8382884
======
jacques_chester
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>

~~~
mercurial
Agreed. Illustrating a point with the results of an experiment is more
instructive than "you should do this, because it works for me".

------
mion
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. :-)

~~~
halostatue
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.

~~~
jasonlotito
> 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.

~~~
halostatue
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.

~~~
joshka
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.

~~~
halostatue
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 and
learning from a book like _Clean Code_ simply don’t know any better and fall
into even worse habits than if they had never read the book. Given a choice
between following complex business logic across lots of little classes and
files and a few larger functions, I know which I would choose.

------
programminggeek
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.

------
jcampbell1
> 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.

~~~
jasonlotito
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.

~~~
colomon
Isn't that a side effect?

~~~
ruficornis
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...)

~~~
colomon
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.)

~~~
ruficornis
Sorry, I was wrong. I did not read the comment closely nor was I familiar with
the CS definition. Thank you for the information.

------
jmcdonald-ut
> 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.

~~~
halostatue
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).

~~~
jmcdonald-ut
As someone who is just diving into Ruby, I'm curious what specifically you
think is bad advice for Ruby?

~~~
halostatue
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).

~~~
mercurial
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.

------
rluhar
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.

~~~
jrydberg
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.

------
cocoflunchy

        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')
?

~~~
spc476
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).

------
tdonaghe
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.

------
skatenerd
output arguments are a special case of side effects?

~~~
mc-lovin
The best thing about functions with no side effects and no output arguments,
is they often get optimized out by the compiler.

------
xkcdfanboy
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.

~~~
spc476
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_).

