
Design Patterns in Clojure - susi22
http://mishadoff.com/blog/clojure-design-patterns/
======
kilink
I like Clojure quite a bit more than Java, but some of these are unfair if you
are comparing against modern Java.

For instance, the sorting example can be simplified:

    
    
        Comparator<User> userOrdering = Comparator.comparing(User::isSubscription).thenComparing(User::getName);
        // forward sort
        Collections.sort(users, userOrdering);
        // reverse sort
        Collections.sort(users, userOrdering.reversed());
    

A lot less verbose than it's made out to be.

~~~
codahale
While it’s definitely the case that there are more concise domain-specific
examples, as you’ve pointed out, the article’s point stands: in Clojure, a
Strategy is simply passing a function as an argument to another function.

~~~
phamilton
The caveat is perhaps that in Java 8, a Strategy is simply passing a function
as an argument to another function too.

I'd love to see patterns struck down as obsolete with Java language updates.

~~~
TwoSheds
\+ Finding or creating suitable functional interface for passing the function

------
jph
Brilliant-- this is among the best design pattern writeups I've ever seen, and
will greatly help developers who are coming to Clojure.

This would be excellent for expanding to book-length guide to help people
learn functional programming along with the patterns. Thank you Misha for
writing this!

------
patrickmay
Peter Norvig covered this two decades ago: [http://norvig.com/design-
patterns/design-patterns.pdf](http://norvig.com/design-patterns/design-
patterns.pdf)

