[Persistence-sig] A simple Observation API

Phillip J. Eby pje@telecommunity.com
Wed, 31 Jul 2002 19:34:31 -0400


At 06:19 PM 7/31/02 -0400, Jeremy Hylton wrote:
>[Meta-comment: I'm sorry it's taking us so long to reach some kind of
>understanding on this issue.  It seems like we keep talking past each
>other, but I'm not sure why.]
>
> >>>>> "PJE" == Phillip J Eby <pje@telecommunity.com> writes:
>
>   [I wrote:]
>   >> If I understand this example correctly, then there are three
>   >> different objects that implement the resource manager interface:
>   >>
>   >> 1. persist->XML
>   >> 2. XML->Database
>   >> 3. Database
>   >>
>   >> It sounds like the application code only interacts with 1, and
>   >> that 2 and 2 should be considered implementation details of 1.
>   >> Thus, only 1 should register with the transaction, since it's the
>   >> only independent entity.
>   >>
>   >> When the transaction commits, it first calls prepare() on 1.
>   >> This delegates the responsibility for the commit to 2, which in
>   >> turn delegates to 3.  So for 1 to return True from its prepare, 2
>   >> and 3 must also return True.
>   >>
>   >> Why doesn't this work? :-)
>   >>
>
>   PJE> Because 3 would be shared by other objects also being persisted
>   PJE> to that SQL database, for just the first thing that comes to
>   PJE> mind.
>
>If you call prepare() twice on a resource manager, it should return
>the same answer both times, right?  If so, then it shouldn't matter if
>the same resource manager is being used as a top-level component and
>an internal component.  It will perform its prepare work the first
>time it is called and then just return its vote the second time it is
>called.

The greater the guarantees that the transaction can give in its contract to 
the resource manager, the easier it is to write resource managers.  I think 
that we should err on the side of making the transaction core more complex, 
if it makes implementation of other components easier.  Specifically, the 
transaction should make guarantees that certain methods will be called a 
specific number of times (as I proposed in the Straw Man API), because it 
makes the resource manager code simpler -- i.e., less boilerplate needed to 
write them.


>   PJE> But that's an implementation detail.  This is primarily an
>   PJE> architectural issue.
>
>I agree that it's an architectural issue.  (It's good that we agree on
>some things <wink>.)  The example above sounds like a component-based
>system, where there is a compound persist->xml->database component.
>The subcomponents of this entity should not be registering themselves
>with the transaction manager.  A component should control all
>communication of its constituent parts with other components.

Er, no.  See my first point.  The "database" component, in the specific 
application example I have in mind, is *shared*.  In addition to 
persist->xml->database there's also some persist->database taking place, on 
different objects stored in the same relational back-end.

To re-state, there is *not* a three-part-component composed of three data 
managers, there are three data managers, loosely coupled via the objects 
they manage.

You seem to be assuming that there's only one data manager to an 
application.  I expect to be dealing with a variety of application 
scenarios where I will have a *bunch* of them, each written relatively 
independently of the others.  In most cases, they'll have little indirect 
coupling to underlying data managers.  But it will happen sometimes.


>   PJE> Data manager 1 is generic code written to work on an XML DOM.
>   PJE> It shouldn't have to *know* that the DOM *is* persistent, let
>   PJE> alone *how* it's persisted.
>
>The description of the first component implies that is supports
>persistence objects and stores them using another component that
>stores XML.  That top-level component *must* know how to handle
>persistent objects and transactions, as it implements those
>interfaces.

As Jim would say, Waaaaa!  :)

My whole point is that I don't *want* to have a "top-level component" in 
order to implement this scenario.  It seems a poor component architecture 
that doesn't support delegation without implementation knowledge, and 
that's what you're asking for here.  To create this top-level component, it 
has to know about implementation details of its children.  But if the data 
managers are simply peer transaction participants, this is unnecessary.


>   PJE> You're calling for the placement of global architecture
>   PJE> knowledge into individual components, that should only be known
>   PJE> at a higher abstraction level.
>
>I thought I was arguing the opposite.  Individual components should
>not all talk to the global transaction manager.  Instead, when a
>component is assembled, the parts should be wired together so that
>each knows who to communicate with.

The application simply says, "Hello Mr. Transaction Manager.  I'll be using 
the following collection of data managers today.  Kindly inform them when 
you have something going on that they need to know about."  That is a *lot* 
different than the degree of implementation knowledge required to assemble 
compound data managers.  For one thing, it requires considerably less skill 
on the part of the application developer.