I'm writing a sample app in Qi4j using DCI, and the whole thing is to be
exposed as a REST API in the end. Writing commands as interactions is
pretty straightforward, but what I'm wondering now is whether to include
the view methods in the context as well.
The app is a basic webforum-type thing (Forum->Board->Topic->Post domain
model). When I view a Board I should be able to create a topic, for
example. But for viewing it, I need to expose state that can be used to
either just view it, or make a decision to create a new topic.
What is the general feeling for how to do this best? Should methods for
doing that be included in the context, or should that type of code be
put directly into the REST layer on top of it?
My personal take is that if a context is to model a use case, then
queries are a big part of that. A user should always do a view request
first to get the current state, then make a decision on what to do, and
then do it. But I haven't seen any examples thus far (or maybe I just
missed it) where contexts expose methods for doing such queries.
What are your thoughts on it?
/Rickard
Oh, I definitely have more than just an execute method. I have as many
methods as I have interactions within that context, but up until now
they have mostly been for executing commands that change state. What I'm
wondering now is whether to include view-type methods as well, because
from a use case point of view that is definitely needed. I.e. "given
this selection of objects, show me a view for it so I can make
decisions, and then act on those decisions".
Technically I could have one context for returning the view, and then
another for executing the commands, but it seems unnecessary, and was
wondering how others have solved this, and whether it is fundamentally
right or wrong to do it like this.
/Rickard
No no, nothing like that. I'm talking about returning the data needed
for the view. If that is rendered as JSON, XML or HTML is up to the
actual View to decided, in my case the REST API.
/Rickard
Sure, here's an example. When viewing a Post on a Board in the Forum, it
must be possible to reply() to it. But first step is to view the post:
public class ViewPostContext
implements IndexContext<Post>
{
ViewPost viewPost = new ViewPost();
ReplyTopic replyTopic = new ReplyTopic();
Poster poster = new Poster();
public ViewPostContext bind( @Uses Topic topic, @Uses Post post,
@Uses User user )
{
viewPost.bind( post );
replyTopic.bind( topic );
poster.bind( user );
return this;
}
@Override
public Post index()
{
return viewPost.self();
}
public Post reply( String message )
{
return replyTopic.reply( message, viewPost );
}
class ReplyTopic
extends Role<Topic>
{
@Structure
Module module;
public Post reply( String message, ViewPost viewPost )
{
Post post = module.currentUnitOfWork().newEntity( Post.class );
post.message().set( message );
post.createdBy().set( poster.self() );
post.createdOn().set( new Date(
module.currentUnitOfWork().currentTime() ) );
post.replyTo().set( viewPost.self() );
self().lastPost().set( post );
Numbers.add( self().postCount(), 1);
return post;
}
}
class ViewPost
extends Role<Post>
{
}
class Poster
extends Role<User>
{
}
}
---
I'm using the wrapper approach, as a test of what happens, but the main
question right now is whether the index() method should be included or
not. I *could* put this straight into the REST API on top of this
context, but that makes it harder to reuse this context in testing,
where the test would call index() to get the Post, make some decision,
and then reply() to the Post.
/Rickard
I did it that way so that after bind() there are no other references to
the original data objects. There might be methods added later also,
depending on what interactions I add.
> Other question: is the context instantiated one time for each call to
> index() and reply()?
Since it's a REST API, for each request.
> And "index" is a weird name to give a method which shows a post.
That comes from this being used mainly to back a REST API, i.e. it maps
to "index.html" or "index.json".
/Rickard
I'm writing a sample app in Qi4j using DCI, and the whole thing is to be exposed as a REST API in the end. Writing commands as interactions is pretty straightforward, but what I'm wondering now is whether to include the view methods in the context as well.
Since the query in itself doesn't include any logic I found that it was natural to have a query package within what I call a "Communication" layer - the layer that communicates with the user (probably similar to your REST API or a "Controller" layer) where I would have "Query objects" that retrive whatever data the view wants. Queries can change with the needs of the views and shouldn't have an impact on the Context layer (and thus not used for testing the Contexts either).
Right, so in my case I would just have the REST resource classes get
whatever they need, without having to go through a context. Sometimes
that makes sense, especially with the simple cases. Sometimes the query
*does* involve quite a bit of domain-related logic however, and for
those cases I suppose it would make sense to put it in the context, as
the context bindings are actually required to make a decision on what to
return.
> I found it interesting to see that queries mapped to steps in
> "User-Goal" use cases (see Cockburn pp 61) and commands to steps in
> "Subfunction" use cases! So we end up having two levels:
<snip>
> Does this make sense? (see also
> http://marcgrue.com/dci/dci-sample/use-cases where I talk about this too).
I think it makes sense... still struggling with all this, trying to
figure out what it turns out to in actual code.
/Rickard
On Oct 7, 2011, at 10:20 , Marc Grue wrote:Since the query in itself doesn't include any logic I found that it was natural to have a query package within what I call a "Communication" layer - the layer that communicates with the user (probably similar to your REST API or a "Controller" layer) where I would have "Query objects" that retrive whatever data the view wants. Queries can change with the needs of the views and shouldn't have an impact on the Context layer (and thus not used for testing the Contexts either).I am scratching my head.In an OO world, the Controller and View *together* "talk" to the user. These environments are not layered per se: they are flat from one perspective and fractal from another. Controllers are not a layer.
I view a Context as a use case. A use case is a collection of related scenarios. I can see having an execute method for each scenario (i.e., for each use case deviation).