As I mentioned to Rickard offline; I don't get it and suggest the full
codebase for both cases before I have any bigger opinion, since it is
likely I misunderstand what is written below.

-- Niclas

On Thu, Aug 18, 2011 at 2:53 PM, Rickard Öberg <[email protected]> wrote:
> Hi guys,
>
> On the DCI mailing list, there has been a lot of discussion about how to
> actually implement roles, and what is the "proper way" and what is the
> "practical way", and so on. Lately I came up with a variant that seems to
> fulfill all the semantical and syntactical criteria, with the only problem
> being that the roles are not actually part of the object, but instead are
> implemented as wrappers. So, I wanted to run this by you guys and get your
> views on this.
>
> Here's the old way: an Entity would have Data, i.e. Properties and
> Associations, and with methods to modify these formulated as imperative
> Commands (i.e. "changeFoo"). These can internally be handled by just doing
> it (i.e. check if command is ok, and if yes, apply to state), or it can be
> done by using event sourcing (i.e. do command check and then call event
> method that in turn does the state change). Here's an example from
> Streamflow:
> @Mixins(Groups.Mixin.class)
> public interface Groups
> {
>   Group createGroup( String name );
>
>   ... methods removed for brevity ...
>
>   interface Data
>   {
>      @Aggregated
>      ManyAssociation<Group> groups();
>   }
>
>   interface Events
>   {
>      Group createdGroup( @Optional DomainEvent event, String id );
>
>      void addedGroup( @Optional DomainEvent event, Group group );
>
>      void removedGroup( @Optional DomainEvent event, Group group );
>   }
>
>   class Mixin
>         implements Groups, Events
>   {
>      @This Data data;
>
>      @Service
>      IdentityGenerator idGen;
>
>      @Structure
>      Module module;
>
>      public Group createGroup( String name )
>      {
>         Group group = createdGroup(null, idGen.generate(GroupEntity.class));
>         group.changeDescription( name );
>         addGroup(group);
>         return group;
>      }
>
>      public Group createdGroup(@Optional DomainEvent event, String id)
>      {
>         return
> module.unitOfWorkFactory().currentUnitOfWork().newEntity(Group.class, id);
>      }
>      .. the rest of the methods removed for brevity ...
>   }
> }
> ---
> The above is then extended by an entity interface that needs "Group
> management", in my case an OrganizationalUnitEntity.
>
> So once you have a "Groups" entity, you can invoke the commands directly.
> With DCI, the "createGroup" method would only be called from a GroupsContext
> where the interaction exist.
>
> The new way: since GroupsContext is basically the only place from which you
> would do this, and it represents a particular usecase, the "createGroup"
> method actually belongs in a role in the context, which is only valid *from
> within that context*. So, the way to do this is to implement GroupsContext
> as a class and then do the Groups commands thing as an inner class that
> wraps a Groups object that has Events+Data:
> public class GroupsContext
> {
>   // Injection
>   @Structure
>   Module module;
>
>   GroupsAdmin groups;
>
>   public GroupsContext()
>   {
>      groups = new GroupsAdmin(); // Create wrapper
>   }
>
>   public GroupsContext rebind(Groups groups)
>   {
>      this.groups.bind(groups); // Bind wrapper
>      return this;
>   }
>
>   public Iterable<Group> index()
>   {
>      return groups.index();
>   }
>
>   public Group creategroup( StringValue name )
>   {
>      return groups.createGroup( name.string().get() );
>   }
>
>   class GroupsAdmin
>      extends Role<Groups>
>   {
>      Iterable<Group> index()
>      {
>        return self.groups();
>      }
>
>      Group createGroup(String name)
>      {
>         Group group = self.createdGroup(null,
> module.serviceFinder().<IdentityGenerator>findService(IdentityGenerator.class).get().generate(GroupEntity.class));
>         group.changeDescription(name);
>         self().addedGroup(null, group);
>         return group;
>      }
>   }
> }
> ---
> The way to use this in client code would be:
> new GroupsContext().rebind(groups).createGroup(newName);
>
> The benefits with this solution are:
> * You can create any number of contexts and roles that uses the basic
> data/event methods, and don't have to worry with method clashing (major
> issue without this solution).
> * Role code can access members of the Context that wraps it, e.g. "module".
> If there were more bound objects, those could be accessed directly instead
> of having them be passed as method arguments to role methods.
> * Easier to see the algorithms as they are directly in the context, rather
> than having to go one step down into some external mixin.
> * Roles are only visible/usable from within the context that defines them.
> * Very clear what the dependencies of the context are.
> * Invisible from outside that DCI is being used.
>
> The drawbacks I can see are:
> * Since the roles are wrappers you have to think about what to pass around:
> wrapper or self() (will almost always be self() since wrapper class is
> unknown outside of context)
> * Right now cannot use concerns/sideeffects/constraints on inner classes.
> Can still use on context interaction if implemented as transient though.
>
> I'm sure there are more benefits and drawbacks, but this is what I can see
> right now. If anyone has other ideas, that would be great. IF this solution
> is acceptable, then that changes quite a bit what the typical usage pattern
> of Qi4j in a DCI setting would be, so it is kind important. It also makes it
> easier to use DCI outside of Qi4j, since there's nothing really in the above
> that requires Qi4j, from a pattern point of view.
>
> WDYT?
>
> /Rickard
>
> _______________________________________________
> qi4j-dev mailing list
> [email protected]
> http://lists.ops4j.org/mailman/listinfo/qi4j-dev
>



-- 
Niclas Hedhman, Software Developer
http://www.qi4j.org - New Energy for Java

I live here; http://tinyurl.com/3xugrbk
I work here; http://tinyurl.com/24svnvk
I relax here; http://tinyurl.com/2cgsug

_______________________________________________
qi4j-dev mailing list
[email protected]
http://lists.ops4j.org/mailman/listinfo/qi4j-dev

Reply via email to