Hi, I'm trying to figure out the right way to implement a set of classes and roles in ZPatterns. I asked some questions about this a while ago, and then went away and did some learning, but I'm stuck again and I'm afraid I need to ask more questions. I have two types of actors - Person (with properties name, phone, email, password) and Organization (with properties name, phone, fax, business_number). I also have two participants - Customer and Reseller. Each participant can be either a Person or an Organization. The participants can fill several roles, like OrderingEntities, BillableEntities, etc. Starting from the bottom, I create a Specialist for each role, each one with two virtual Racks - customerRack and ResellerRack, so I can refer to an OrderingEntity without caring if it's a Reseller or Customer. My problem is in implementing the Participant Specialists and storing Participant and Actor classes. Do I create Specialists for the Actors? It seems to me that since there is either one Person or one Organization per Customer, then the actor object should be created in the Customers Specialist. So Customers will have 3 Racks - defaultRack (using Customer object), personRack (using Person object) and organizationRack (using Organization object). Does this make sense? If this is a good way to do it, how do I handle creating and accessing the Person and Organization objects? Do I call personRack.newItem(newCustomerId) in the script that creates the customer? Or do I somehow do it in a SkinScript in defaultRack? And how do I get to the Person data? With an attribute provider? Or in the SkinScript: WITH personRack.getItem(self.id) COMPUTE name=name, phone=phone, email=email, password=password, personObject=RESULT) Also, if Actors are stored in the Specialists that implement the roles they participate as, there is no place to store methods that are common to an Actor regardless of role - for example, a method that checks if a password is secure enough and called when adding a Person object. So I either duplicate these methods in every Participant Specialist, or create more Specialists - which seems like a waste either way. Another problem is how to edit these objects - if I have a form which includes fields for a Customer properties and for the properties of the Person object linked to that Customer, can I change the Person object from the Customer SkinScript? I don't think I can do this: WHEN OBJECT CHANGED STORE name, password USING personObject.propertysheets.manage_changeProperties(name=self.name, password=self.password) Right? Because name and password are not properties on the Customer DataSkin. So I have to call person.manage_changeProperties(...) in the method that changes Customer... it seems to me that I always end up doing object connections work in methods and the SkinScript can't help with anything :( Hope this is not too convoluted...I'd really appreciate any help anyone can offer. The existing ZPatterns examples all deal with fairly straightforward situations, but it's the more complex class relationships where the bears and tigers are hiding :) Itai -- Itai Tavor "Je sautille, donc je suis." C3Works itai@c3works.com - Kermit the Frog "If you haven't got your health, you haven't got anything"
At 06:19 PM 11/29/00 +1100, Itai Tavor wrote:
Hi,
I'm trying to figure out the right way to implement a set of classes and roles in ZPatterns. I asked some questions about this a while ago, and then went away and did some learning, but I'm stuck again and I'm afraid I need to ask more questions.
I have two types of actors - Person (with properties name, phone, email, password) and Organization (with properties name, phone, fax, business_number).
I also have two participants - Customer and Reseller. Each participant can be either a Person or an Organization.
The participants can fill several roles, like OrderingEntities, BillableEntities, etc.
Starting from the bottom, I create a Specialist for each role, each one with two virtual Racks - customerRack and ResellerRack, so I can refer to an OrderingEntity without caring if it's a Reseller or Customer.
My problem is in implementing the Participant Specialists and storing Participant and Actor classes. Do I create Specialists for the Actors? It seems to me that since there is either one Person or one Organization per Customer, then the actor object should be created in the Customers Specialist. So Customers will have 3 Racks - defaultRack (using Customer object), personRack (using Person object) and organizationRack (using Organization object). Does this make sense?
I think what you want is to have an Actors specialist containing a personRack and organizationRack. That is, treat "Actor" as a role relative to either Customer or Reseller. The reason I say, "I think", is because I'm really not clear on why you're doing certain things here to start with. See below.
If this is a good way to do it, how do I handle creating and accessing the Person and Organization objects? Do I call personRack.newItem(newCustomerId) in the script that creates the customer? Or do I somehow do it in a SkinScript in defaultRack? And how do I get to the Person data? With an attribute provider? Or in
Here's a red flag: why are you creating a person when you create a customer? If a person is something that you only make when you have a customer, then the actor-participant-transaction pattern isn't really valid, IMHO. For Actor-Participant-Transaction to make sense, you have to have Actors that exist seperate from the Participants. While it makes sense to be able to create an Actor at the same time, your model needs to also include a way to select an *existing* Actor as the Participant, otherwise you are not gaining anything from the A-P-T pattern and you might as well just have the Participant. Here's a pattern for mapping A-P-T interactions onto ZPatterns, however... If you are doing A-P-T, make sure you use a Specialist for access to the Actors. For example, in some applications Ty and I write, "acl_users" is designated as the Specialist for actors if all actors in the system have to be able to use the application. The user interface and implementation for creating and/or selecting actors to fill a participant role is placed in the actors' specialist - acl_users in our case, or perhaps a specialist called "Actors" in yours. (But I'd recommend you use a domain-specific name, if possible.) So you would not be worrying about whether to create a person or organization or what fields they need or anything else in the specialist for your "participant" objects. Indeed, you wouldn't be worrying about whether a new one was being created, or an old one selected, if you delegate that aspect of the UI to the actors' Specialist.
Also, if Actors are stored in the Specialists that implement the roles they participate as, there is no place to store methods that are common to an Actor regardless of role - for example, a method that checks if a password is secure enough and called when adding a Person object. So I either duplicate these methods in every Participant Specialist, or create more Specialists - which seems like a waste either way.
Again, this is solved by using a specialist for the role "Actor".
Another problem is how to edit these objects - if I have a form which includes fields for a Customer properties and for the properties of the Person object linked to that Customer, can I change the Person object from the Customer SkinScript? I don't think I can do this:
WHEN OBJECT CHANGED STORE name, password USING
personObject.propertysheets.manage_changeProperties(name=self.name, password=self.password)
Right? Because name and password are not properties on the Customer DataSkin. So I have to call person.manage_changeProperties(...) in the method that changes Customer... it seems to me that I always end up doing object connections work in methods and the SkinScript can't help with anything :(
You're making this entirely too hard. The Prime Directive of ZPatterns design is, "if it looks too complicated in any one place, your design is probably wrong. If almost every individual piece looks simple, even though the whole is quite complex, your design is just right." :) Specifically, what you're doing here is trying to know things your object can't know. That's what delegation is for. You can't "edit" a participant and change data about the actor. That's an encapsulation violation. You can solve this several ways. In most of the app design I've done, I seperate editing the actor from editing the participant, simply placing a link on the participant object that references the actor directly, so that you can go and do whatever you need on the actor. However, that's not the only way to do it. You can always specify in your design that objects playing the actor role must have a method to provide an editing sub-form, and another method to accept data provided from that sub-form. You can then embed the actor's editing screen inside your participants' editing screens and call the actor's update method from your participant's update method. Problem solved.
Hope this is not too convoluted...I'd really appreciate any help anyone can offer. The existing ZPatterns examples all deal with fairly straightforward situations, but it's the more complex class relationships where the bears and tigers are hiding :)
Yep. While lack of ZPatterns implementation-level documentation sucks, it's quite clear that the really big issue for ZPatterns developers is the shortage of information on designing applications for ZPatterns. Basically what happens now is that I personally tutor everybody, and there's a couple of people who are passing on what they've internalized enough to be able to teach others. Complex examples would be helpful, and perhaps sometime I'll take a look at mapping a couple of the projects in Peter Coad's book into ZPatterns models. Coad's book is key to learning how to divide up responsibilities between classes, and it's important to work through those seperations before you try to map to ZPatterns. I'm guessing you've read the book, but I think you might want to study it a bit more deeply, because your design as presented above has classes trying to do work that properly belongs to other classes. The key thing I learned from the Coad book was that O-O designs are always simple -- *after* you seperate responsibilities. As Ty and I worked on designs, we came to realize that apparent complexity was always a clue that we either didn't have as many classes as we needed, or we were giving classes jobs that belonged to other ones. The Law of Demeter for methods is also a very handy checkpoint. If your design will require you to violate it, that is a concrete signal of excessive complexity, poorly seperated responsibility, or the most egregious of O-O design sins: failure to create domain-specific methods. (Notice, for example, that Coad never gives collections generic access methods, but instead puts any behavior that requires knowledge of contents directly into the collection object itself. That is, he makes a domain-specific collection, and never uses a generic "collection" object.)
Phillip J. Eby wrote:
At 06:19 PM 11/29/00 +1100, Itai Tavor wrote:
Hi,
I'm trying to figure out the right way to implement a set of classes and roles in ZPatterns. I asked some questions about this a while ago, and then went away and did some learning, but I'm stuck again and I'm afraid I need to ask more questions.
I have two types of actors - Person (with properties name, phone, email, password) and Organization (with properties name, phone, fax, business_number).
I also have two participants - Customer and Reseller. Each participant can be either a Person or an Organization.
The participants can fill several roles, like OrderingEntities, BillableEntities, etc.
Starting from the bottom, I create a Specialist for each role, each one with two virtual Racks - customerRack and ResellerRack, so I can refer to an OrderingEntity without caring if it's a Reseller or Customer.
My problem is in implementing the Participant Specialists and storing Participant and Actor classes. Do I create Specialists for the Actors? It seems to me that since there is either one Person or one Organization per Customer, then the actor object should be created in the Customers Specialist. So Customers will have 3 Racks - defaultRack (using Customer object), personRack (using Person object) and organizationRack (using Organization object). Does this make sense?
I think what you want is to have an Actors specialist containing a personRack and organizationRack. That is, treat "Actor" as a role relative to either Customer or Reseller.
The reason I say, "I think", is because I'm really not clear on why you're doing certain things here to start with. See below.
If this is a good way to do it, how do I handle creating and accessing the Person and Organization objects? Do I call personRack.newItem(newCustomerId) in the script that creates the customer? Or do I somehow do it in a SkinScript in defaultRack? And how do I get to the Person data? With an attribute provider? Or in
Here's a red flag: why are you creating a person when you create a customer? If a person is something that you only make when you have a customer, then the actor-participant-transaction pattern isn't really valid, IMHO. For Actor-Participant-Transaction to make sense, you have to have Actors that exist seperate from the Participants. While it makes sense to be able to create an Actor at the same time, your model needs to also include a way to select an *existing* Actor as the Participant, otherwise you are not gaining anything from the A-P-T pattern and you might as well just have the Participant.
I think I have problems understanding the whole A-P-T pattern. Maybe someone can help clear it up for me... An Actor is a Person or an Organization. A Participant can be (in my application) a Customer, Customer Contact, Reseller, ResellerContact, or Employee. Participants have different roles - for example, all Participants can place orders on behalf of customers, and they take on the OrderingEntity role. Orders are always paid for by Customers in their role as BillableEntities. Now, OrderingEntities and BillableEntities are roles that actualize the object connections between the Participants and the Transaction objects (in the above examples, the Transaction object would be Order), right? They are not new Participants. So in this application, while Participants can fill multiple roles, each Actor can only be a single Participant. A Person participating as a CustomerContact is (in the real world) employed by the Customer, so in the application she won't participate as anything else. So the A-P pattern seems to serve the purpose of reusing common properties and methods, rather than allowing for n-1 relationship between Actors and Participants. This seems to me to suggest that the application should have a Person class but that the Person will get created when a new Participant is created, and that a 'select existing Actor as Participant' interface, as Phillip suggests above, is not necessary. Am I right, or do I persist in misunderstanding A-P-T? A related problem I've been struggling with is how to allow a Reseller to buy product for itself/herself. Normally orders are placed for Customers only. Would it make more sense to create a role for entities that receive orders (implemented as a Specialist with virtual Racks for Customers and Resellers), or to complicate the A-P pattern by allowing a single Actor to be both a Reseller and a Customer? The new role path seems to make more sense to me, but I've been known to be wrong before :).
Here's a pattern for mapping A-P-T interactions onto ZPatterns, however... If you are doing A-P-T, make sure you use a Specialist for access to the Actors. For example, in some applications Ty and I write, "acl_users" is designated as the Specialist for actors if all actors in the system have to be able to use the application. The user interface and implementation for creating and/or selecting actors to fill a participant role is placed in the actors' specialist - acl_users in our case, or perhaps a specialist called "Actors" in yours. (But I'd recommend you use a domain-specific name, if possible.) So you would not be worrying about whether to create a person or organization or what fields they need or anything else in the specialist for your "participant" objects. Indeed, you wouldn't be worrying about whether a new one was being created, or an old one selected, if you delegate that aspect of the UI to the actors' Specialist.
I like the idea of using acl_users as the actors Specialist, it's much simpler than what I intended to do - have virtual Racks in acl_users that access users in all the different Participant Specialists. But doing it this way creates another problem for me - your acl_users authenticates Actors, not Participants. But in many cases the application needs to know the Participant* , and that requires that the Actor know its Participant. But knowing the Participant requires knowing the *type* of Participant - which is very ugly. How would you work this out? * For example, an employee of a reseller company logs in and places an order for a customer. The Participant is a ResellerContact, and a commission from the order has to be credited to the Reseller. Itai -- Itai Tavor "Je sautille, donc je suis." C3Works itai@c3works.com - Kermit the Frog "If you haven't got your health, you haven't got anything"
participants (2)
-
Itai Tavor -
Phillip J. Eby