I've been studying the Streamflow code intensely for a while and I'm getting
a lot of very appreciated inspiration from it! One thing though that I've
been struggling with is the concepts of "Context" and "Interactions".
Between version 0.7-30 and 0.7-31 "Context" was renamed to "Interaction" in
several files in the dci.api (former dci.context) which suggests that those
concepts are not trivial. If the DCI api is becoming part of Qi4j, I would
like to bring up a discussion here about the terminology and hear what
Streamflow developers and others think.
I might certainly lack some deeper understanding of the DCI concepts and the
knowledge leading to the changes in Streamflow, but my instincts suggests me
to rename some of the DCI interfaces (now used in Streamflow). Below is a
list showing former -> current -> suggested names (former is before version
0.7-31) along with my reasoning and some examples to illustrate the
consequences (which I personally think are good):
InteractionContext -> Context -> RoleMap
Quote from Tryggve's Artima article about DCI (1):
- "... the algorithm and role-to-object mapping are owned by a Context
object. The Context "knows" how to find or retrieve the objects that become
the actual actors in this Use Case, and "casts" them to the appropriate
roles in the Use Case scenarios" (1)
The current Context class:
- Holds a role-to-object map
- Doesn't initiate any role casting.
- Doesn't know which roles are "appropriate" for the objects to play
- Doesn't know about any Use Case algorithm/scenario
It seems confusing to have a class named "Context" that doesn't match the
characteristics of the DCI concept "Context" as Trygve describes it above.
Since it only holds a role-to-object map, I would suggest to name it a
RoleMap.
Examples of current use:
1a) StreamflowRootContextFactory.getRoot( Context context )
2a) Context keeps parent role-to-object maps in a Context parentContext
field.
3a) RootContext, line 64: context.set(Object)
Same examples after suggested name change:
1b) StreamflowRootContextFactory.getRootContext( RoleMap rolemap )
2b) RoleMap keeps parent role-to-object maps in a RoleMap parentRoleMap
field.
3b) RootContext, line 64: rolemap.set(Object)
Context -> Interactions -> Context
- "The interactions that weave their way through the roles are also not new
to programming: we call them algorithms" (1)
- "... the algorithm and role-to-object mapping are owned by a Context
object." (1)
The Context *owns* (and initiates) the algorithms/interactions, and it also
owns the role-to-object mapping (the RoleMap, through SomeContext.Mixin) but
*is* not itself Interactions. If SomeContext extends "Context" instead, it
seems natural to say that "we have a Context" which is what SomeContext
*is*.
Currently:
1a) SomeContext extends Interactions
2a) StreamflowRootContextFactory extends RootInteractionsFactory
3a) In CommandQueryRestlet:
- line 164: Context context = new Context();
- line 166: initContext( request, context ) does context.set( Object,
roleClass )
- line 172: rootInteractionsFactory.getRoot( context ) returns a RootContext
- line 173: context = uow.metaInfo().get( Context.class )
- line 475: getInteractions( Object interactions, segments )
- line 481: if(interactions instanceof SubContexts)
- line 485: interactions = ((SubContexts) interactions).context( segment )
- line 502: interactions = interactions.getClass().getMethod( segment
).invoke( interactions )
Suggested:
1b) SomeContext extends Context
2b) StreamflowRootContextFactory extends RootContextFactory
3b) In CommandQueryRestlet:
- line 164: RoleMap rolemap = new RoleMap();
- line 166: initContext( request, rolemap ) does rolemap.set( Object,
roleClass )
- line 173: rolemap = uow.metaInfo().get( RoleMap.class )
- line 172: rootContextFactory.getRootContext( rolemap ) returns a
RootContext
- line 475: getCurrentContext( RootContext(?) currentContext, segments )
- line 481: if(currentContext instanceof SubContexts)
- line 485: currentContext = ((SubContexts) currentContext).context( segment
)
- line 502: currentContext = currentContext.getClass().getMethod( segment
).invoke( currentContext )
>From here follows naturally:
ContextMixin -> InteractionsMixin -> ContextMixin
To me it seems confusing that Some*Context*.Mixin extends
*Interactions*Mixin and implements Some*Context* that is extending
*Interactions*. We kind of have Context-Interactions-Context-Interactions
going on :-|
SomeContext.Mixin *holds* interaction methods but *is* not itself
"interactions" - it's a *SomeContext* implementation (implementing the
interactions as a result). To my mind it would therefore be natural to
extend a "ContextMixin".
Currently:
1a) SomeContext.Mixin extends InteractionsMixin
2a) InteractionsMixin @Uses a (Context)context
3a) InteractionsMixin.subContext(...) sets (Context)context to
(Context)subContext = new Context( context )
4a) InteractionsMixin.subContext( Class<SomeSubContext> interactionsClass )
returns SomeSubContext with subContext injected
Suggested:
1b) SomeContext.Mixin extends ContextMixin
2b) ContextMixin @Uses a (RoleMap)roleMap
3b) ContextMixin.subContext(...) sets (RoleMap)roleMap to
(RoleMap)currentRoleMap = new RoleMap( roleMap )
4b) ContextMixin.subContext( Class<SomeSubContext> subContextClass ) returns
SomeSubContext with currentRoleMap injected
1a-2a) "context" being a Context suggests that it's "in family with"
SomeContext - both "Contexts". But they are not. "context" is a
role-to-object map and SomeContext is a Context.
3a) I find it misleading that the method name ("subContext(...)") is equal
to the variable name "subContext" holding the role map.
1b-3b) SomeContext.Mixin is now conceptually related to SomeContext (both
extends Context*) and roleMap is distinguable as a different concept - a
RoleMap.
4) I thinks it's unnecessarily easy to confuse SomeSubContext with
subContext. "interactionsClass" is a Context class and "subContext" is a
RoleMap in my understanding, and I would therefore would like to name them
accordingly.
Adopting the name changes would of course have some deep impact on the
terminology used throughout the Streamflow project, and any reluctancy to do
that would be 100% understandable. But I think it's worth reconsidering the
terminology if the Streamflow DCI api is incorporated into the Qi4j
libaries/extensions.
What do you think?
Cheers,
Marc
(1)
The DCI Architecture: A New Vision of Object-Oriented Programming
by Trygve Reenskaug and James O. Coplien
March 20, 2009
http://www.artima.com/articles/dci_vision.html
Extracts from the article:
Entities...
- "At compile time programmers must face the end user's models both of Use
Case scenarios and the entities they operate on."
roles...
- "Whereas objects capture what objects are, roles capture collections of
behaviors that are about what objects do."
- "Roles provide natural boundaries to carry collections of operations that
the user logically associates with each other."
- "The collections of operations snipped from the Use Case scenario are
called roles."
- "At their heart, roles embody generic, abstract algorithms."
- "We use roles to capture the main user concepts that participate in a Use
Case requirement. Roles are first-class components of the end user cognitive
model, so we want to reflect them in the code."
Context...
- "... the algorithm and role-to-object mapping are owned by a Context
object. The Context "knows" how to find or retrieve the objects that become
the actual actors in this Use Case, and "casts" them to the appropriate
roles in the Use Case scenarios (we use the term "cast" at least in the
theatrical sense and conjecturally in the sense of some programming language
type systems). In a typical implementation there is a Context object for
each Use Case, and each Context includes an identifier for each of the roles
involved in that Use Case. All that the Context has to do is bind the role
identifiers to the right objects. Then we just kick off the trigger method
on the "entry" role for that Context, and the code just runs."
- "the Context object [...] knows, for a given Use Case, what objects should
play what roles."
Interactions...
- "The interactions, that describe end-user algorithms in terms of the
roles, both of which can be found in end users' heads."
- "these three [MVC] roles define interactions between the objects that play
them"
- "The interactions that weave their way through the roles are also not new
to programming: we call them algorithms"
- "each object must [...] implement behaviors that come from the user's
model of the interactions that tie it together with other objects through
the roles it plays in a given Use Case."
- "A method of one role interacts with other role methods in terms of their
role interfaces, and is also subject to the role-to-object mapping provided
by the Context."
--
View this message in context:
http://old.nabble.com/DCI-api-Context-Interactions-naming-tp29374400p29374400.html
Sent from the Qi4j-dev mailing list archive at Nabble.com.
_______________________________________________
qi4j-dev mailing list
[email protected]
http://lists.ops4j.org/mailman/listinfo/qi4j-dev