16

I'm currently reading Robert Martin's Clean Code. I think it's great, and when writing OO code I'm taking his lessons to heart. In particular, I think his advice to use small functions with meaningful names makes my code flow much more smoothly. It's best summed up by this quote:

[W]e want to be able to read the program as though it were a set of TO paragraphs, each of which is describing the current level of abstraction and referencing subsequent TO paragraphs at the next level down.

(Clean Code, page 37: a "TO paragraph" is a paragraph that begins with a sentence voiced in the infinitive. "To do X, we perform steps Y and Z." "To do Y, we..." etc.) For example:

TO RenderPageWithSetupsAndTeardowns, we check to see whether the page is a test page and if so, we include the setups and teardowns. In either case we render the page in HTML

I also write functional code for my job. Martin's examples in the book definitely do read as if they were a set of paragraphs, and they're very clear -- but I'm not so sure that "reads like a set of paragraphs" is a desirable quality for functional code to have.

Taking an example out of the Haskell standard library:

maximumBy               :: (a -> a -> Ordering) -> [a] -> a
maximumBy _ []          =  error "List.maximumBy: empty list"
maximumBy cmp xs        =  foldl1 maxBy xs
                        where
                           maxBy x y = case cmp x y of
                                       GT -> x
                                       _  -> y

That is about as far away as you can possibly get from Martin's advice, but that's concise, idiomatic Haskell. Unlike the Java examples in his book, I can't imagine any way to refactor that in to something that has the sort of cadence he asks for. I suspect that Haskell written to the standard of Clean Code would come off as long-winded and unnatural.

Am I wrong to consider (at least some of) Clean Code at odds with functional programming best practices? Is there a sensible way to reinterpret what he says in a different paradigm?

  • 1
    Functional programmers tend to write overly terse code, it's true. I wouldn't remotely consider that a best practice though, even in that environment. – Telastyn Aug 27 '14 at 22:39
  • Forgive the ignorance, but what's a TO paragraph? – Shashank Gupta Aug 28 '14 at 0:00
  • 4
    As was mentioned in another question recently, Dijkstra wrote about the foolishness of "natural language programming" and I tend to agree with him that code that reads like prose is a pipe dream. I think this is especially true in Haskell which, being pure, symbolically expresses equalities between values rather than sequences of steps to produce effects. I think the important thing is that the quoted code is idiomatic. E.g. xs is kind of a bad name but it's as common in functional languages as i for loop variables. – Doval Aug 28 '14 at 1:07
  • @ShashankGupta I edited the question with a link to the specific page in the book as well as my own understanding of what Uncle Bob wrote. – user22815 Aug 28 '14 at 1:49
  • @ShashankGupta He gives a few examples, but the idea is that it should read like prose. "TO find the maximum of the list, you check every element..." – Patrick Collins Aug 28 '14 at 16:26
11

Clean Code is first and foremost a style manual. Strunk and White does not apply when you are writing in Klingon. The idea is that you want to be clear to the programmers that will likely read your code. You want to have code that is modularized and easy to restructure. There are ways to do this in Haskell just as there are ways to do this in any other language but the precise particulars will vary.

That being said, there are a number of style guidelines out there for Haskell. Stack Overflow has a fairly comprehensive guide as well. Keeping coding logic straightforward and brief seem to be fairly constant. Generalization of functions is also stressed as it leads to modularity. DRY code is also stressed, same as with Clean Code.

In the end, Clean Code and Haskell's coding guidelines strive for the same thing but wind up taking their own paths to get there.

  • 1
    I feel like this answer discounts principles that Clean Code teaches which are very applicable across languages, and that is core to the question asked. I can see why people think of Clean Code as a style manual, and I think it's partly true, but not true enough to dismiss the entire book as one. – Allan Jun 26 '18 at 18:13
  • I don't think of the Martin's Clean Code book as style manual. I feel the teachings of the book actually fit somewhere between a style guide and design patterns. – Michael R Jan 7 at 5:59
15

I'm not sure I follow what you mean by your example. Paragraphs, as he describes them, do not require long-windedness. He doesn't mean the code should read like English. The important part is the grouping of functionality at the same level of abstraction, in a logical progression. That's a theoretical structural concept that transcends programming paradigms.

Expressed in Bob Martin's "TO paragraph" format, I read your example as:

  • To compute the maximumBy, you need an ordering function and a list, and the result is an element of that list.
  • To compute the maximumBy of an empty list and any ordering function is an error.
  • To compute the maximumBy of a list xs, you fold over that list using the maxBy function.
  • To compute the maxBy of two list elements, you compare them using the given ordering function. If the first element is greater, choose it. Otherwise choose the second.

You're starting with the most general concepts and progressing to more detail, just as in the imperative examples. The idea of the "TO paragraphs" is that you can stop reading at a certain point when you've gotten enough detail, without having to jump up and down the page. That's certainly the case here.

A couple of the names could perhaps be better, but they are common conventions of the language, especially when writing generic higher-order functions. Higher-order function names also don't translate well into imperative verb phrases like the examples in the book, because they more describe relationships between verbs.

There are ways to implement this that don't follow the "TO paragraph" guidelines. Leaving off the explicit type signature would omit the higher-level "overview" sentence. You could use an if expression for the error handling instead of pattern matching, which would muddle that inappropriately with another abstraction level. You could inline maxBy as an anonymous function instead of giving it a name that can be described later in more detail.

In fact, I think constructs like where actually are a better fit for the paragraph format, because you can use them to give a name to a deeper detail in a way that's close to how we express it in English, and similarly limit its scope in a clear way to the context of the "paragraph."

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.