software design trilogy part ii - design patterns for rubyists

37
+ Design Patterns for Rubyists Who Said Dynamic Languages Can’t Have Patterns? Software Design Trilogy – Part II Andy Maleh / Software Engineer / Groupon

Upload: andymaleh

Post on 08-May-2015

5.252 views

Category:

Technology


0 download

DESCRIPTION

Design Patterns have gained a lot of popularity for helping programmers achieve polymorphic object oriented code in statically typed programming languages like Java and C++. However, although the original Design Patterns book by the Gang of Four used Smalltalk, a dynamically typed language, in some of its examples, Design Patterns have not nearly gotten the same popularity in Ruby, and sometimes for good reasons. Ruby supports duck-typing and makes it very easy to do meta-programming, which alleviates the need for many of the Gang of Four Design Patterns. Additionally, Ruby can often provide easier implementation alternatives for certain Design Patterns such as State, Strategy, and Adapter. That said, Design Patterns can still offer a great value in Ruby as problem-solving tools that yield better object oriented code with higher cohesion and cleaner separation of concerns. This is clearly demonstrated in Design Patterns like State, Composite, and Decorator.

TRANSCRIPT

Page 1: Software Design Trilogy Part II - Design Patterns for Rubyists

+

Design Patterns for RubyistsWho Said Dynamic Languages Can’t Have Patterns?Software Design Trilogy – Part II

Andy Maleh / Software Engineer / Groupon

Page 2: Software Design Trilogy Part II - Design Patterns for Rubyists

+Outline

Design Patterns Pop Quiz

Practical Applications of Design Patterns in Ruby

Alternative Implementations in Ruby

Deprecated Design Patterns in Ruby

Summary

Page 3: Software Design Trilogy Part II - Design Patterns for Rubyists

+Design Patterns Pop Quiz

Who are the Gang of Four?1. Group of communist party leaders in China

2. Rock band

3. Bunch of computer programmers

Page 4: Software Design Trilogy Part II - Design Patterns for Rubyists

+Design Patterns Pop Quiz

What is a Design Pattern? Reusable solution to a common problem encountered

at the software design level of abstraction.

Page 5: Software Design Trilogy Part II - Design Patterns for Rubyists

+Design Patterns Pop Quiz

What does a Design Pattern consist of? Name Problem Solution Consequences

Page 6: Software Design Trilogy Part II - Design Patterns for Rubyists

+Practical Applications of Design Patterns in Ruby

Strategy

Problem: Need to customize behavior with multiple variations at run time, and possibly allow clients to provide their own customization as well

Solution: Encapsulate each behavior variation in a Strategy object

Page 7: Software Design Trilogy Part II - Design Patterns for Rubyists

+Practical Applications of Design Patterns in Ruby - Strategy

Example: Problem: A customer can submit a payment in one of

multiple methods, such as credit card, cashier’s check, and paypal. The code is littered with conditionals that alter behavior per payment type, making it quite involved and difficult to add a new payment type in the future or maintain existing code

Solution: Separate each payment type into its own PaymentStrategy object and let it handle that payment’s details

Page 8: Software Design Trilogy Part II - Design Patterns for Rubyists

+Practical Applications of Design Patterns in Ruby - Strategy

Code:

Page 9: Software Design Trilogy Part II - Design Patterns for Rubyists

+Practical Applications of Design Patterns in Ruby

State

Problem: An abstraction transitions through multiple states and behaves differently under each

Solution: Encapsulate behavior variations in multiple State objects

Page 10: Software Design Trilogy Part II - Design Patterns for Rubyists

+Practical Applications of Design Patterns in Ruby - State

Example: Problem: An order passes through multiple

states before it is processed: new unverified shipping processed

It can also be made inactive

Developers are tired of all the conditionals littering their codebase everywhere about the different behaviors associated with each state Solution: Encapsulate behavior associated with

each state in its own OrderState object, including the transitions

Page 11: Software Design Trilogy Part II - Design Patterns for Rubyists

