How to understand DCI pattern
Asked Answered
G

3

10

According to Wikipedia Data, context and interaction (DCI) is a paradigm used in computer software to program systems of communicating objects. Here I am not clear about the problem which DCI tries to solve. Can you explain it with simple example? What is Data, Context and Interactions in your example?

Guzel answered 24/7, 2017 at 10:32 Comment(0)
C
13

An easy way for me to understand it is with the classic banking application example. In this example, I'll use Rails.

Let's say there's a feature of our app where users can transfer money from one account to another account.

We might have a controller that looks like this:

# app/controllers/accounts_controller.rb
class AccountsController < ApplicationController
  def transfer
    @source_account = Account.find(params[:id])
    @destination_account = Account.find(params[:destination_id])
    @amount = params[:amount]

    if @source_account.transfer_to(@destination_account, @amount)
      flash[:success] = "Successfully transferred #{@amount} to #{@destination_account}"
      redirect_to @source_account
    else
      flash[:error] = "There was a problem transferring money to #{@destination_account}"
      render :transfer
    end
  end
end

In here, we're calling transfer_to on one of our Account objects. This method is defined in the Account model.

# app/models/account.rb
class Account < ActiveRecord::Base
  def transfer_to(destination_account, amount)
    destination_account.balance += amount
    self.balance -= amount
    save
  end
end

This is a traditional MVC solution - when the transfer method on the controller is called, we instantiate a couple of model objects and call the behavior defined on the model. Like Robert said, the business logic is split up, and we have to look in a couple different places to understand the code.

The downside of this approach is that we can end up with a lot of behavior defined inside of our models that they don't always need and lacks context. If you've worked on a large project before, it's not long before model files grow to be several hundred or even a couple thousand lines of code because all of the behavior is defined inside of them.

DCI can help solve this problem by giving our data models behavior only within certain contexts that they need to use that behavior. Let's apply this to our bank application example.

In our example, the Context is transferring money. The Data would be the Account objects. The Behavior is the ability to transfer money. The Interaction is the actual action of transferring money from one account to the other. It could look something like this:

# app/contexts/transferring_money.rb
class TransferringMoney # this is our Context
  def initialize(source_account, destination_account) # these objects are our Data
    @source_account = source_account
    @destination_account = destination_account

    assign_roles(source_account)
  end

  def transfer(amount) # here is the Interaction
    @source_account.transfer_to(@destination_account, amount)
  end

  private

  def assign_roles(source_account)
    source_account.extend Transferrer
  end

  module Transferrer
    def transfer_to(destination_account, amount)
      destination_account.balance += amount
      self.balance -= amount
      save
    end
  end
end

As you can see from the example, the Data is given its behavior within the Context at runtime, when we call source_account.extend Transferrer. The transfer method is where the Interaction takes place. This prevents us from splitting logic into separate files and it's all contained inside one Context class.

We would call it from the controller like this:

# app/controllers/accounts_controller.rb
class AccountsController < ApplicationController
  def transfer
    @source_account = Account.find(params[:id])
    @destination_account = Account.find(params[:destination_id])
    @amount = params[:amount]

    if TransferringMoney.new(@source_account, @destination_account).transfer(@amount)
      flash[:success] = "Successfully transferred #{@amount} to #{@destination_account}"
      redirect_to @source_account
    else
      flash[:error] = "There was a problem transferring money to #{@destination_account}"
      render :transfer
    end
  end
end

With such a simple example, this might seem like more trouble than it's worth, but when apps grow really large and we add more and more behavior to our models, DCI becomes more useful because we only add behavior to our models within the context of some specific interaction. This way, model behavior is contextual and our controllers and models are a lot smaller.

Cordate answered 24/7, 2017 at 20:55 Comment(1)
Putting DCI into a code-only perspective like above is missing the bigger picture. The connection to the user mental model, and a mapping to code directly through use cases are some of the things that makes it more than just a design pattern.Spinks
S
5

The key aspects of the DCI architecture are:

  • Separating what the system is (data) from what it does (function). Data and function have different rates of change so they should be separated, not as it currently is, put in classes together.
  • Create a direct mapping from the user's mental model to code. The computer should think as the user, not the other way around, and the code should reflect that.
  • Make system behavior a first class entity.
  • Great code readability with no surprises at runtime.

I highlighted user's mental model because that's what it's really about. The system architecture should be based on the users thought processes, not the engineers.

Of course the mental model should be discussed and produced by everyone related to the project, but that's rare. Usually the engineers will code according to patterns, decomposition, inheritance, polymorphism, and the part of the code that makes sense to the user is obfuscated behind layers of structure.

This is what DCI tries to remedy. It has run across some resistance over the years, in my opinion because engineers love their structure and classes, so they focus primarily on that.

An illustrating code example would be too lengthy to post here, but the mindset is more important anyway. It's about objects dynamically working together, to solve specific problems. I have made a larger tutorial here, with some code: https://github.com/ciscoheat/haxedci-example

Also, I highly recommend the video A glimpse of Trygve for further explanation, by one of the DCI authors, James Coplien.

Spinks answered 25/7, 2017 at 10:42 Comment(0)
A
0

If you read this paper from the original authors, specifically the chapter "Where did we go wrong?", the authors give some reasons why they felt a new approach was needed.

In short: The authors complain, that proper Object-Oriented methodology leads to "splitting up" the business logic. This is true, as this is the primary reason we decompose problems, so that we don't have to tackle the whole logic in one go.

The authors argue (in the same chapter as above), that the previous procedural approach was better (giving the example of FORTRAN code), since one could read the code sequentially and decide whether it does what it is supposed to do.

They also argue (in the next chapter: Back into the Users' Head) that it is easier for developers to think about "data" first, and procedures (e.g. interactions) later.

The authors basically argue for at least a partial regression to procedural programming, clearly separating data and logic, in contrast to object-orientation which bundles "data and logic" together.

My personal opinion is, that it is slightly misleading to call this approach object-oriented, since it is a strong critique of it, with clear intention of deviating from it. But, don't take my word for it, read the Article.

Armageddon answered 24/7, 2017 at 11:55 Comment(1)
The authors do not argue that a procedural approach is better. Real objects are the focus of DCI, not the current class-oriented approach, where the decomposed approach you talk about makes the program far away from something that is based on a users mental model (which is the main DCI idea, not the engineering stuff.)Spinks

© 2022 - 2024 — McMap. All rights reserved.