Paul Graham mentioned Norvig's work in 2002:
[http://www.paulgraham.com/icad.html](http://www.paulgraham.com/icad.html)

------
rfw
I love the idea! A few examples are a bit strawmanish but really when you're
comparing languages like that who can resist the strawman.

The Clojure solutions do sacrifice a lot of safety though, due to dynamic
typing (e.g. the visitor pattern, which relies on basically strings to do its
dispatching).

~~~
yenda
keywords are not strings. And what do you mean by safety ?

~~~
sdegutis
I'm assuming commenter meant it'll crash at runtime if there's typos in a
keyword used for dispatching a multi method.

------
0x0dea
[http://wordsmith.org/anagram/anagram.cgi?anagram=SerpentHill...](http://wordsmith.org/anagram/anagram.cgi?anagram=SerpentHillREE&t=1)

Subtle.

------
moomin
I'll just plug my own (not as comprehensive) contribution to this meme:
[http://www.colourcoding.net/blog/archive/2014/10/27/design-p...](http://www.colourcoding.net/blog/archive/2014/10/27/design-
patterns-happy-birthday-and-goodbye.aspx)

------
yenda
I would love to have some Java programmer opinion on this piece.

~~~
daxfohl
I'll bite, downvotes notwithstanding :)

One advantage of the Java is that the interfaces are named, type-checked
documentation. Yes it's more verbose, but a maintainer of that code can
understand exactly the intention just from the interface names, without having
to decipher it line-by-line.

For the Clojure code, after you've added enough comments to explain what
you're doing, so that the code can be reasonably maintained, then it's the
same size as the Java code, but without the type safety.

Granted for some of the simpler patterns like strategy, Java's verbosity just
gets in the way, though much of that has been simplified in Java 8. FWIW I
prefer Scala over both in all cases. But if Scala didn't exist, I'd prefer
Java for the enterprise use case, and Clojure for the small applet use case.

~~~
bpicolo
> it just doesn't work at an enterprise level Elaborate?

~~~
daxfohl
Big, not-very-interesting CRUD app. Every time the data model changes, you've
got to go through manually and find all the places the code needs changed, and
hope you didn't miss anything. It probably didn't help that it was running on
MongoDB, so two levels of dynamic typing and impossible to remember what went
where, and a DB that takes whatever you give without complaining. So no
compile errors and often no runtime errors either, just incorrect behavior.

Switched to Scala and SQL, and code is almost as compact but typed relations
are far easier to reason about; if a relation changes then you change the core
type and follow the compile errors. Once it compiles, it usually works. We've
not missed Clojure in the least.

Scala (and even Java) simply feels more structured, with relations between
types, the resulting app more "designed", which seems necessary at the
enterprise level. In my 2 years, Clojure constantly felt like just hacking.

Would love to see some examples of Clojure being used well at an enterprise
level so I could understand better how to do so, but CircleCI's recent
flopping between core.typed and prismatic just makes me think it's a square
peg in a round hole.

~~~
michel-slm
Using Mongo certainly didn't help, we're in the same situation ourselves and
having various regrets over different aspects of it...

What do you use to interface with SQL on the Scala side? Squeryl?

~~~
daxfohl
JDBC. I tried a few libraries and found they all provide either too much or
too little. It's not so hard to write your own wrapper around it to make JDBC
more friendly. Plus then you get to use features specific to your DB rather
than just the lowest common denominator.

Another thing that helped was to use underscore_naming for any case-class in
Scala that maps directly to a query, so it's easier to identify them.

------
richcole2
Really nice writeup of patterns. What turned me off Clojure is that the
dynamic typing makes it very hard to refactor. e.g. even renaming a function
is really quite difficult, let alone adding function parameters. Forget
extracting a function. The dynamic typing also means a typo can yield a nil
that travels far from the mistake site making debugging difficult. There are
hints towards better debugging in clojure, but last time I checked it was
still very much a work in progress. Also lazy lists are easy to screw up, e.g.
if you put a concat inside a reduce then stack go boom.

Still this is a great post because it teaches you both good Clojure and the
design patterns. Since java has closures now you can take a lot of what you
learn from Clojure and put it in your well typed and refactorable Java
programs.

~~~
yenda
Refactoring is a breeze when your editor is connected to the repl, you should
try clj-refactor for instance.

I'm not sure what you mean with the typo story since most of the functions in
your program should be free of side effects you should be able to test them as
you write them.

~~~
daxfohl
I'm always curious about the latter sentiment. Maybe I just haven't been on
enough interesting projects, but I've never had a program that didn't
have/need side-effecting code nearly every other line. Upload something to S3,
if X then call some web service, otherwise log and call something else, etc
etc etc. Pure data manipulation has always been a fairly minor component
limited to dashboard statistics for me. Is purity that really your experience?
What industry / types of projects?

~~~
brandonbloom
Thinking in data & functions just takes some practice. Traditionally
imperative code can often be reimagined in terms of reducing over a command
sequence, or interpreting some more sophisticated representation. The benefits
for implementation, testing, debugging, refactoring, etc can be massive.

Consider your chain of examples for "Upload something to S3, if X then call
some web service, otherwise log and call something else, etc etc etc." You
could represent this as a sequence of steps which could be interpreted by a
central side-effecting loop. Let's call it an "action plan", in this case for
your "upload" operation:

    
    
        (defn upload-plan [req]
          [{:action :upload
            :file (get-in req [:params :doc])
            :max-size 2000
            :name :doc}
           {:action :notify
            :message (fn [state] (get-in state [:data :doc]))
            :target [:somebody]}])
    

Now you can process this plan centrally:

    
    
        (defmulti take-action (fn [state {:keys [action]}] action))
    
        (defmethod take-action :upload ...)
        (defmethod take-action :notify ...)
    
        (defn execute [plan]
          (let [{:keys [status]} (reduce take-action {:status :ok, :data {}} plan)]
            (when (not= status :ok)
              (log "omg!"))))
    

While this is initially a tad more verbose, there's great reasons to do this
sort of thing.

For example, now have a central place to mock all side effects! You could
substitute a different execute method during testing, or automatically log the
"action" object that failed.

More importantly, you can develop each of your "plan" functions independently.
You can reuse them, re-order them, etc.

You can also do hypotheticals, for example: "Which plan would cause less
network round trips?" can be answered before committing to a plan.

You can _record_ plans. Instrument your execute method to record and save
plans to a file, then you can just check them right in as test cases.

You can optimize plans. If five different functions all notify the same target
of the same thing, your central execution method can filter subsequent calls.
Or you could separate your "optimization" from your "interpretation" and you
can ask "After accounting for idempotence, which operations will be
performed?"

The list goes on and on...

~~~
phamilton
As an aside, you just (sort of) implented the IO monad.

The simplest explanation of the IO monad is that your Haskell application
outputs a recipe or "execution plan". This output is side effect free and
pure. The runtime then executes your plan, producing those side effects.

~~~
brandonbloom
One key difference between this and the IO monad or a free monad: There's no
continuation.

That is, you can't communicate between the code that produces the command
sequence and the code that interprets it. This is either a shortcoming, or a
dramatic simplification, depending on your needs. I find that it's often the
latter, since it enforces a one-way information flow.

~~~
daxfohl
I looked at this, and isn't it inside-out though? Given that code/data
equivalence being the fundamental thing that makes a lisp a lisp, wouldn't the
lisp way to go about it be, to write a whole-program-transformation macro that
can replace certain function calls with specified equivalents? That way you
can write code just like normal, but have it do completely different things
based on the context. The idea of being able to do this is what made me
consider a lisp in the first place. Yet I don't see much evidence of people
working in that direction.

~~~
brandonbloom
There's a lot of stuff packed in to your comment here.

The code/data equivalence isn't necessary to make this data-first approach
work. Consider JavaScript, where it's quite popular to power complex processes
with simple JSON (maybe + extensions, like functions). The approach also works
well in typed functional languages, albeit with greater declaration burden.
Moreover, it would even work well in languages like Java, if you're willing to
buck the XML trend.

That said, data being a subset of code (which is also implied by equivalence)
is what makes this technique much more popular in Lisps (and JavaScript).
Being able to easily move forms between evaluation, quoting, interpretation,
etc is critical to evolving the right approach.

Regarding whole program transforms: They don't compose, at least not without a
substantially more sophisticated macro system (like Racket's) or evaluator
(see work on "extensible interpreters"). Check out Racket's rich literature on
macros if you want to see the state of the art here.

Lastly, changing behavior based on context can be accomplished by many
techniques including interpretation, dynamically scoped binding, etc. Read
about Common Lisp's condition system, or Eff's "Algebraic Effects and
Handlers" to see the state of the art of the dynamic substitution of effects.
However, each new context needs to carefully reason about the interleaving of
effects, since time is linear.

If you want more flexibility with time, you have to turn it in to space.
That's what happens when you take a step-by-step procedure and turn it in to
data you can interpret. Consider code that prints a lot of stuff. Instead, you
can return a lazy sequence of strings and then at the very end do something
like `(apply str parts)` to concatenate it all together. Now that each sub-
printer doesn't have side effects, you can re-order and refactor the calls
without worrying about messing up the printed output. You've decoupled the
evaluation timeline from the linear order of the output.

------
moomin
Whilst I agree in general with the sentiment, it really doesn't help if you
start with a misunderstanding of the command pattern. The essential property
of command is that it's data that can be executed. Implicitly, it's possible
to do other things with them: log them, undo them and so on. A better model
would be a record that implements IFn.

------
OmarIsmail
I think the Visitor example is a mistake. Couldn't you replicate the Clojure
version in Java by having a "Formatter" singleton that has a function for each
of the different item type/format type combinations?

~~~
js8
I don't think so, the whole point is that Clojure will select the correct
function dynamically (that's what multiple dispatch is about). In all cases
you need 4 different functions (for each type/format combinations).

------
js8
Excellent, definitely going to read this. I would like to see this for
Haskell, though. And some Lisp idioms (from On Lisp, for example) could be
thrown in for a good measure, too.

------
greydius
> Eve: Stop talking, show me the code!

I like Eve.