+Practical Applications of Design Patterns in Ruby - State

Code:

Page 12: Software Design Trilogy Part II - Design Patterns for Rubyists

+Practical Applications of Design Patterns in Ruby

Composite

Problem: An object may be composed of other objects, like chapters consisting of sections in a book, yet both parent and child objects share common behavior

Solution: Define a child object superclass and a parent object superclass. The parent object superclass extends the child object superclass to share common behavior.

Page 13: Software Design Trilogy Part II - Design Patterns for Rubyists

+Practical Applications of Design Patterns in Ruby - Composite

Example: Problem: An educational website needs to

handle behavior for storing and formatting a hierarchy of information consistently: chapters, sections, and pages

Solution: Define a Node superclass for all elements and a ParentNode superclass for all parent elements (chapters and sections)

Page 14: Software Design Trilogy Part II - Design Patterns for Rubyists

+Practical Applications of Design Patterns in Ruby - Composite

Code:

Page 15: Software Design Trilogy Part II - Design Patterns for Rubyists

+Practical Applications of Design Patterns in Ruby

Adapter

Problem: An existing object (object A) with a particular interface needs to interact with another object (object B) that requires a different interface

Solution: Create an Adapter object that wraps object A to adapt its interface to what is expected of object B.

Page 16: Software Design Trilogy Part II - Design Patterns for Rubyists

+Practical Applications of Design Patterns in Ruby - Adapter

Example: Problem: Authentication library supports outside

strategies with an authenticate method. We have a CompanyLogin implementation that has a login method instead.

Solution: Create an CompanyAuthenticationAdapter that wraps CompanyLogin and provides an authenticate method instead that calls login

Page 17: Software Design Trilogy Part II - Design Patterns for Rubyists

+Practical Applications of Design Patterns in Ruby

Proxy

Problem: there is a need to alter access to an object for aspect oriented reasons like caching, security, or performance, and ensure that this controlled access is enforced across the app

Solution: Create a Proxy object that wraps the original object and alters access to it by adding a caching, security, or performance related layer

Page 18: Software Design Trilogy Part II - Design Patterns for Rubyists

+Practical Applications of Design Patterns in Ruby - Proxy

Example: Problem: we need to cache data retrieved from a

web service via a client object Solution: Create a Proxy object that wraps the

web service client and have it cache incoming data

Page 19: Software Design Trilogy Part II - Design Patterns for Rubyists

+Practical Applications of Design Patterns in Ruby

Decorator

Problem: an object capabilities need to be enhanced without modifying the object

Solution: Create a Decorator object that wraps the original object and adds the extra capabilities

Page 20: Software Design Trilogy Part II - Design Patterns for Rubyists

+Practical Applications of Design Patterns in Ruby - Decorator

Example: Problem: the view needs to render some model

attributes as is as well as render some formatted versions of the model attributes (example a client description that includes name and address)

Solution: Create a Decorator object that wraps the model providing its original attribute methods as well as extra formatted versions

Page 21: Software Design Trilogy Part II - Design Patterns for Rubyists

+Practical Applications of Design Patterns in Ruby - Decorator

Code:

Page 22: Software Design Trilogy Part II - Design Patterns for Rubyists

+Practical Applications of Design Patterns in Ruby - Decorator

Code:

Page 23: Software Design Trilogy Part II - Design Patterns for Rubyists

+Practical Applications of Design Patterns in Ruby

Mediator

Problem: there is a need to decouple multiple objects from each other while orchestrating a particular part of work

Solution: introduce a Mediator object that is responsible for orchestrating the work between multiple objects

Page 24: Software Design Trilogy Part II - Design Patterns for Rubyists

+Practical Applications of Design Patterns in Ruby - Mediator

Example: Problem: work associated with processing an

order requires orchestration of many objects, such as Order, PaymentGateway, AddressService, and has gone beyond the scope of what an Order object can handle

Solution: introduce an OrderProcessor mediator object that is responsible for processing an order

