Domain Driven Design and SaveAll()

This is a discussion on Domain Driven Design and SaveAll() within the Object forums in Theory and Concepts category; In our domain driven design, we allow clients to consume a service that includes a "Save Step" method (public Step SaveStep(Step userStep). This works great for the consumers of the web service (easy call, just send back entire step object) and for persisting the step data to the data store (just send the step to the repos). It gets a little more complicated when we introduce the idea that SaveStep should, in addition to persisting data, trigger a specific event that is captured by an outside process, such as a workflow engine. A Step in this case is somewhat complex; ...

Go Back   Application Development Forum > Theory and Concepts > Object

Object Mix

Register FAQ Calendar Search Today's Posts Mark Forums Read
  #1  
Old 09-02-2008, 08:42 PM
Daniel C
Guest
 
Default Domain Driven Design and SaveAll()

In our domain driven design, we allow clients to consume a service
that includes a "Save Step" method (public Step SaveStep(Step
userStep). This works great for the consumers of the web service
(easy call, just send back entire step object) and for persisting the
step data to the data store (just send the step to the repos).

It gets a little more complicated when we introduce the idea that
SaveStep should, in addition to persisting data, trigger a specific
event that is captured by an outside process, such as a workflow
engine. A Step in this case is somewhat complex; a collection of
users, collection of documents, and permissions per user on the
documents. We need to trigger events such as user added, removed,
permission set added/removed, etc. Is there a best practice/pattern/
example to approaching this; basically, comparing the passed in step
to the persisted step and generating what has changed?

I could obviously write a very specific algo to compare the saved and
new steps, with hard-coded references to each component in the
Step...but this would be ugly and not very adaptable to changes in the
Step in the future.
Reply With Quote
  #2  
Old 09-03-2008, 11:31 AM
H. S. Lahman
Guest
 
Default Re: Domain Driven Design and SaveAll()

Responding to Daniel C...

> In our domain driven design, we allow clients to consume a service
> that includes a "Save Step" method (public Step SaveStep(Step
> userStep). This works great for the consumers of the web service
> (easy call, just send back entire step object) and for persisting the
> step data to the data store (just send the step to the repos).


<Hot Button>
Passing objects around like this does save some keystrokes in the short
term but it tends to lead to fragile applications that are difficult to
maintain. Passing object references is the worst form of coupling
because the receiver can do virtually anything with the object and some
of those things may be quite unexpected from the sender's viewpoint.
Another maintenance problem is that the sender implementation of the
objects may change and that may require changes to the receiver.

In effect, passing a problem space object effectively trashes
implementation hiding and bleeds cohesion across subsystem or layer
boundaries because such an object exposes the implementation of the
sender. (Computing space objects like String that are pure data holders
aren't a problem.) If one uses a general purpose interoperability
infrastructure to save even more keystrokes, one will also pay a
substantial performance penalty. All in all it is not a real good idea,
especially across distributed boundaries.

If you limit your interfaces to pure messages (i.e., {message id,
by-value data packet}) like events, the interface will tend to be finer
grained and will require encode/decode on each side but the application
will be faster, more robust, and far more maintainable. That's because
the encode/decode decouples the contexts so that the only thing shared
between them is the definition of the message. That allows each context
to interpret the message in a unique fashion for its local problem space.
</Hot Button>

>
> It gets a little more complicated when we introduce the idea that
> SaveStep should, in addition to persisting data, trigger a specific
> event that is captured by an outside process, such as a workflow
> engine. A Step in this case is somewhat complex; a collection of
> users, collection of documents, and permissions per user on the
> documents. We need to trigger events such as user added, removed,
> permission set added/removed, etc. Is there a best practice/pattern/
> example to approaching this; basically, comparing the passed in step
> to the persisted step and generating what has changed?


I am missing something here because I don't see the problem. B-(

An event is an announcement of some change in solution state. The event
is triggered by that change so it must be generated where the change
occurs. The event needs to be consumed by somebody who cares that the
state of the solution has changed in a particular way so the event is
addressed to whoever that is.

Connecting those dots is a pretty straight forward resolution of flow of
control. (In an event-based system one can rigorously, albeit sometimes
tediously, resolve flow of control with DbC by matching method post
conditions to the precondition for executing the receiver method.)

Once one has connected the dots, it should be obvious what information
about the source context needs to be supplied with the event for the
receiver. That information might be complex because of multiple users,
documents, etc. but that just means the message data packet gets bigger.

[Apropos of the point above: the more information needed, the more
valuable the encode/decode decoupling is. If the information needs to be
extracted from and loaded to multiple objects on each side, hiding those
objects is critical. That's because they are more likely to change than
the information needed across a distributed boundary. For example, the
service still needs the same information but the more objects there are
on the source side, the more likely it will be for the source to
reorganize its management of the information with object changes in its
implementation when requirements for just its subject matter change. But
if the objects are passed directly to the receiver, that will trigger
changes in the receiver as well.]

> I could obviously write a very specific algo to compare the saved and
> new steps, with hard-coded references to each component in the
> Step...but this would be ugly and not very adaptable to changes in the
> Step in the future.


This is just an example of what goes wrong when one passes problem space
objects around, especially across subsystem boundaries. If each
subsystem manages it own knowledge and behavior responsibilities in
isolation, then all one needs to define is a client/service protocol for
messages exchanged between the subsystems. Then the objects implementing
each subsystem are fully hidden and can be modified without touching the
protocol or the other subsystems. Nor does one subsystem need to
understand the implementation of another subsystem to do its thing.


--
There is nothing wrong with me that could
not be cured by a capful of Drano.

H. S. Lahman
hsl@pathfindermda.com
Pathfinder Solutions
http://www.pathfindermda.com
blog: http://pathfinderpeople.blogs.com/hslahman
"Model-Based Translation: The Next Step in Agile Development". Email
info@pathfindermda.com for your copy.
Pathfinder is hiring:
http://www.pathfindermda.com/about_us/careers_pos3.php.
(888)OOA-PATH
Reply With Quote
Reply


Thread Tools
Display Modes


All times are GMT -5. The time now is 03:53 AM.


Powered by vBulletin® Version 3.7.2
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
vB Ad Management by =RedTyger=

In an effort to better serve ads to our visitors, cookies are used on objectmix.com. For more information, check out our Privacy Policy.