Triggering the DCI Context

by Jim Gay

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.

Clean Up Your Code

If you want more information about cleaning up your objects, classes, and code, then check out Clean Ruby, an ebook which will describe ways to keep your code clean, maintainable, and focused on business value. Make your OOP more obvious, easier to understand, easier to test, and easier to maintain.

Comments

Nicholas Henry said on Wednesday, February 08, 2012:

Looking forward to reading this post, Jim. Just a quick correction, it's Firsthand, not Freehand :-) Cheers!

Jim Gay said on Wednesday, February 08, 2012:

So sorry about that, Nicholas! I've corrected it.

Mike Pack said on Wednesday, February 08, 2012:

Nice post Jim. Use cases are the driving factor behind getting the system to function as the end-user thinks.

I find the multi-level discipline quite interesting. It seems like straying too far down the multi-level path can lead to some unmanageable code. Maybe 2 or 3 levels deep would be manageable but thinking about contexts as 5 and 6 levels deep would get overwhelming. I could see this getting out of hand in the name of keeping context DRY. In the case of 3+ deep context leveling, I would personally rather repeat logic in two contexts than try to separate that logic out. It's my gut feeling that this would be much more readable to the next programmer.

Jim Gay said on Wednesday, February 08, 2012:

Good point, Mike, but we could probably argue different things and mean the same without concrete use cases. I left those out of the post because I don't want to distract with implementation details, but if you have the need for 5 of 6 levels of nested business processes, then you're probably looking at a problem with the business. Although, maybe not. The devil is in the details.
Thanks for your comment.

Mike Pack said on Wednesday, February 08, 2012:

@jim You're probably right. I can't contrive an example that would need nesting that deep but I can imagine DRY evangelists might take it too far thinking "well, this could be used elsewhere in another context, I'll break it out into it's own context". Just a thought.

Ben Morris said on Tuesday, February 14, 2012:

Jim, thanks for the post. I really like the side-by-side comparison against the definition of a use case. It helps to underscore the goal of what DCI & clean code is about.

You talk about implementing a use case in code. Are you talking about displacing other artifacts (i.e. if the code is readable enough, than why have another duplicative use case in some other document format)? Similarly, would you see this working in concert with something like Cucumber, which is designed to bridge that gap of readable-but-executable, or is a use-case-as-DCI readable enough?

Also, one small comment: I suggest spelling out the acronym at the start of the post. I always struggle to remember what DCI stands for (which may be a problem in the light of discussion on well named things within software, but that's a bit of a tangent).

Post a comment


(required, but not displayed)

(optional)



(required)

1999 - 2012 © Saturn Flyer LLC 2127 S. Oxford St. Arlington, VA 22204

Call Jim Gay at 571 403 0338