Update Note:
When I first wrote this post I argued that the alias_method_chain example in the article linked below felt more like the Pipeline / Pipes and Filters pattern to me. What I didn't comprehend was that the alias_method_chain functionality of Ruby invokes behavior in another block of code within the context of the preceding block in the chain, and not simply an iteration of blocks of code (methods). So, while eating crow, I'll leave my post with some editorial adjustments to keep my comparison of the patterns and retain the knowledge that I can alias "alias_method_chain" to "decorate_methods" to make me feel more comfortable, and less misguided.
The Pipeline Pattern has been part of the coding that I've been doing lately, so when I got sent a great discussion of the Decorator Pattern in the Rails implementation from my design patterns discussion group co-host Wes I had to check it out. Charlie started a pretty intriguing discussion about the differences between the Decorator and Chain of Responsibility (CoR) patterns. Charlie started out his article with the claim that the Rails architecture was a CoR implementation and later on had a smart reply by Peter Williams that the architecture was not CoR, but rather closer to Decorator. It's hard to argue with a code author about the patterns they used, and even harder when the response comes from someone like me who is not a user of that code. (I should have known better, guess I'll learn) However I'd like to compare the Chain of Responsibility and Decorator patterns with the Pipeline /Pipes-and-Filters pattern.
I think the Charlie was on a common thought-track when he inadvertently described a piece of the Rails Architecture as Chain of Responsibility. Limited by the pattern vocabulary in the GoF book any list of methods to invoke in sequence might lead you to thinking about the CoR. In fact Chalrie's description of the code still contains the words "chain" and "link" in many places. In retrospect, the name alias_method_chain is a bit misleading for folks with a design pattern history and common practices that include pattern hints in the names of code elements, such as ValidatorFactory, ItemIterator, or BowlingFacade. Following the thought process in the article I began to think (and ultimately falsely came to the conclusion) that it wasn't CoR, but rather Pipeline / Pipes and Filters.
Until recently I wouldn't have been able to distinguish Chain of Responsibility and Pipeline, but after a while working with Pipeline I've formulated the following reasoning. As it often is with patterns, the two vary in their intent. The Pipeline Pattern is not CoR because pipeline pieces are collectively responsible for handling a message unless an exception condition is met in any one piece, while CoR passes the request only up-to the point at which a single chain claims responsibility for the complete processing of the message. Pipeline is meant to be used as a static whole, while CoR (and Decorator) are designed for dynamic part-whole composition. The individual components of the Rails implementation probably aren't designed to be used in any combination, or in whole-part compositions, but rather designed to be used as a single conceptual entity with it's pieces always in the same order relying on processing precedence.
Charlie's frustration with not being able to break existing dependencies in the Rails framework and inject a new participant in the middle of the established code helps support the argument for Pipeline with it's static whole nature instead of the dynamic part-whole design of CoR and Decorator. The author's follow up quandary about being able to distinguish the conceptual difference between the "Decorators" and Rails filters helped me believe that Pipeline/ Pipes-and-Filters was a more accurate description of the design than CoR. Conceptually it seemed like Pipeline / Pipes-and-Filters to me, not CoR or Decorator.
Where I went wrong was being too confident in my interpretation of the problem and the consequences of the pattern that Charlie was experiencing. I skipped the very crucial step of evaluating the pattern within it's context; I didn't look at how the alias_method_chain structure and the aliased methods' implementations fit together. As a result the Decorator pattern wins the cage match with a knock-out punch to my ego at the end of the first round.
Monday, September 10, 2007
Subscribe to:
Post Comments (Atom)
1 comments:
When I brought up article I was interested in the AOP angle most... but now I think I'm more in tune with Neal Ford's Design Patterns in Dynamic Languages post.
Post a Comment