Sadek Drobi’s Blog

April 20, 2008

And Design Patterns suddenly Degrade!

Filed under: Architecture, C#, DSL, Functional Programming, Haskell, LinQ — Sadache @ 9:25 pm

Lately I’ve been writing some programs with Haskell (a pure functional programming language) and I noticed that I am not using GoF design patterns anymore, and that got me to a question: What are GoF design patterns? And why do we need them?

This actually reminds me of a good definition I read (I can’t recall where) of these design patterns: Resolutions to programming language limitations implemented using the programming language available syntax. When one learns a programming language, he learns to express what he wants to express using a very limited set of expressions of the language. The problem with this is that his imagination in this environment gets boxed! So what are GoF design patterns?

Most of GoF design patterns are inspired from Smaltalk, so what is so special about Smaltalk? Closures! It turns out that Java and C++ didn’t have closures and higher order functions. Some of the Design Patterns came to rescue and provide "alternatives" to these powerful constructs or workarounds  to resolve these limitations. Such an approach requires a kind of object gymnastics and results in an explosion of classes!

I am now on a project where I use C# 3.5 features, and guess what? Suddenly I use much less strategies, much less templates. I write much less code yet being as or even more flexible. Powerful lambda expressions!

Update: DSLs also come from fp paradigm!

12 Comments »

  1. You might be interested in Peter Norvig’s take on this topic.

    Comment by Steve Vinoski — April 22, 2008 @ 2:43 am

  2. Or http://blog.plover.com/prog/design-patterns.html

    Comment by Anonymous — April 22, 2008 @ 6:43 pm

  3. You could argue that monads are a Haskell design pattern…

    Comment by Joe Chung — April 22, 2008 @ 7:00 pm

  4. Design Patterns are mostly useful for naming - by slapping a concrete name on a, wall, Pattern, it’s easy to talk about code that uses these approaches.

    Eg. a sort function that takes, say, a lambda function to implement the equality relation can be said to use the Strategy Pattern. The fact that there’s no boilerplate is a merit of the language. Or is there a better terminology for this kind of pattern in functional languages? (’higher order functions’ or similar don’t really suggest the same thing as ‘Strategy’ - but that might just be me…).

    Comment by murphee — April 22, 2008 @ 7:02 pm

  5. “Design Patterns in Dylan or Lisp: 16 of 23 patterns are either invisible or simpler”

    http://norvig.com/design-patterns/img010.gif

    Comment by Ricardo Herrmann — April 22, 2008 @ 8:21 pm

  6. Smalltalk didn’t just have closures: it also had first-class classes, which make many more GoF patterns unnecessary. Common Lisp’s multimethods render more patterns unnecessary. And so on… I’m with Mark Dominus (linked above): while patterns will probably always be with us, the patterns we use will change as today’s patterns are absorbed into tomorrows languages and libraries.

    I wrote a blog post commenting on an aspect of this stuff a while ago. Warning: the post contains errors, but they’re corrected in the comments.

    And historically, DSLs aren’t particularly tied to the FP camp. Smalltalk’s a pure OO language, and DSL creation is very much part of their culture. Many APL applications were actually delivered as embedded DSLs written on top of APL (an array-based language, albeit with some functional attributes). Lisp’s arguably a functional language, and Lispers write a lot of DSLs, but they mostly use macros to do so.

    Comment by pozorvlak — April 22, 2008 @ 8:28 pm

  7. Joe: I guess you are talking about the monadic abstraction. Yes, you can argue that it is a pattern, but I personally think that it is much more than a pattern.
    First: Looking at all patterns class diagrams you will notice that most of them look really similar. So it is more fair to compare the whole patterns idea to monads IMO.
    Second: Patterns are templates, that you have to copy paste or to get inspired from when you write your code. A monad is an abstraction. An abstraction in the way that it hides complexity. A monad is an abstraction that has a set of interesting properties that you get out of the box when you “inherit” it and satisfy its conditions. Doing this is not very hard if you get to understand monads concept. But using it is really easy and quite straightforward (you don’t really need to understand monads to use them) because it hides complixity unlike patterns which are templates that introduce complixity when you use them.
    Third: Monads got support in Haskell (and in linq somehow), so when you introduce a monad you can get the nice syntaxt for free.
    A whole library can be abstracted with a monad, which hides its complexity.
    Anyway i am almost done with a series of posts that compare such concepts from both my experience with Java and C# and my experience with Haskell.

    Comment by sadek — April 22, 2008 @ 8:38 pm

  8. Murphee : I would rather say that higher order function are just a very natural thing, like passing an object as a parameter to a method of another object. Functions are first class citizens and combining them is so natural that you dont even need a template or a catalog to do so. Like, say, Inheritence in OOP. What is hard in OOP is logic (function) composition. That is why we need Template Pattern, Strategy Pattern, Visitor Pattern and so on. I guess it is all about composability. At least that is what I think after my fairly long journey with Java and C# :)

    Comment by sadek — April 22, 2008 @ 9:00 pm

  9. Pozorvlak: I beleive that Smalktalk has a functional side which makes logic composition fairly easy. APL is a functional programming language.
    Please don’t get me wrong. I am not a FP geek. I rather have a considerable history in imperative programming languages. I just think that functional programming concepts, the power of functions composability, brings a lot of benefits to programming languages, including C# :)

    Comment by sadek — April 22, 2008 @ 9:14 pm

  10. @sadek
    @”First: Looking at all patterns class diagrams you will notice that most of them look really similar. So it is more fair to compare the whole patterns idea to monads IMO.”

    Absolutely not. This is a canonical example of how novice functional programmers do not understand the value of patterns. A UML Class Diagram tells you absolutely *nothing* about the pattern. You *have* to see the context that the pattern is being used in. Static representations of patterns don’t work. If that were the case, then it would be a simple matter of stitching together lego building blocks to make applications: Just cut-and-paste patterns! However, that is NOT the case.

    Also:
    Part of me really loves that Norvig Patterns link, and the other part of me really hates it, too. It just seems like people take concepts as being mutually exclusive: ‘if the pattern isn’t visible, then it *degrades* or ceases to exist.’

    Comment by John "Z-Bo" Zabroski — April 24, 2008 @ 4:39 am

  11. @John
    The context that differs from pattern to another is the problem domain. It exists even without the pattern. The fact that all patterns have almost the same static representation shows that they are the same tool for different kind of problems. That tool in FP is a function and higher order functions (and other abstraction tools).
    When I am doing Haskell I feel much more relaxed, I just use my first class tools to solve problems without looking through a catalogue or trying to apply names to my solutions. I see patterns as a catalogue for doing composition because composision is not a first class citizin in the concerned programming languages.

    Comment by sadek — April 24, 2008 @ 8:46 pm

  12. @sadek

    Yes, I recognize that is how you see patterns. However, patterns are supposed to be formal elements of real world solutions. They are not simply proven to work, but they can (and should be) proven through formal analysis to have unique properties. I’m happy for you, but it seems to me like you are undergoing a mathematical re-awakening more than anything else. That’s great, but don’t drop what you already learned at the gates just so you can pass through into Heaven.

    Software engineering can be *both* intuitively appealing *and* mathematical. Creational patterns allow composition, by definition. Behavioral patterns also allow composition, by definition. Structural patterns also allow composition, by definition. People often misunderstand the GoF design patterns. “Prefer composition over inheritance” is a major principle behind these patterns. Yet, just the other day I was reading a blog that *tried* and *failed* at teaching the most mathematical design pattern of all: Singleton. Someone in the comments stated that the purpose of a Singleton was to create a “pattern of prohibition - to stop a programmer doing something they shouldn’t do by accident by enforcing the primary goals of single point of access”. This is not true, either. Singleton is a mathematical concept. Even in Lisp, there is a singleton: *nil* or the *empty* list (depending on the dialect of Lisp). This is the most natural expression of Singleton possible, and absolutely essential to Lisp: it is the ATOM! of Lisp.

    It is true that Singleton has major repercussions on referential transparency, seeing as how it enforces global state at the architectural layer it is defined in. In Lisp, nil is totally referentially transparent, so you can define it at any layer of your architecture you choose. The symbol is global scope, but not many people say it is global state. This is not true. It is a globally-defined state, not a global state. A global state would mean you’ve hardwired something significant into the system that you truly intended as a “pattern of prohibition”. People do this all the time, because they can’t see the consequences of their actions, both intuitively and mathematically!

    Take for instance your typical Dependency Injection framework that ends up injecting objects into Controllers and Managers. What is the point in injecting _anything_ into an object with the name “Manager” or “Controller”? Objects named “Manager” or “Controller” are the true prohibition, because they hard-wire state-process decisions and force actions to go through them - you need managerial approval from the Boss component to get work done. This is far from composition, and also far from the goals of inheritance. It’s simply bad system planning and design. The end result is that you have an architecture that responds slowly to maintenance actions, because any assumptions made in the Manager or Controller are going to be impossible to revisit, because they directly impact the whole system. At this point, a “bug” in such a component becomes a “feature”. If you don’t like it, well, too bad!

    I could rant for hours about this, and how it is important to understand design and examples of good design BY NAME and why they work, not simply what they are used for. Suffice to say, if you are experiencing a mathematical reawakening, don’t think for a second that design patterns degrade. Instead, I encourage you to unite your intuition with your growing mathematical prowess. Try learning the most intuitive mathematical system of all: Geometry. Hyperbolic geometries, Finite geometries, Infinite geometries, etc. At least, Modern Geometry was the course in college that taught ME the most about systems thinking and how to design programs. At that point, it was clear to me that specification trumps structure, and that understanding the importance of an intuitive and mathematically appealing specification is a loftier goal than understanding design patterns.

    Comment by John "Z-Bo" Zabroski — April 25, 2008 @ 5:13 am

RSS feed for comments on this post. TrackBack URL

Leave a comment

Powered by WordPress