Posts Tagged DCI

Ruby On REST 2: Representers and the DCI Pattern

Friday, December 16th, 2011

We talked about Representers earlier last week. Today, I wanna describe DCI and how it fits perfectly together with representers in Roar.

What is DCI?

For years we’ve been taught that “Fat Models, Skinny Controllers” is the way to organize code. Push all your domain code into your ActiveRecord classes. Many people, including me, agree that this is bullshit. This leads to bloated classes, usually combined with one or two object instances taking care of an entire workflow (aka request).

DCI is an architectural pattern that makes the model “fat-on-demand”: Data objects are enhanced with roles at runtime, but only when needed.

The DCI pattern consists of three concepts.

  1. Data objects are supposed to contain application data. Nothing else. This would be your ActiveRecord row instance, but without any predefined behaviour. Just data.
  2. Context objects define what is done in the current workflow. In Rails, a controller running an action could be a context object.
  3. Roles are behaviour for data objects in a particular context. In Ruby, a Rails controller could mixin a module (a “role”) into an empty model row and thus let it process something.

Hooray for DCI – But Why?

Now the thing is, I absolutely hate to hype something (except stuff I did, of course). However, DCI makes code better maintainable, easier to follow and way easier to test. Period.

BTW, did you already check out my new Roar gem? It’s hip!

Think of a classical model found in many Rails applications with maybe one hundred methods. Or fifty. Fifty methods to interfere with each other. In a DCI setup, an object has a limited behaviour scope. The limited knowledge makes it easier to debug and predictable.

One Model, Multiple Faces

Since representers are modules they fit perfectly into the DCI approach, making them roles. Let’s consider the fruit representer from last week, again.

require 'roar/representer/json'
 
module FruitRepresenter
  include Roar::Representer::JSON
 
  property :title
  collection :colors
end

You still can include this representer into its “host” class directly.

class Fruit
  include Roar::Representer
  include FruitRepresenter
end

The problem now is that the Fruit class is limited to one representation, only. Forever and a day you may only render one particular representation. The key about representations, however, is that one model may be represented by multiple, yeah, representations.

Now, back to the start, let’s assume the Fruit class is some empty ActiveRecord class without any prior knowledge of representations at all.

class Fruit < ActiveRecord::Base
end
 
lemon = Fruit.from_json("{\"title\":\"Lemon\"}")
#=> undefined method `from_json' for Fruit:Class

Yeah, there is no #from_json class method.

Representers On DCI

In order to use the DCI approach, we first need an instance. Here’s how the lemon instance, and only this instance, can be extended with the fruit representer.

lemon = Fruit.new.extend(FruitRepresenter)
lemon.from_json("{\"title\":\"Lemon\"}")
lemon.title #=> "Lemon"

Awesome! The built-in Ruby #extend method makes the lemon instance aware of its representation and mixes in #from_json and friends.

Naturally, this works in both ways.

orange = Fruit.find_by_title("Orange")
orange.extend(FruitRepresenter).to_json
#=> {"title":"Apple","colors":["green"]}

The mixed-in representer also lets us render the JSON document.

Gimme Complexity!

On a flat level with single objects, this works out-of-the-box with recent Roar/representable versions. Problems arise when we have nested setups.

module BowlRepresenter
  include Roar::Representer::JSON
  include Roar::Representer::Feature::Hypermedia
 
  property :location
  collection :items, :as => Fruit,
    :extend => FruitRepresenter
 
  link :self do
    "http://bowl/#{location}"
  end
end

Using the :extend option we can give representable a hint about the representer to use when rendering/parsing contained objects.

And, hey, this works.

empty_bowl = Bowl.new
empty_bowl.extend(BowlRepresenter)
emtpy_bowl.from_json("{\"location\":\"kitchen\", \
  \"items\":[{\"title\":\"Lemon\",\"colors\":[]}]}")
 
