coding dependency_injection labs

DI Matters: Structuring Commands for clarity

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 😀

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