Introducing DCI to the Perl world.
For those who are not aware, there is a newish methodology called DCI (Data, Context, Interactions) which attempts to solve the problems of OOP. DCI was designed and proposed by the same guy that created the MVC concept that has become hugely successful. DCI is an attempt to group methods with their use cases so that interactions used by business logic and algorithms are more predictable.
The key to DCI is a separation of concepts:
- Data: what the system is
- Context: A use case
- Interactions How objects interact within a context
I have created the DCI dist which includes helpers for writing Contexts and Interactions (DCI uses the terminology roles, but to avoid conflict with other perl concepts of roles I have called them casts.)
The DCI perl package can be found here:
If iframes are supported, this should show the synopsis for a common example of DCI.
Here are some links to information about DCI.
It can be hard to wrap ones head around DCI in the beggining. The important ideas are as follows:
Implement very simple data/model classes. You should avoid putting any methods into an object that implement business logic. Your data objects should not contain anything that requires utside context to understand.
When you have business logic, or an algorithm, you shoudl encapsulate it in a 'Context'. A context can be thought of much like a movie script. A context has many roles that need to be played. A single object may play any number of roles, however a role can never be played by more than one object. The context is responsible for assigning (or casting) the 'dumb' data objects, aka actors to the specified roles.
Within a context the idea of a role represents a set of methods an actor must provide. These methods only make sense within the greator context/encapsulation of the business logic or algorithm. You do not want these methods avalable to clutter or confuse the 'dumb' data object outside of the context.
The DCI::Context package provides sugar that makes defining a context very easy. You tell your context what roles need to be filled, and what Cast package should be used for that role. During construction you provide (role => dumb_object) for each role, the casts happen automatically. Once the roles are defined all you need is a method that kicks off the interactions for the algorithm/business logic.
The DCI::Cast concept of roles (or casts as my DCI package calls them) differ from the Moose concept or roles in one critical way. While both define methods that get injected into a root class, DCI's Cast methods are only present within the proper context; Outside of the context the DCI cast's methods are unavailable. Further this means that you do not need to import the cast/role when defining the class (wheras in Moose you must use the role in the package.)
This difference is particularily useful when you need to implement an algorithm that uses objects who's code is not under your control. With Traditional OOP you would subclass the objects you do not control, which can lead to messy hierarchies. In addition you may not control the code that produces the object instances in which case patching, or even worse moneky patching may be the only way to inject your methods.
With the DCI package you create casts, these casts wrap around a core object. The cast instance provides full access to the underlying object and it's API. In addition the cast object may define or override methods which you want to add to the underlying class. Finally the casts are also created with a reference to the context object which allows you to write context-specific interactions.