|
From: Frank Fredstone on 11 Feb 2007 21:09 I'm still struggling with OO concepts. I've read several books and studied various OO languages, but I don't really feel I have a good grasp of the concepts. I like the sound of the "tell, don't ask" model, where networks of objects are asked to perform the work they are responsible for, rather than asking objects to give you information (like a string) that you do something with. But, I get confused when I try to apply the idea to a program design. The only way I can think of avoiding asking objecs for information is if the program consists of nothing but one object of class "Program" with one method called "execute" that does everything. I've seen an example of bad design: AssociativeArray c = object.getEmployees() for each employee in employees: c.put(employee.name(), employee) the "tell don't ask" version of which could be: object.addEmployees(employees); So, "object"'s class supports the "tell model", by allowing you to tell it to add employees rather than asking it for a map to modify. But, doesn't that mean that "employees"'s class has to support the "ask model", so that it "object" can get each of the "employee" objects and their names? Is there a way to actually use "tell" insead of "ask", through out. Or, how do you categorize when you should use "tell" and when you should use "ask"?
From: Frank Fredstone on 11 Feb 2007 22:55 ram(a)zedat.fu-berlin.de (Stefan Ram) writes: > Frank Fredstone <none(a)not.no> writes: >>AssociativeArray c = object.getEmployees() >>for each employee in employees: >> c.put(employee.name(), employee) >>the "tell don't ask" version of which could be: >>object.addEmployees(employees); > > One possibility: > > employees.add_all_pairs_of_name_and_employee_to_map( c ); > > Or using the notation [x|f(x)] for a block object ith the > parameter �x�: > > employees.for_each_employee_do[ e | e.with_name_do[ n | c.put( n, e ); ]] > > The blocks are passed into the objects as arguments to the > operations �for_each_employee_do� and �with_name_do�, > so the objects do not return values such as �e� or �n�. Well, your examples uses different objects (employees and a map) instead of (object and employees). But, if I change your first example to employees.add_all_pairs_of_name_and_employee_to_object(object) I suppose that uses the "tell model" for both classes. It seems disconcerting to me that Employees would have to have a method specifically for interfacing with "object" objects, though. If there became a reason to have an ineraction between an Employeees object and some other object, would I then have to modify Employees to have a method specifically for that other class? For example: employess.add_employee_to_some_other_object(some_other_object) employees.add_employee_to_yet_another_object(yet_another_object)
From: Wavemaker on 11 Feb 2007 23:05 "Frank Fredstone" wrote: > I'm still struggling with OO concepts. I've read several books and > studied various OO languages, but I don't really feel I have a good > grasp of the concepts. > > I like the sound of the "tell, don't ask" model, where networks of > objects are asked to perform the work they are responsible for, rather > than asking objects to give you information (like a string) that you > do something with. But, I get confused when I try to apply the idea to > a program design. My take on the "tell, don't ask" approach is that objects announce (tell) when something happens. This could be, for example, when they're finished with a task or an event outside of the system occurs and its their job to let interested parties know about it. > But, doesn't that mean that "employees"'s class has to support the > "ask model", so that it "object" can get each of the "employee" > objects and > their names? In my opinion, it's ok to have "getters" that expose an object's properties. One wants to be careful not to overdo it; you'd like the interface for a class to be as narrow as possible, but sometimes it just makes sense to have a getter for a particular property. A "Name" property seems reasonable for an Employee class. The question I'd have would be whether or not to make this property mutable (probably not). But then it's hard to judge what kind of interface a class should have in a vacuum. You really need to know more about the overall problem being solved. But as a general rule, I don't have a problem with a class providing a few properties that can be queried through "getters." In other words, I don't have a problem with an object being asked to give more information about itself.
From: H. S. Lahman on 12 Feb 2007 14:39 Responding to Fredstone... I agree with Wavemaker; the OO view of "tell; don't ask" is necessarily different than the procedural view... > I'm still struggling with OO concepts. I've read several books and > studied various OO languages, but I don't really feel I have a good > grasp of the concepts. > > I like the sound of the "tell, don't ask" model, where networks of > objects are asked to perform the work they are responsible for, rather > than asking objects to give you information (like a string) that you > do something with. But, I get confused when I try to apply the idea to > a program design. This view is just plain wrong in the OO world. OO methods are /supposed/ to access the knowledge they need on an as-needed basis because the OOA/D model of behavior communication is asynchronous. That implies an arbitrary delay is possible between when a message is generated and when the response is executed. (That's because the OOA/D must be unambiguously implementable in inherently asynchronous and/or concurrent environments at OOP time as well as synchronous environments.) However, data integrity becomes a mess with that model if it is passed in messages because of the potential delay. So in OOA/D knowledge access is always synchronous (getters/setters are aka synchronous services). That's the only way to ensure timely data and the OOP implementation must provide infrastructure to ensure accessing the data behaves as-if it were synchronous, even in distributed implementations. That makes it much easier to manage scope for data integrity during OOP. So the method always asks for the data it needs and in a well-formed OO application messages very rarely carry data packets. (There are data packets only when requirements demand "snapshots", such as processing data from multiple sensors that in from the same time slice.) Message and method are separated in the OOA/D so that one can eliminate hierarchical implementation dependencies. The 'tell' part refers to the fact that all behavior messages are announcements (I'm done). They tell whoever is listening that something was done that changed the state the the solution. Then the sender of the message only needs to know what it did and has no expectation of what will happen as a consequence. IOW, what the message receiver does with that information is a personal matter for the receiver. The sender doesn't even need to know who will receive the message. Routing the messages to the right receiver is done at a different level of abstraction (e.g., a UML Interaction Diagram). Conversely the 'ask' part refers to an expectation that a specific receiver will do something in particular (Please Do This). That is a no-no in an OO context because for the message sender to have that expectation it needs to know: (A) that someone specific cares what it did; (B) they have a specific behavior responsibility; and (C) that responsibility is what needs to be done next in the overall solution. All of those break OO encapsulation but the last is especially insidious because it hard-wires the overall solution sequence into the sender implementation. > The only way I can think of avoiding asking objecs for information is > if the program consists of nothing but one object of class "Program" > with one method called "execute" that does everything. > > I've seen an example of bad design: > > AssociativeArray c = object.getEmployees() > for each employee in employees: > c.put(employee.name(), employee) > > the "tell don't ask" version of which could be: > > object.addEmployees(employees); I agree the example is poor practice, but I don't think it has anything to do with "tell, don't ask". "object" is clearly a collection class that implements a 1:* relationship to Employee in the OOA/D. A such its natural responsibilities are to manage the collection. So it would logically have "add", "remove", "get", etc. responsibilities when one abstracted the concept of a collection from the problem space. So there is no point in having an intermediary collection (AssociativeArray) to implement those notions. [BTW, the example seems curious from another standpoint. Why is there a second collection of Employees ("employees")? That would only be justified if there were another 1:* relationship to Employee that involved a different set of employees in the collection. But if that were true, I would expect there would be some selection criteria to apply for the subset. My point here is not to critique the example, but to point out that the use of collections and their management will depend on the specifics of the problem. "tell, don't ask" is not relevant here because the problem space is dictating the relationship collections and the collaborations that navigate them. IOW, problem space abstraction determines what collections are needed and what responsibilities they must have. "Tell, don't ask" only becomes relevant when one constructs the behavior methods that navigate those relationships during collaborations.] ************* There is nothing wrong with me that could not be cured by a capful of Drano. H. S. Lahman hsl(a)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(a)pathfindermda.com for your copy. Pathfinder is hiring: http://www.pathfindermda.com/about_us/careers_pos3.php. (888)OOA-PATH
From: Frank Fredstone on 13 Feb 2007 00:30
ram(a)zedat.fu-berlin.de (Stefan Ram) writes: > Frank Fredstone <none(a)not.no> writes: >>>employees.add_all_pairs_of_name_and_employee_to_map( c ); >>Well, your examples uses different objects (employees and >>a map) instead of (object and employees). > > I call an �associative array� a �map�, but this is not > intended to be another class or object - just another name for > the same thing. I didn't state what my example was doing clearly I think. The example was showing the interaction betwen an object named "object" of some class (let's say it's Organization) and another object called "employees" of some class (let's say it's Employees). Assuming the premise of my post "tell" is good, "ask" is bad, the "bad way" was for Organization to allow you to ask it for a map to modify: AssociativeArray c = object.getEmployees() for each employee in employees: c.put(employee.name(), employee) This is supposed to be a typical example of "asking" an object for something that you modify, rather than "telling" the object to perform some operation. The "good way" was for Organization to allow you to tell it to add emloyees to itself: object.addEmployees(employees); My question was then, doesn't that imply that Employees needs to support the "ask" model though? I can get from your example that it could be possible for Organization to allow an "add" operation and then use your employees.add_to(object) which is then "tell model", but, an Organization might need to have things other than employees added to it, so an "add" method might not be suitable, and the representation of an employee in an Organization could change to require something other than a map of employees by name. I suppose there could be an addEmployee method on Organziation and Employees.add_to could know that, but then doesn't that mean that Employee has to support the "ask model"? >>But, if I change your first example to >>employees.add_all_pairs_of_name_and_employee_to_object(object) > > My first suggestion is intended to replace the statement: > > for each employee in employees: > c.put(employee.name(), employee) > > This statement contains �c�, not �object�. > Therefore, my first suggestion also contains �c�, not �object�. Right, but "c" only exists in the supposedly "bad way" of doing things. The problem I was posing was one between "object" and "employees". Maybe you are saying that it is a good idea to ask employees for a map to modify. "Wavemaker" <jabberdabber(a)BiteMeHotmail.com> writes: > My take on the "tell, don't ask" approach is that objects announce > (tell) when something happens. This could be, for example, when they're > finished with a task or an event outside of the system occurs and its > their job to let interested parties know about it. I think this doesn't match what I've been reading referred to as "tell, don't ask". I keep coming across it while I'm looking into testing and mock objects, maybe it's a fringe idea. I've seen "tell, don't ask" expressed in Allen Holub's book 'Holub on Patterns' in the section "Getters and setters are evil", and on this web page: http://www.pragmaticprogrammer.com/ppllc/papers/1998_05.html By "tell" they seem to mean telling objects to perform some action rather than asking objects for information that you will then do something with. Allen Holub's argument for why it tends to be bad to ask for objects for information about their state, is that it spreads dependencies on the internal state of an object around to other objects. He also argues that the place where getters/setters are not evil is where you bump up against the "procedural boundary" of the system or operating system that you are interfacing with. Or, if you need your objects to be unusually flexible in how they can interact with other objects, like if you are writing a general class library. However, this is all to vague for me, and that's really what I'm asking for is some less vague guidelines that someone can express an opinion about. "H. S. Lahman" <h.lahman(a)verizon.net> writes: > Responding to Fredstone... > >> I like the sound of the "tell, don't ask" model, where networks of >> objects are asked to perform the work they are responsible for, rather >> than asking objects to give you information (like a string) that you >> do something with. But, I get confused when I try to apply the idea to >> a program design. > > This view is just plain wrong in the OO world. OO methods are > /supposed/ to access the knowledge they need on an as-needed basis > because the OOA/D model of behavior communication is > asynchronous. I don't understand what you are describing as synchronous or asynchronous about either "tell" or "ask" model methods, I think they are both synchronous. But, I think you might not be refering to the same thing as I am about "tell, don't ask". By "tell" I mean methods that tell an object to perform some processing, like "add an employee to your organization", and by "ask" I mean methods that ask for data that you can then do processing with yourself, like "give me a map that I can add employees to". |