Project Ramon

A learning journey from a Ruby noob perspective

Today I’m Learning: Context & Roles in DCI pt[2]

dci2_header_img

Hello and happy Monday!

In my last post we began looking into what DCI is and how to separate an object’s state from it’s behaviors. This gives us both modularity (separating our functionality into independent reusable modules) and also provides the benefit of making our code easier to read.

Today we’ll be looking into context creation in our code and the concept of defining roles for our objects involved within a specific context.

Creating Context

In DCI we can think of context as the script for a movie scene. The purpose of this scene is to progress the story of a set of actors.

In our code the context declares an interaction between a set of objects by assigning each of these objects a role in the scene. These objects then perform their roles as the goal of the scene dictates. We can layout our script before actually implementing it by using brief statements that describe each step towards the goal of our context.

  1. Create a player for the role of @the_pitcher
  2. Inject a baseball collaborator for @the_pitcher to throw
  3. Create a player for the role of @batter_up
  4. Inject a bat collaborator object for the player at bat to swing with
  5. @the_pitcher throws a pitch
  6. the player at bat swings at a pitch
  7. Homerun if the player at bat’s swing matches @the_pitcher‘s pitch_type
  8. A new inning occurs once 3 missed swings (strikes) occur from both players
  9. Winner is determined by the player who reaches 10 home runs first
  10. When the first at bat player reaches 10 home runs the pitcher receives a chance to bat once more

The above list, attempts to cover the angle of missed hits as well as hits accumulated to determine a change of inning or a winner.

We can think of the naming scheme as the primary way to define the acting object’s roles in a specific context (i.e. use case). From the little scenario painted in the paragraph above, we would have one class Player which creates two objects for this context, @pitcher = Player.new(ball) and @batter = Player.new(bat).

Heres another example to illustrate naming our ‘actor’ objects after the roles they play in the scene (i.e. context/use case).

class MessageMe
  include MsgComposer
  include MsgDispatcher
  include MsgReader

  def initialize(author=User.new, recipient=User.new)
    @author = author
    @recipient = recipient
  end

  def compose_a_msg(msg)
    @author = author
    title = msg[0]
    body = msg[1]
    @author.compose(title, body)
  end

  def dispatch_to(recipient, msg)
    @author.dispatch_to(recipient, msg)
  end

  def read_a(msg)
    @recipient.read(msg)
  end
end

class User
  def inbox
    @inbox ||= Inbox.new
  end
end

class Inbox
  def initialize
    @inbox = {}
  end

  def add_to_inbox(msg)
    title = msg[0]
    body = msg[1]
    @inbox.store(title, body)
  end
end

module MsgReader
  def read_a(msg)
    title = msg[0]
    body = msg[1]
    puts "#{title}"
    puts "#{body}"
  end
end

module MsgComposer
  attr_accessor :title, :body
  def initialzie(msg={})
    @title = msg[:title]
    @body = msg[:body]
  end

  def compose(new_title, new_body)
    title = new_title 
    body = new_body
  end
end

module MsgDispatcher
  def dispatch_to(recipient, msg)
    @recipient = recipient
    @recipient.add_to_inbox(msg)
  end
end

# role: 1
author = User.new

# role: 2
recipient = User.new

message = MessageMe.new

# trigger: 1
message.compose_a_msg('Hello', 'world!')

# trigger: 2
message.dispatch_to(recipient, msg)

# Goal
message.read_a(msg)

There are probably errors in the above code preventing the objects that these classes create from actually working together, we could also refactor some things. But for now, the thing I wanted to point out was how we created explicit roles for the ‘actors’ of these contexts through naming.

The key thing to remember here has to do with naming of the two User objects, one playing the role of an author while the other plays the role of the recipient in our little scene.

Conclusion

To wrap things up, in the first post of this series we’ve learned that separating ‘state’ from ‘behavior’ leads to more modular code and makes reading code more of a pleasure since we aren’t being overloaded all behaviors of an @user stuffed into its class.

Instead we can read the file tree and see at a glance what our @user can do by quickly glancing at the behavior classes and looking at the roles we’ve defined, as we’ve learned above.

I’m still seeking a clearer picture of how to make this sort of distinction in my own code bases a reality and will be continuing with the final part of DCI, Interaction soon!

Stay tuned…

Advertisements

Categories: Ruby, Ruby on rails

Tags: , ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s