views:

401

answers:

5
  1. Are there any Principles for Clojure ?

    a. Like the S.O.L.I.D. Object-Oriented Design Principles for OO languages like Java ?

    b. or others more heuristic, like "Tell don't ask", "Favor Composition vs Inheritance", "Talk to Interfaces" ?

  2. Are there any design patterns (for flexible code) ?

  3. What is the counter part of the basic of functional-programming like encapsulation for object-oriented ?

Know of any resources for these ?

+1  A: 

1a) I don't know of something like that but every book about FP will do something like that.

1b)

  • "Favor Composition vs Inheritance" --> is already taken care of because you started with FP

  • "talk to abstractions" --> more general

  • "be lazy when you can"

  • "avoid state"

  • "Use PURE FUNCTIONS!!!"

  • List item

....

2.) You can use some of the some same design patterns they are just much easier to implement. Some of them make less sense but normally. FP folks don't make a big deal out of it. (This is about GoF patterns I only know them)

Look at the observer-pattern for example. In Clojure you can use add-watcher function witch make the observer-pattern obsolete.

3.)You can use encapsulation in name spaces look at defn- or you can hide your function in other functions. In the Joy of Clojure are some examples. You can push it as far as you want.

nickik
+7  A: 

Hard question.

Clojure is very flexible. So they are best practices, but they aren't nearly as important as for java.

I write here a few examples of advices from the most general to the most particular families.

There are advices for programming in general: write a lot of tests, write something correct and nice, profile and optimize when needed

There are advices for functional programming: write small functions, write pure functions, compose the small functions, factor your code through functions, try to use combinators when possible...

There are advices for LISP: use macro to factor out repetitive patterns, build your program bottom-up. (See Paul Graham's 'on LISP' for a better explanation than mine)

There are also some advices specifically for Clojure: follow the careful analysis of state and identity ( http://clojure.org/state , for a very good explanation), try to use seqs and their functions when possible, write doc strings for functions

A good source for more advices are the Clojure Library Coding Standard http://www.assembla.com/wiki/show/clojure/Clojure_Library_Coding_Standards

But all these advices are just advices, and Clojure can be used by someone that do not want to follow these advices, because, as a Lisp, it is very flexible.

As far as design pattern are concerned, functional programmer rarely think in these terms, as most of them has been designed for OO languages and do not apply in a functional language.

Peter Norvig has interesting slides on Design Pattern and LISP/Dylan: http://norvig.com/design-patterns/

Hope that helps.

Nicolas Oury
+16  A: 

To your first question: no.

Clojure is here to help you get things done correctly, quickly, and enjoyably. Everything after that is gravy.

And there's a lot of gravy. I don't presume to know the Clojure way, even if there is one, but here are some guidelines I've been told and have discovered while writing in Clojure:

  1. First, get something working. Then you can examine, text, and optimize if necessary. There's a reason that the time macro is in the core language. Correctness before quickness, to be cute.

  2. Abstract. If you are repeating yourself, you're probably not doing it right. Compose, curry and combine functions.

  3. Separate side-effects from your logic. e.g. if you want to format and save a string, format it in one function, then use another function to save it, however you need to.

3a. Don't go too crazy with this. Sometimes it's better to have a a few anonymous functions than a bunch of one-line defns littering your code.

  1. Test. Rich gave you a REPL for a reason; use the hell out of that REPL.

  2. Don't clutter your namespace. We're clean in Clojure-land. Qualify your uses or use :only what you need. Make your code readable.

  3. Know the core library. Not just clojure.core, but clojure.java.io, clojure.string, clojure.set and everything in between. If you thing Clojure should have a function to do X, it probably does. You can use apropos (from, yes, another core library: clojure.repl).

  4. Document your code. Docstrings are a beautiful thing. If you have a tendency to be verbose, the doctsring is the place to let loose.

  5. This is a functional language. When you can, use a function. Protocols, macros and records are all great: but when you can get away with it, use a function. You can compose, combine, map, reduce, iterate (the list goes on, and on, and on…) functions. That's really nice.

  6. Above all, break the above rules if it makes sense. But be prepared to rethink and refactor. If you've kept your code modular enough, refactoring your code should be a matter of reorganization and recombination.

Some other tips: read other people's code. If you begin to read code, and become good at reading code, you'll become better at writing your own, and you're likely to learn new things, too: there's more than one way to do just about everything.

Finally, read though the Clojure Library Coding Standards to get an idea of what's expected in production Clojure code.

† At least, not yet.

Isaac Hodes
A: 

there is a post in a blog mentioning "thinking in clojure" here and it gives some pointers to the book The Joy Of Clojure, and to some other books (and even links to some videos)

now, i got the book The Joy Of Clojure, read a bit of it, and it promises to teach me "The Way Of Clojure". hope it turns out telling me what i'm looking for, some principles...

this book is work it progress but you can buy an "early access edition" from manning here and get 40% of with code "s140". see info here

Belun
+2  A: 

The Don't Repeat Yourself (DRY) principal applies very well to clojure. The language is very flexible and really promotes composing abstractions in ways that can really reduce the amount of boiler place code very close to zero.

some examples of ways to remove duplicated code are:

  • only use lazy-cons when generating original data where no variant of map will do. If you find your self writing (lazy-seq (cons (do-something data) (call-myself (rest data))), check to see of map or iterate will do what you want.
  • use small functions and compose them liberally. if a function needs to format some data, wrap it in XML, and send it over a network. write these in three small functions and then use the (def send-formated-xml (comp send xml format)) this way you can map the format function onto some data later etc.
  • when the language absolutely can not express you repeated pattern, use a macro. Its better* to use a macro than to repeat your self. and always remember the first rule of macro club is do not use a macro.
Arthur Ulfeldt
can you detail a bit on those points ?
Belun
expanded with 170% more details :)
Arthur Ulfeldt