There's been a lot of interest in DCI among Ruby developers, and a lot of good discussion going on among some blogs about application architecture.
I've written about basic information on the concept which touched on some sample code. One main point to make is that our class oriented approach to application architecture is that we end up with junk drawer objects; objects which contain methods for any number of interactions that may be performed at some time during the execution of the application.
Mike Pack's article has been the first to discuss triggers for DCI in Rails (but correct me if I'm wrong). Triggers are the actions that initialize your Context to perform the algorithm.
When you develop your system with DCI one of the goals is to take your business use cases and describe them in your Context. When writing a use case you'll say that you have a specific preconditions, specific actors, and of course specific goals. But we can look to Alistair Cockburn for the full understanding of use cases.
Here are the main points about what a use case should do and some points about how we can apply this to our executable code. In Cockburn's words (with my comments afterward) use cases DO:
Hold Functional Requirements in an easy to read, easy to track text format. We can do this in code. Ruby is widely known for being easy to read and the community values beautiful code. As far as holding functional requirements, that should be very simple for executable code to do.
Represents the goal of an interaction between an actor and the system. The goal represents a meaningful and measurable objective for the actor. This is both an important aspect of your business, and an important aspect of DCI. When we're attempting to achieve our business goals, we should write software that is uniquely designed to do that. The Context is an object that encapsulates this concept.
Records a set of paths (scenarios) that traverse an actor from a trigger event (start of the use case) to the goal (success scenarios). In simple code this is easy enough to do with if/else
blocks or case
statements, for example.
Records a set of scenarios that traverse an actor from a trigger event toward a goal but fall short of the goal (failure scenarios). An example here might be the above if/else
blocks or perhaps a rescue
from an exception. A use case describes a complete interaction between the user and your system and it is the responsibility of your Context to implement this.
Are multi-level: one use case can use/extent the functionality of another. This is reflected in DCI in the fact that we want to achieve the vision of Alan Kay, to create a network of interacting objects much like biological cells or computer networks. A Context can trigger other Contexts within.
What you're attempting to do with DCI is not battle junk drawer objects with other junk drawer objects, but to implement business logic in an organized set. Take a specific need and describe it, including variations, in a single Context to coordinate the Data and Interactions. The Context has real meaning and real value to your business, it's not just a place to use extend
on your objects.
In Rails, your controllers should handle the user actions that trigger these use cases. You might have multiple ways to trigger a use case. For example in a typical view your user can interact with objects in your system but in admin view another user can do the same with perhaps an alternate scenario allowing him to override certain aspects of the scenario. It makes a lot of business sense to look at this use case and scenarios together, so why not put that code into one place? Why not create Context that explains all of this for us in executable code.
Put your use cases in a set of executable code and trigger it from wherever your interface requires it. Before you attempt this, begin first by writing your use cases. Use cases reveal the needs of the program and also show the value of the DCI Context in centralizing your business needs.
I'm writing about this and more in "Clean Ruby" a book about DCI in Ruby that is a collection of research and tips from my experience in working with large and small applications and making them easy to understand and maintain.