Re: [Zope-dev] Externalize or Adapt? (ZPatterns)
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.
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.
Got it! Thanks. Now I see my previous questions was like 'where to put horse in steam engine' ;-)
Mike wrote:
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.
Maybe the best way is to put a 'thumb' data source into Customers instead of native one. This thumb should translate all messages to SkyDivers' data source. I'm just considering on specialized racks which implement non-standard api, such as 'findItem( criteria)', 'itemValues()' or something similar. By the way, racks should have a kind of 'scanning' api, like Zope's Folders, at least they should have itemIds() method. Mike
At 06:31 PM 6/10/00 +0800, Mike wrote:
Maybe the best way is to put a 'thumb' data source into Customers instead of native one. This thumb should translate all messages to SkyDivers' data source.
Yes, a "Delegation Rack" is certainly possible. It would make it really easy to merge data from different specialists; just drop in more than one. I suppose you could even make the DelegationRack have an expression to use to translate from the ID asked for in the horizontal specialist, to the kind of ID used by the vertical specialist, perhaps by using a search function of the vertical specialist.
I'm just considering on specialized racks which implement non-standard api, such as 'findItem( criteria)', 'itemValues()' or something similar.
By the way, racks should have a kind of 'scanning' api, like Zope's Folders, at least they should have itemIds() method.
This is waiting for indexes and predicates; which won't hit until 0.5.0. Meanwhile, I'll add a getPersistentItemIDs() method to Rack in 0.4.0. This will not get you the id of all possible items in the rack, since you might be using SQL or some other kind of storage. It will only get the items which have data or propertysheets in the ZODB. Currently, the correct way to have 'scanning' API's is to implement them on your Methods tab using SQL methods, LDAP methods, or whatever is appropriate for your dataset. In 0.5.0 or later, hopefully there'll be some sort of plug-in API for that.
participants (2)
-
Mike -
Phillip J. Eby