Page 25: Software Design Trilogy Part II - Design Patterns for Rubyists

+Practical Applications of Design Patterns in Ruby

Bridge

Problem: there is a need to implement an abstraction in different ways or using different libraries

Solution: decouple abstraction from implementation by creating an implementation object separate from the abstraction object, which bridges the abstraction to the specific implementation

Page 26: Software Design Trilogy Part II - Design Patterns for Rubyists

+Practical Applications of Design Patterns in Ruby - Bridge

Example: Problem: models are coupled to ActiveRecord as

their storage mechanism. We would like to decouple the ActiveRecord implementation to allow switching some models to MongoDB easily without affecting controllers and higher level models

Solution: decouple models from their storage implementations by introducing a ModelRepository object for each Model

Page 27: Software Design Trilogy Part II - Design Patterns for Rubyists

+Practical Applications of Design Patterns in Ruby

Observer

Problem: there is a need to perform work outside an object’s responsibilities whenever the object state changes

Solution: make the object an Observable object that allows subscribing to state notifications, and introduce Observer objects that observe the Observable and react according to changes

Page 28: Software Design Trilogy Part II - Design Patterns for Rubyists

+Practical Applications of Design Patterns in Ruby - Observer

Example: Problem: there is a need to send an email on

every order state change and we do not want such specific logic to be tied to the order model directly

Solution: introduce an EmailOrderObserver object that monitors Order for state transitions. Make Order an observable by having it provide a subscribe_to_state_transitions(observer) method to allow monitoring its state changes

Page 29: Software Design Trilogy Part II - Design Patterns for Rubyists

+Practical Applications of Design Patterns in Ruby - Observer

Code:

Page 30: Software Design Trilogy Part II - Design Patterns for Rubyists

+Practical Applications of Design Patterns in Ruby

Prototype

Problem: there is a need to build a complex object a certain way, with several variations

Solution: define a Prototype object for each of the variations, and implement a clone method that enables you to use them to instantiate objects easily

Page 31: Software Design Trilogy Part II - Design Patterns for Rubyists

+Practical Applications of Design Patterns in Ruby - Prototype

Example: Problem: need to create different kinds of User

objects when writing tests that conform to different common roles: User, Admin, Visitor, etc…

Solution: define each Deal type as a prototype using the FactoryGirl library

Page 32: Software Design Trilogy Part II - Design Patterns for Rubyists

+Practical Applications of Design Patterns in Ruby - Prototype

Code:

Page 33: Software Design Trilogy Part II - Design Patterns for Rubyists

+Alternative Implementations in Ruby

Strategy: enumerate blocks per strategy name

State: enumerate blocks per state value

Decorator: method_missing, Forwardable, Delegator, etc…

Template Method / Factory Method: abstract library

Abstract Factory: abstract library

Page 34: Software Design Trilogy Part II - Design Patterns for Rubyists

+Deprecated Design Patterns in Ruby

There are Design Patterns that have alternative implementations in Ruby that render them deprecated to an extent Command Blocks Iterator Iterator Methods (each, map, inject,

etc…)

Page 35: Software Design Trilogy Part II - Design Patterns for Rubyists

+Summary

Design Patterns enable developers to honor the open-closed principle to keep their libraries open for extension, yet closed for modification

Design Patterns help improve maintainability when behavior gets complex by adding structure that improves separation of concerns

Design Patterns serve as a good design communication tool

Design Patterns in Ruby often have alternative implementations due to language features like blocks and duck-typing

Page 36: Software Design Trilogy Part II - Design Patterns for Rubyists

+Contact Info

Andy Maleh / Software Engineer / Groupon

Blog: http://andymaleh.blogspot.com

Twitter: @AndyMaleh

Page 37: Software Design Trilogy Part II - Design Patterns for Rubyists

+References

Design Patterns by the Gang of Four (ISBN-13:978-0201633610)

Head First Design Patterns (ISBN-13:978-0596007126)