DCI
From APIDesign
Data, Context and Interaction is a paradigm used in computer programming. In some sense a modernized version of MVC ready for modular applications in the 21th century. Originally described at artima article. If you are seeking for official explanation of DCI read that article or start at wikipedia. Here you can find my thoughts and also mine and Geertjan's enthusiastic screencast that we recorded when we learned about the amazing suitablity of using DCI to explain behavior of modular applications.
Contents |
Vision
DCI separates a program into different perspectives where each perspective focuses on certain system properties. Code in the Data perspective specifies the representation of stand-alone objects. Code in the Context perspective specifies runtime networks of interconnected objects. Code in the Interaction perspective specifies how the networked objects collaborate to achieve the system behavior[1].
Screencast
When I learned about DCI I realized (with a lot of surprise) that the action system in NetBeans platform applications quite nicely fits the above stated DCI vision. Since then we are explaining cooperation of actions in modular applications with their context and various data coming from unknown sources in terms of DCI:
The progenitors of DCI, Trygve Reenskaug and James O. Coplien, got attracted by our screencast and challenged my claim that Lookup is a general tool to practice DCI in Java. I have to admit I have no proof of that. The screencast only demonstrates that the Lookup can be used in simple DCI-like scenario. The modular applications action management usually deals with a simple context containing one role or multiple roles of the same type. In such situation use of Lookup is appropriate. More general configuration still need deeper investigation.
Emotionally Attached to Model
The base difference mentioned in the screencast is that in MVC only the model is independent on the rest. The view, controller or presenter are always assumed to know what the model is and operate directly on it.
This is not true in DCI. The interactions are written without knowing the actual data. They are general and need to be turned into concrete ones by establishing proper context before they can be performed, executed.
Swing Mental Shift
I do remember arguing for ages with an experienced Swing designer that the (swing) actions are wrong and cannot be used in NetBeans. I was explaining it all, describing that action by itself cannot do much, that it needs some context and that nothing else can work in modular world. No chance, my message just could not pass the gap between modular and monolithic Swing mindset.
Now I know why! The Swing designer was imprisoned in the MVC mental model. For him a component/window represented the model and action was there to act on that model. In NetBeans this is different - the action is just an interaction. It does not do much by itself, it needs properly filled context to enable itself and invoke some operation. The context is then morphed by any window/component that wishes to be recognized by the interaction. It needs to morphs its data into appropriate context.
Quite easy if you have good theory to backup your reasoning with, isn't it?
Yet Another Layer
In some sense the DCI brings another level of indirection ("all problems in computer science can be solved by another level of indirection", can't they?). The interactions know only what context they need, not the real data - e.g. model. In the classical MVC terms the CI is itself an MVC and there is a bridge morphing the D to the new M. This may not seem like a really big change and indeed, technically, it is not. However the mental shift is huge!
Pitfalls of Unknown Model
There is another reason why differentiate between MVC and DCI. Recently we had a polemic discussing whether NetBeans uses Swing correctly or not. After receiving some comments I felt totally unsuitable to use Swing or even program. As this is not true, I started to seek for reasons why people say things like: Why was the event dispatch thread used for non-painting computation in the first place?
Swing is following the MVC design path. View displays its associated model. This means that during painting (on the event dispatch thread) one needs to query the model. The silent assumption here is that the model is going to answer quickly, not require really long computation. This is easy to achieve when one instantiates the whole MVC triad. However, modular applications are more like DCI - someone provides the data, someone else provides the interactions (for example actions, or various presenters) and someone completely else binds these elements together.
As a result we are not testing a single MVC triad, but a very big number of unknown triad's combinations. Each of the data (originally a model) is different, yet it gets morphed into the same context when necessary. However, same does not mean absolutely equal! Remember that abstractions leak! The context required by an interaction is an abstraction and all the morphed data shall be uniquely morphed to it. They can try, but still there will be differences. Some mappings may be faster than other and that is why sometimes it may be appropriate to query the data while painting and sometimes not.
For example recently we noticed an action in NetBeans that needed to find out whether currently selected project supports Java 5 or some later version. Given the advices of DCI it searched its context for a role called SourceLevel with a method returning the Java version of the selected project. Obviously it did this during painting to find out whether it shall be enabled or not. For most of the project types (usually Ant based) this worked fine. However for Maven projects this could took ages. Who's to blame?
Either the data are provided too slowly. Then the Maven would need to be sped up. However sometimes it just takes time to get an information. Then the interaction needs to be improved to deal with data not ready yet and the role interface in the context needs to be enhanced to allow expressing such temporary data unavailability. Various situations may require different solutions, but in general it is not possible to say AWT thread shall be used only for painting. It can be used only for that in MVC, but in the modular world this also requires well designed role interfaces and their proper implementation.
Dependency Injection
Is in DCI still a need for dependency injection? That is question asked by Andreas in the discussion section. I am not sure whether I am the most qualified person to answer the question, but certainly I have some opinions.
For me the DCI is a design paradigm. A general method to help us look, perceive, understand and solve problems we face when converting real world situations into computer understandable language. When using DCI one needs to choose some technology that supports binding of data through some context into the interactions. It can be dependency injection. It can be traits in Scala. It can be Lookup as in the example of action system in NetBeans.
What is the design model behind dependency injection? MVC? Hardly. Where is the model, view, controller? It is much easier to explain dependency injection in terms of DCI - there is some interaction class with setters and the process of injection needs to feed it up with proper context and data before it can be usable.
So DCI is a general concept and dependency injection is one possible way to realize it.
<comments/>