puts empty_bowl.items.first.title #=> "Lemon"

Discussion Needed!

Having representers on an object level makes the whole thing really clean and versatile. You can test document rendering and parsing without polluting classes. And you can have a FruitRepresenter, a RottenVegetableRepresenter and what else you like for your orange instance. BTW, oranges ain’t no vegetables.

We still discuss about the API and need your opinion. Right now, we got this

collection :items, :as => Fruit,
    :extend => FruitRepresenter

Here, :as describes the class that encapsulates the contained data. The :extend option helps representable to find the correct module for the nested item. Now, what about this?

collection :items, :class => Fruit,
    :module => FruitRepresenter

Does that make sense? These options really just describe what’s on the right side of the hash rocket. Thanks to Scott for discussion here. Now, tell us your story!

Are Class Methods Evil?

Wednesday, July 20th, 2011

Two things I like in programming: Object instances and abandoning global things.

I especially appreciate any DCI effort in the community helping us getting away from classes back to thinking about objects and clean responsibilities.

In order to explain my thoughts about DCI, here’s a first post about class methods, which seem to be a crucial problem in this newer approach.

A tweet from my good friend Michał Łomnicki recently made me think about class methods in Ruby. What he was basically saying is that class methods suck.

I’m more and more against using class methods. It often leads to procedural-like programming.

From a rant perspective I’ll second that and agree. However, class methods have a certain purpose, so let’s discuss it in this post.

What Is a Class Method?

Class methods are global methods. You may access and call them from anywhere since you don’t need an object instance.

class User
  def self.find(id)
    # ...
  end
end

In order to find a certain User instance you call the class method #find on the User class. I personally find this a handy thing.

michal = User.find(1)

As we’re creating a fresh instance we command the class to do so. And since there is no user instance around, yet, we have to use a class method rather than an instance method.

What’s the Problem With Class Methods?

Now, class methods come in handy – you don’t have to think about the context as they’re available everywhere. Consider the following misuse of a class method.

class User
  def self.email_to(id, email)
    user = User.find(id)
    Emailer.send(email, "Hello, #{user.name}")
  end

It’s obvious that #email_to has to be refactored to an instance method. Nevertheless, I see code like that quite often. Just for completeness, here’s a better version.

class User
  def email_to(email)
    Emailer.send(email, "Hello, #{name}")
  end

Object-oriented vs. Procedural

What makes the class method example being bad style is that we’re in an object-oriented environment. Maybe we can break that down to the advise “Use object instances wherever possible.”

In the example, the programmer didn’t see that the email behaviour (aka method) is tied to an instance rather than to a class. His user code will look like the following.

User.email_to(1, "michal@snatch.pl")

If subsequent method calls like this would follow, this could be considered procedural code as we’re not working on object instances but on globally available methods. And, yeah, I personally don’t like global things when it comes to programming.

Avoiding Class Methods

Right now, I can come up with two reasons for having class methods.

  • The programmer didn’t analyze his problem sufficiently, does not see the coupling to an instance and simply pushes the behaviour into a class method. That happened in the last example.
  • There simply is no object instance available at this system state and we’re urged to use a class method.

On first sight, there seems to be no way out for the latter.

Abandoning Class Methods?!

There are strong opinions on the net that class methods shouldn’t be used at all (except for the constructor, of course). I’m still unsure here.

Anyway, in a lot of cases class methods can be replaced with instance methods on factory or builder objects.

michal = user_factory.find(1)

This implies a user_factory instance is around. So my question is: Where would this come from? There must be some kind of initial class method call somewhere in the chain of actions. I’d love to see some reactions and comments on that.

Class Methods and DCI

The reason I’m writing this here is that I like the DCI approach where you dynamically extend objects at runtime according to system state.

Object instances include required behaviour and then, they die. No pollution on class layer.

This works great with instance methods but there are big problems when it comes to class method usage (see the next post). So – are class methods evil?