Monday, August 22, 2011

DCI in short - Can you fly that helicopter?

Trinity is the object, Matrix is the Context, HelicopterPilot is the role (injected runtime in Matrix).


It's obviously a simplification but overall I think this metaphor expresses the idea of DCI very well. Trinity represents the D (Data), Matrix represents the C (Context) and HelicopterPilot role along with the Helicopter itself (and other objects) represent the I (Interaction).

This example is good as it shows how your software can evolve. Your objects don't need to know upfront that they will play some roles, it's all runtime (as with Trinity and the helicopter).

Can you fly that helicopter?

Wednesday, August 17, 2011

Tracing aspect for a Rails application

Aspects are modules for crosscutting concerns. Typical crosscutting concerns are: persistence, tracing changes (history), permissions and logging.

Aspect Oriented Programming is not a popular topic in the Ruby community. Partially, it's because Ruby gives us some AOP constructs out-of-the-box (open classes) but also due to some built-in mechanisms in Rails - like filters and callbacks which serve as the dynamic part of AOP.

I think that there are scenarios in which traditional AOP can be very useful. Today, I'm going to show you how to implement logging of chosen method calls, without touching the methods itself.

Aquarium seems to be the best AOP framework with Ruby.

Installation

#the first part is only needed if you want to use ruby 1.9
#otherwise just put gem "aquarium" into the Gemfile and run "bundle install"

cd vendor/gems
git clone https://github.com/deanwampler/Aquarium.git
cd Aquarium
git checkout 1.9.1-port

# edit Gemfile and add:
gem 'aquarium', "0.0.0", :path => 'vendor/gems/Aquarium/aquarium'
bundle install

Creating an aspect


Create config/initializers/tracing_aspect.rb and paste:
require 'aquarium'
include Aquarium::Aspects
Aspect.new :around, :calls_to => :all_methods, 
    :for_types => [User],
    :method_options => :exclude_ancestor_methods do |jp, obj, *args|
  begin
    names = "#{jp.target_type.name}##{jp.method_name}"
    p "Entering: #{names}: args = #{args.inspect}"
    jp.proceed
  ensure
    p "Leaving:  #{names}: args = #{args.inspect}"
  end 
end

If you now run the tests or just use your app, you should see all the method calls on User objects being logged to the output.

I hope it works fine for you, let me know in case of problems.

Sunday, August 14, 2011

DCI patterns - how to write DCI contexts in Ruby

After my previous post about DCI and Rails some people contacted me regarding best DCI patterns. As the topic of DCI is still new I didn't want to engage into creating patterns - I think they should emerge from existing projects. The idea of DCI seems to propagate in the Ruby/Rails circles - there was a RailsConf talk on this topic and more DCI blog posts appear. If you haven't heard about DCI yet, please read my last post first: DCI and Rails.

Recently I got an email from Pavel Mitin in which he describes his pattern for creating DCI contexts in Ruby. As this pattern matches exactly with my approach I think it's worth sharing and recommending as a pattern.

This example consists of two base classes - Human and Address. Objects of the Human class can play two roles: Policeman and Thief, while the Address can sometime play the role of FakeAddress.

Splitting classes into roles and injecting roles runtime is only a small part of DCI. The bigger thing is the idea of Contexts, which you can also think like a User Story or a Use Case (as a big simplification). In Pavel's example we have the context of the Policeman arresting the Thief. In this case the thief object has the address object extended with a FakeAddress.

This example shows some interesting concepts. As you see we're not replacing the thief's address - as in this world we think that humans have one address. What we're doing is extending the address object and "overwrite" the to_s method runtime in the context of arresting. I assume here the to_s method abstracts the thing that the thief is "saying" to the policeman.

The most important part, however is the way the context class is written. ArrestContext is a class with a constructor and the execute method. It's the constructor job to wire all the relevant roles to the actors. Once the roles are injected the execute method can start the "procedure".


There are still questions remaining regarding the contexts. Who should access the context classes? Let's assume that we have an application object in our project which represents the whole system and that it's a web Rails app. Should the application object (a model) know about the contexts?

Here are some options:

1. the application object has access to all the possible contexts. The controller just calls methods like: application.register_new_user(..) and it's the application that initializes the context.

2. controller has the knowledge about the specific "global" context it handles: NewUserContext.new(..).execute

3. controllers as we know them (Rails) disappear, the wiring between actions and context takes place in a configuration file.

All of the Ruby DCI examples so far seem a little bit verbose. It's because they are direct translation from languages that are not as dynamic as Ruby. It's not my goal at the moment to create a nicer API but I'm pretty sure we can come up with nicer syntax. Can you help? Especially, I think that the context classes can become some kind of configuration files - what role to inject to which objects, then which method starts the "procedure".

I'd love to know your opinion on this topic. Does it make sense to you? Is the DCI concept clear to you?