DI Matters: Structuring Commands for clarity

December 20, 2013 Rasheed Abdul-Aziz

I like using command objects as the ‘crux’ of my controllers. They encapsulate behavior without making models or controllers thick.

I think of commands as reactions to a signal (event). To produce a command I think first of the signal it is responding to. Let’s use an example:

class WidgetController < ApplicationController

  # We're assuming there's sufficient complexity in publishing
  # a widget to warrant a command.
  def update
    publish_command.execute(params[:widget]) if params[:publish]
  end

  private

  def publish_command
    Widget::PublishCommand.new(WidgetParamsParser.new)
  end
end

The ‘signal’ that WidgetController emits is ‘Publish the widget’. It sends the only thing which is topical to this signal, the widget in question. This is a contextual dependency.

The command inverts control, passing it a parameter parser that knows how to deal with the representation used. This is a constructional dependency. In this particular case, I think it would be preferable to extract the builder for the PublishCommand because it’s no concern of the controller’s. Constructional dependencies have nothing to do with the signal.

I make the distinction between constructional and contextual dependencies so that I can communicate the intent of the command more clearly. By default I place constructional dependencies in the initialize method, or I define getter/setter dependencies, often with a clear default.

Another approach to construction injection defaults is highlighted here.

If we used some kind of orthogonal dependency injection framework, we could define a container that configures the common constructional dependencies for us. But that’s a topic of another post :D

For completeness, here’s a stub of Widget::PublishCommand

module Widget
  class PublishCommand
    def initialize(representation_parser)
      @representation_parser = representation_parser
  end

  def execute(widget_representation)
    normalized_widget =
      @representation_parser.parse(widget_representation)

    # complex stuff with widgets here
  end
end

About the Author

Biography

Previous
Open Source Analytics Library MADlib Receives Site Relaunch, v1.4 Release
Open Source Analytics Library MADlib Receives Site Relaunch, v1.4 Release

MADlib, the open source analytics library shepherded by Pivotal data scientists and UC Berkeley researchers...

Next
Pivotal People—Roman Shaposhnik, Founder of Apache Bigtop Joins Pivotal
Pivotal People—Roman Shaposhnik, Founder of Apache Bigtop Joins Pivotal

Pivotal is proud to announce a new addition to our Hadoop leadership team, Apache Bigtop founder Roman Shap...