[Zope-dev] Externalize or Adapt? (ZPatterns)

Phillip J. Eby pje@telecommunity.com
Fri, 09 Jun 2000 11:23:38 -0500


At 05:46 PM 6/9/00 +0800, Mike wrote:
>Great! Excellent!
>Thank you Phillip for a good explanation.
>I guess should write something like for the ZPatterns Wiki.

Ty added it yesterday, and I've linked to it as DropZoneExample from
various points in the Wiki.

>
>One more thing we still need is a set of 'right hand' rules.
>Let me try to formalize ZPatterns-based design process.
>
>1. Write scenario (client comes to skydiving office blah blah blah...)
>2. Detect roles learning scenario (Orders, Planes, Students etc)
>3. Create an empty (blackbox) Specialist for each role
>4. Populate the specialists with methods implementing roles
>5. Create (whitebox) specialists implementing scenario
>
>Thus, the object classes (Customer, Order) went nowhere. The things
>ruled by black specialists are just identity markers, without methods,
>types and names.

Not quite.  There are three problem domains here: two reused horizontal
domains (accounting and resource scheduling) and one vertical domain
(skydiving facility).  The two horizontal domains contain blackbox
Specialists such as Invoices and Reservations.  You don't modify the black
boxes, because that's what you're reusing.  The horizontal domains also
contain whiteboxes: Customer, Resource, ResourceUser, etc.  These just
contain the data handling needed to adapt a "Party" or other basic object
to be usable as a Customer or ResourceUser.  These whiteboxes are your hook
point to interface the framework to a larger application.  You just tell it
where "Party" objects are.


>Or is the object an specialist specific internal abstraction which never 
>leaves specialist's frames and have methods and type just for
>specialist's fun?

Not quite.  See below.


>"Phillip J. Eby" wrote:
>> First, I'm going to create some ZClasses, and specialists to go with them:
>> SkyDiver, Pilot, Airplane, FlightManifest, RentalTicket, RentalItem
>> (w/subclass for Parachute, Helmet, and certain other specific items).  Then
>> I'm going to set up the Resources and Products specialists to access my own
>> specialists for these ZClasses.  (Notice that I am going in and directly
>
>How you will set up those specialists? By adding 
>get(Resources|Products)Specialist methods?

I will add a "retrieveItem" method to the Specialist which, instead of
accessing a rack in the local specialist (the default implementation), it
will instead call (for example) SkyDivers.getItem().  Thus, when you call
Customers.getItem(), you will actually get an object from the SkyDivers
specialist.  In other words, I make the horizontal domain specialist
delegate to the vertical specialist.


>> that a Party plays in a resource scheduling system.  SkyDiver, then should
>> implement a Party interface, allowing it to be *used as* a Customer or
>> ResourceUser.  Thus, SkyDiver can be used by *any* framework that needs to
>> collaborate with a Party object, although it may have a new *role* in which
>> the party will be used.  For example, if I later add a curriculum
>> management system to cover my skydiver training courses, I will want
>> SkyDiver to fill the Student role.
>
>Well, we have two specialists, implementing roles (again, who _actually_ 
>implements the role, specialist or class, CustomerSpecialist or
>Customer?). 

The SkyDiver implements its own behavior.  The Customers specialist
implements anything relating to customers as a group, or to creating a new
customer.  To do this, it may have to ask the SkyDivers specialist to do
things on its behalf.  For example, if the billing system lets you add
customers, it will end up actually asking the SkyDivers specialist to add a
SkyDiver, and will use the SkyDivers specialist's forms to get the
necessary information to create one.


>Now, "SkyDiver ... *used as*" means we should:
>
> 1. subclass (not a good choice)
> 2. implement interface
>    2.1. by copying and pasting methods code (or whole methoids)
>    2.2. by proxiyng (SkyDiver has a references to actual Customer 
>         and ResourceUser)
>    2.3. by transmitting messages to SkyDiverSpecialist which will pass 
>         unhandled messages to CustomerSpecialist and
>         ResourceUserSpecialist (this is a variant of 2.2. case)
>
>The 2.3. case means we should use objects without types (identity
>markers).

None of the above.  SkyDiver should inherit from a Party base class.  For
Customer and ResourceUser behavior, one adds propertysheets whose class is
provided by the respective frameworks.  This is extension through
*composition*, rather than inheritance.  It is similar to the COM approach,
where you can ask an object to give you a pointer to an interface.  In this
approach, you ask for a propertysheet that provides the interface.


>> I will also make some changes to each of these specialists to replace
>> certain common UI snippets to be relevant to the kinds of things I'm
>> dealing with.  For example, in the Customers and ResourceUsers Specialists,
>> I will replace the findForm method (if that's what it's called) to be a
>> call to SkyDivers.findForm - a form that searches for skydivers by their
>> ratings, certification, or freefall style, as well as name or phone number.
>
>How about Editor and Renderer plug-ins for each specialist?

I think that they are not necessarily a good idea.  I don't really see a
value-add over just having a DTML (or other) method.  The requesting
Specialist just wants a page snippet, with at most some parameters
indicating what field name it would like the selected object to have.  Now,
it may make sense at some point to make (generally useful) Form objects
which can return such snippets.  I haven't had a chance to look at
ZFormulator or MetaPublisher, which I understand may both have some
applicable solutions in the form rendering area.


>> lifting" machinery and plug it into their local specialists, then gut the
>> collaborator specialist and wire it to the appropriate local specialist.
>
>If I understand something at all, whitebox specialist (Script?) called
>SkyDiverSpecialist must have its own data source (rack) for SkyDiver
>class and use 2.2. strategy mentioned above. (I just see no other way).

Very close.  It's just done more simply, and doesn't need the co-operation
of the SkyDiver class.  The SkyDivers specialist simply provides them as
propertysheets.  In this way, you can "adapt" between frameworks as long as
you always use propertysheets as whitebox "decorators".  So, if you have a
document management system (knows about authors, revisions, etc.), and a
project management system (knows about assigments, deadlines), you can make
them work together if the project management system stores
assignment/deadline stuff in a  project management-specific sheet.  And
with ZPatterns, it's easy to add support for that sheet to existing objects
- without altering existing code.  Just plug the sheet providers into the
appropriate specialists, and then extend the project management system's
Tasks specialist to be able to delegate to your Documents specialist, as
well as any others it needs to talk to.

Granted, some integrations like this may be complex, especially once you
start factoring indexes and searches and integrity rules.  However, they
are at least *possible* with ZPatterns, and the results should be worth the
work.

One of the very first inspirations for ZPatterns was a mailing-list
discussion about event scheduling in Zope.  It made me realize that there
wasn't a good way to mingle horizontal and vertical frameworks in Zope.
i.e., you couldn't easily go back in and add event scheduling or project
management to a bunch of classes that you got from somebody else, or even
your own classes, without changing your base classes or other really nasty
things (like copying code).  So, when used as framework glue, ZPatterns
emphasises run-time composition rather than code-time inheritance.  Of
course, ZPatterns can be used as just an application-building framework on
its own, but if used wisely, your applications should then be reusable as
frameworks by others.