Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
100644 578 lines (577 sloc) 27.361 kb
25da785 @rcaputo Documentation reorganization.
1 Patterns of Object Interaction
2 Abstract
3 A useful object framework must support all possible design and interaction patterns.
4 The framework must support a core suite of general-purpose design patterns.
5 The framework must provide a good foundation for external implementation of additional patterns.
6 Top-down design is impossible.
7 An object framework must support all future uses, but it cannot anticipate them.
8 People write programs, and people are unpredictable.
9 Bottom-up design tends to fail.
10 Simple conceptual models work well at small scales.
11 Growing complex systems from basic principles is difficult.
12 There is an early, seductive sense of success.
13 Simple conceptual models often fail over time.
14 Larger systems strain the requirements of simple conceptual models.
15 Prevailing best practices change over time, and new practices introduce new requirements.
16 The rules and corollaries eventually conflict.
17 It's impossible to anticipate everything.
18 A hybrid approach may succeed where the other two fail.
19 It's easier to catalog meta design and interaction patterns than use cases.
20 By cataloging basic object design and interaction patterns, certain basic requirements will emerge.
21 By satisfying these requirements, the emergent object framework will conceptually scale farther.
22 Roadmap
23 Catalog and consider as many design and interaction patterns as possible.
24 Describe the emergent meta patterns.
25 Develop and document a syntax and specification to support the meta patterns.
26 Implement the specification.
27 Call for Contribution
28 Please help.
29 This is a huge project.
30 The project leader has worked on bottom-up designs since 1998 and would like to get it right this time.
31 Object Structural Patterns
32 Code Conventions
33 Functions
34 Methods
35 Class Methods
36 Object Methods
37 Parameter Conventions
38 Self and Positional Parameter List
39 Self and Parameter Hashref
40 Lexical Aliases
41 Self
42 Hashref Members
43 Return Conventions
44 Returned Data Formats
45 Returned as a List
46 Returned as a Hashref
47 Type and Hashref
48 Returned Data Mechanisms
49 Return via Return Builtin
50 Emitting via Method
51 Synchronous Emit
52 The emitted message target is called during emit().
53 Bypassing queue latency is efficient.
54 Deep recursion can occur.
55 Broad recursion cannot occur.
56 Requires deep Perl magic to work across process boundaries.
57 Asynchronous Emit
58 A message representing the emit() call is enqueued for the message target.
59 Queue latency makes this slower than synchronous emit.
60 Deep recursion cannot occur.
61 Broad recursion can occur.
62 May work locally or remotely.
63 Hybrid Emit
64 Synchronous emit is used whenever possible.
65 Asynchronous emit is used at the first sign of recursion.
66 Asynchronous emit may also be used for remote messages.
67 Deep recursion cannot occur.
68 Broad recursion is less likely.
69 Constructor Conventions
70 Direct Instantiation
71 Instantiate in Another Thread
72 Instantiate in Another Process
73 Process Already Exists
74 Process Doesn't Exist
75 Instantiation upon Request
76 Destructor Conventions
77 Destruction upon Release
78 Owner Explicitly Releases Object
79 Cascaded Owner Destruction
80 Global Destruction
81 Destruction upon Request
82 External Shutdown Request
83 Avoid Shutdown upon Destruction
84 Shutdown upon destruction tends to be too late.
85 Shutdown may take time.
86 Objects in the throes of destruction don't have time.
87 Self-Destruction upon Task Completion
88 Relies upon weak references or implicit management.
89 May be thwarted by users holding onto additional object references.
90 Accidentally, causing memory leaks.
91 Explicitly, but power users.
92 Object Never Destructs
93 Do nothing vital within object destructors.
94 Object destructor invocation is not guaranteed.
95 POSIX::_exit()
96 Signals.
97 Object Composition Patterns
98 Static Class Composition
99 Inheritance
100 Interfaces and Implementations
101 Roles
102 Object Composition
103 Static Object Composition
104 Low-level objects that comprise a higher-level object are created along with the high-level object.
105 The instantiation-time configuration persists until destruction.
106 Dynamic Object Composition
107 A higher-level object creates and by default owns lower-level objects as needed.
108 The type and ordinality of lower-level objects may change over time.
109 Object Composition Roles
110 Lower-level objects fulfill roles within their higher-level objects.
111 Higher-level objects may assign role names to lower-level objects to simplify addressing and management.
112 Role Ordinalities
113 No Objects per Role
114 All objects for a role may have destructed, or no objects for a role may have been constructed yet.
115 One Object per Role
116 Each lower-level object comprising a higher-level object may have its own role, or no role at all.
117 Multiple Objects per Role
118 Multiple objects may be assigned the same role within a higher-level object.
119 Role Addressing
120 Addressing All Objects for a Role
121 Addressing One Object for a Role
122 Addressing One Object at Random
123 Round-Robin Addressing
124 Custom Addressing
125 Owner Ordinalities
126 No Owners
127 An object without an owner is usually a memory leak as a side oeffect of a circular reference.
128 If at all possible, objects should recognize and log a warning when they have been orphaned.
129 If possible, objects should recognize and throw excpetions when too many are leaking.
130 One Owner at a Time
131 Creator
132 An object's scope remains that of its creator for the object's lifetime.
133 Factory
134 One object creates new objects on behalf of another.
135 Namespace
136 An object is created within an object that allows it to be addressed by name.
137 An object is created outside a namespace and is later registered with the namespace.
138 Assembly Line
139 An object is created to represent some multi-stage task.
140 The object is passed from one worker to another.
141 Each worker performs part of a larger complex task.
142 The object represents a complete result when all stages are complete.
143 Multiple Owners
144 An object is created by one object and passed to one or more others.
145 Multiple Serial Owners
146 Each owner relinquishes ownership while passing the object to the next.
147 Multiple Parallel Owners
148 An object is created by one object and passed to one or more simultaneous users.
149 Use must be coordinated from within the object being used.
150 Users are not aware of each other.
151 Owned Ordinalities
152 Owns No Objects
153 Owns One or More Objects
154 Explicit Ownership
155 This is Perl's standard ownership mechanism.
156 Objects are stored in members of their owners.
157 Objects are destroyed when their owners release them.
158 Implicit Ownership
159 About
160 The base class tracks object ownership and parentage.
161 Dynamic composition is simplified.
162 Objects are permitted to self-destruct when they are finished.
163 Objects are identified by their roles within their owners.
164 The mechanism may be visualized as object-scoped namespaces.
165 Implicit Ownership upon Creation
166 Objects are assigned roles at construction time.
167 The base class tracks owned objects by roles.
168 Implicit Ownership upon Request
169 Objects created without roles may be assigned roles later.
170 The base class begins tracking these objects at the time of assignment.
171 Unassinging roles may trigger destruction if the base class held the sole reference to these objects.
172 Inspecting Implicitly Owned Objects
173 Addressing Owned Objects
174 Addressing owned objects by Role
175 Addressing Owned Objects by Class
176 Addressing a Single Owned Object
177 Addressing Multiple Owned Objects
178 Iterating Owned Objects
179 Iterating owned objects by Role
180 Iterating owned objects by Class
181 Counting Owned Objects
182 Counting Owned Objects by Role
183 Counting Owned Objects by Class
184 Benefits of Ownership
185 Default response target.
186 Role and type responses.
187 Transferring Ownership
188 Implicitly during storage.
189 This is Perl's referencing model.
190 Storing an object also implies sets ownership.
191 Releasing an object relinquishes ownership.
192 Easy to implement---just let Perl do it.
193 Difficult to convey benefits without ability to introspect owner relationships.
194 Explicitly via method.
195 Explicit mechanisms are easier to understand.
196 More work for users.
197 More reliable---no need for Perl magic.
198 Determining Ownership in Perl
199 Examine the call stack via caller() in package DB.
200 Have the framework call everything, all the time.
201 Decorator that injects the current $self.
202 Nick Perez suggested this.
203 Custom decorators can be defined with Devel::Declare and MooseX::Declare.
204 A simple C<< parent SomeObject->new() >> might deliver the necessary information.
205 It's a little magicky, but it might be easier (and saner) than walking the call stack.
206 MRO::Magic
207 Nick Perez suggested this.
208 Rjbs is working on it.
209 It's not necessary to track all object ownership.
210 Basic objects that don't use the framework don't need to be tracked.
211 Service Composition
212 Service Scope
213 Available to One Object
214 Generally pointless, since services are meant to be visible in wider scopes.
215 Available to Multiple Objects
216 It is ideal for a service to be available and useful for multiple objects.
217 The service must coordinate requests internally.
218 Objects cannot coordinate use of a service.
219 This is common, so it must be part of a base service class.
220 Available to No Objects
221 Invisiblity is useless.
222 A service must be visible to be used.
223 Service Ownership
224 A serice is owned by a single entity that exposes it to other objects.
225 Other objects may not assume ownership of a service.
226 Service Exposure
227 Service Exposed Within One Process
228 Service Exposed Internally and to Other Processes
229 Service Exposed Only to Other Processes
230 Service Creation
231 Service Creation by Configuration
232 Service Creation upon Request
233 Service Creation Implicitly upon Need
234 Service Destruction
235 Service Destruction upon Request
236 Graceful Shutdown
237 Immediate Shutdown
238 Service Destruction upon Container Destruction
239 Global Destruction at Program Exit
240 Object Interaction Patterns
241 Synchronous
242 Call and Return
243 Request and Wait for Reply
244 Ordinalities
245 One Call and One Request
246 Asynchronous
247 Request and Asynchronous Callback
248 Callback by Function Reference
249 Supports continuations.
250 Supports quick, low-level code.
251 Callback by Object or Class and Method Name
252 Callback by Role and Response Type
253 Promises
254 Requests as Promise Factories
255 Waiting for Promises
256 Request Ordinalities
257 No Requests
258 One Request
259 Multiple Requests
260 Response Ordinalities
261 No Responses
262 One Response
263 Multiple Responses
264 Task Patterns
086bc42 @rcaputo Typo fixes recommended by Chris Fedde.
265 Task Lifespan
25da785 @rcaputo Documentation reorganization.
266 Task Commencement
267 Task Begins with Object Instantiation
268 Task Begins upon Request Receipt
269 Task Completion
270 Task Ends upon Successful Completion
271 Task Ends upon Exception
272 Task Ends with Cancellation Request
273 Task Ends with Object Shutdown
274 Task Ends with Object Destruction
275 Objects may be destroyed before they are finished.
276 Global destruction is an extreme case.
277 There may be a race between the task completion and object destruction.
278 A user may knowingly cancel a task by destroying the object performing it.
279 Task Never Ends
280 Programs may halt without notification or opportunity to clean up.
281 There's nothing to be done in these cases.
282 If absolute reliability is required, try to minimize the amount of time when sudden halting can be catastrophic.
283 Task Ordinality
284 No Tasks Per Object
285 An object may be created for a purpose that is not needed in a partucular execution.
286 Optimally, the object would not be created until its task is required.
287 One Task Per Object
288 Multiple Tasks Per Object
289 Tasks Performed Serially
290 Tasks Performed in Limited Parallelism
291 Tasks Performed without Parallelism Limit
292 Communication Patterns
293 Terms
294 Producer
295 An object that produces information.
296 Also known as a source.
297 Might be a better name than "responder".
298 POE::Wheel is a kind of producer.
299 POE::Component::IRC is both a producer and a consumer.
300 Consumer
301 An object that consumes information from a producer.
302 Also known as a sink.
303 Objects may be both producers and consumers at the same time.
304 Requester
305 An object that initiates a transaction by making a request.
306 Requests may be performed by sending messages to services.
307 Some objects imply requests when they are created.
308 Method calls are a form of request.
309 Requesters produce requests.
310 Requesters may consume responses.
311 Responder
312 An object that receives a request and performs some kind of work.
313 Called responders because they often respond to requests.
314 Some objects perform side effects without responding.
315 A universal sink (the /dev/null of objects) may neither respond nor perform a side effect.
316 Consider calling them workers.
317 Responders may consume requests.
318 Responders may produce responses.
319 To Do
320 The producer/consumer and requester/responder combinations may need to be enumerated and explained in more detail.
321 Discrete Transactions
322 Ordinalities
323 Point to Point
324 One Requester, One Responder
325 Broadcast and Gather
326 One Requester, Any Responders
327 Serial Responders
328 Parallel Responders
329 Message Channels
330 Any Requesters, Any Responders
331 Service
332 Any Requesters, One Responder
333 Multi-Transaction Sessions
334 Ordinalities
335 Point to Point
336 One Connector, One Service
337 Observation and Notification
338 Terms
339 Notifier
340 An object that advertises notifications when its data members change.
341 Observer
342 An object that observes data member changes in one or more other objects.
343 An object may observe its own data members.
344 Ordinalities
345 No Notifiers, Any Observers
346 Ideally the system will optimize this case into a no-op.
347 Runtime support for dynamic ordinalities may prevent optimization.
348 Any Notifiers, No Observers
349 Ideally the system will optimize this case into a no-op.
350 Runtime support for dynamic ordinalities may prevent optimization.
351 One Notifier, One or More Observers
352 Notofication is sent to all observers.
353 One or More Notifiers, One Observer
354 An observer may observe more than one notifier.
355 It remains to be seen whether this case is practical.
356 Multiple Notifiers, Multiple Observers
357 The observation/notification equivalent of a data bus.
358 It also remains to be seen wheter this is practical.
359 Notifications
360 Notification on Set
361 Observers are notified whenever a value is written to an observed member.
362 Obseration occurs even when the new value is identical to the old one.
363 Level-triggered notification.
364 Notification on Change
365 Observers are notified whenever a new value is written to an observed member.
366 Obseration does not occur when the new value is identical to the old one.
367 Edge-triggered notification.
368 Continuation Patterns
369 About
370 Continuations are encapsulated bits of program state that can be passed around and swapped in and out as needed.
371 Each continuation includes an instruction pointer and all the program state required to resume a program from that point in its execution.
372 Perl supports coroutines by grafting its interpreter onto an event dispatcher.
373 This grafting is done deep in its implementation using sharp implements.
374 Continuations may also be implemented as explicit objects to manage execution state between callbacks.
086bc42 @rcaputo Typo fixes recommended by Chris Fedde.
375 Event frameworks like POE implement such continuations, albeit at a rather low level.
25da785 @rcaputo Documentation reorganization.
376 Multiple continuations may be active at once.
377 Continuations may be nested, in which case the inner continuation should run to completion before the outer one may resume.
378 Lexical::Persistence
379 Lexical::Persistence was written to map continuation object data members into lexical pads.
380 This simplifes their use---lexical variables magically refer to the right continuation.
381 It's somewhat off-putting magic, however.
382 Perl seems to behave abnormally.
383 An alternative, explicit mechanism might feel nicer.
384 Request Based Continuations
385 About
386 Tasks require their own continuations.
387 Each task is initiated by some form of request.
388 The request may be implicit in an object's creation.
389 It may be an explicit message sent to a service.
390 Inbound Request Continuations
391 Inbound request continuations are state associated with tasks that one object or service performs on behalf of another.
392 These continuations are associated with inbound requests.
393 They are accessible within receivers of requests.
394 They are automatically made available whenever code is executed as a consequence of the initial request.
395 In other words, these continuations are in scope during the performance of a task triggered by some request.
396 Outbound Request Continuations
397 Outbout request continuations associated with tasks that are being performed by another object upon the current object's request.
398 These continuations are associated with outbound requests.
399 They are accessible within request senders, or method callers.
400 They are automatically made available whenever a response is received by the helper object or service.
401 These continuations provide continuity between asynchronous messages and the responses they generate.
402 Object Based Continuations
403 Self Continuations
404 Each object has a continuation that is in scope whenever the object is active.
405 This continuation is the object itself.
406 Parent Object Continuations
407 These continuations are special cases of Inbound Request Continuations.
408 They exist when the parent object created the current object for the purpose of performing a task.
409 Are there other useful uses of parent object continuations?
410 Child Object Continuations
411 These continuations are special cases of Outbound Request Continuations.
412 They exist when the parent object created the current object for the purpose of performing a task.
413 Are there other useful uses of parent object continuations?
414 Connection Based Continuations
415 About
416 Persistent connections or sessions between objects are useful.
417 Continuation scope and lifetime can be associated to persistent connections.
418 Management of connection state is automated as a result.
419 Connector's Continuation
420 Connector continuations are associated with the client sides of connections between objects.
421 They provide continuity over the course of the connection.
422 Additionally, outbound request continuations may be associated with individual requests that are sent down connections.
423 Service's Continuation
424 Service continuations are associated with the server sides of connections between objects.
425 They provide continuity within the service over the course of the connection.
426 Additionally, inbound request continuations may be associated with individual requests that a service may receive.
427 Lexical Aliases for Continuation Variables
428 About
429 Lexical::Persistence was written to provide easy lexical aliases for continuation variables.
430 Members of a continuation object may be aliased to lexical variables within a callback.
431 Accessing or modifying lexical variables magically does the same to members of the continuation object.
432 However, the aliasing incurs overhead and is not lazy.
433 All aliases are configured regardless whether a particular code path requires them.
434 Lexical Alias Conflicts
435 Multiple continuations may be active at once.
436 They may have identical data members.
437 Lexical variable names need to identify the continuations to which they refer.
438 POE::Stage and Lexical::Persistence use prefixes to disambiguate continuations.
439 The part of the variable name up to the first underscore identifies the continuation.
440 The remaining variable name identifies the data member within the named continuation.
441 Additional Conveniences
442 $self may automatically be aliased to $_[0], Perl's conventional method parameter identifying the object.
443 The "self" prefix may be aliased to members of $self.
444 $args may be aliased to a hashref of method parameters, possibly kept in $_[1].
445 Likewise, the "arg" prefix may be aliased to $args members.
446 Miscellaneous Ideas
447 Metaphors
448 Extending the Actor Metaphor
449 Actor
450 An object that can take requests and respond with results.
451 Described as "services" elsewhere.
452 May also be helper objects.
453 POE::Session is a kind of actor, although not in the computer science sense of the word.
454 POE::Wheel objects aren't actors because they don't stand alone.
455 In this metaphor, actors don't include their own mailboxes, nor do they actively await messages.
456 Prop
457 Basic, non-actor helper objects.
458 They may interact with messages, or use basic asynchronous callback facilities like timers.
459 They generally perform very low-level work.
460 Actors use them to fulfill their roles.
461 Director
462 The event loop, message router and dispatcher.
463 May represent POE::Kernel within the metaphor.
464 Stage
465 About
466 Isolated computational units.
467 More like conventional actors.
468 Ideally, stages should behave identically no matter what.
469 In practice, each type of stage probably has its own caveats.
470 Cooperative Stages
471 Act as thin interfaces between POE::Kernel and actors.
472 Don't have their their own mailboxes.
473 Immediately and synchronously forward events to actors.
474 Threaded Stages
475 Act as bidirectional queues between POE::Kernel (which lives in the main thread) and the actors that coexist within a subthread.
476 Contain their own mailboxes.
477 Cannot directly call anything that exists in another stage.
478 Other iThreads caveats apply.
479 Forked Stages
480 Act as bidirectional queues between POE::Kernel (which lives in the main process) and the actors that coexist within a child process.
481 Contain their own mailboxes.
482 Cannot directly call anything that exists in another stage.
483 Other process-boundary caveats apply.
484 Propmaster
485 An ORM of some sort.
486 DOM Namespaces
487 XPath Object Addressing
488 About
489 Allows global addressing of objects through a DOM-like container and XPath-like queries.
490 Proof of concept exists using XML::LibXML and actual DOM and XPath queries.
491 Supports multiple-object addressing.
492 Supports identifying objects by class, role, and other attributes.
493 In a cluster, nodes may advertise their services by adding their DOMs to a directory.
494 The directory can execute XPath queries that span the entire network.
495 Caveats with XPath Object Addressing
496 Robert Grimes pointed out that there is very little actual need for finding objects globally.
497 Most objects interact locally.
498 Parent object interacts with children.
499 Children interact with parents.
500 Children interact with siblings, usually through a moderator.
501 Global addressing facilitates broken encapsulation.
502 Global addressing should only be used for services.
503 Javascript use of DOM Addressing
504 Torsten Raudssus pointed out that Javascript uses DOM for similar purposes.
086bc42 @rcaputo Typo fixes recommended by Chris Fedde.
505 Code may manipulate page elements singly or in groups by addressing them with XPath.
25da785 @rcaputo Documentation reorganization.
506 It can be very convenient.
507 This seems to be a subset of Robert Grimes' earlier point.
508 Javascript is manipulating sibling objects within the same container---the page containing the code.
509 In a larger application, it seems safer to limit each object's reach.
510 What sorts of limitations are reasonable?
511 Proxy Objects
512 About
513 Proxy objects are an alternative to services and explicit messages.
514 Remote Object Type
515 Remote Helper
516 Remote Service
517 Remote Object Existence
518 Remote Object Already Exists
519 The local proxy object connects to the remote object during instantiation or first use.
520 Remote Object Created on Demand
521 Creating the local proxy triggers creation of the corresponding remote object.
522 Remote Process Existence
523 Remote Process Already Exists
524 The local proxy object connects to the remote process during instantiation or first use.
525 Remote Process Created on Demand
526 Remote processes are created as needed.
527 Remote Class Existence
528 Remote Process Has Required Class
529 Remote objects are instantiated from remote copies of the requied class.
530 Incompatible versions of the same class may cause problems.
531 Remote Process Needs Required Class
532 The local process may push a required class to the remote process.
533 Dependencies may also need to be pushed.
534 In some cases, tarballing the entire module suite may be needed.
535 The remote process must have a version of Perl capable of executing the remote object.
536 Injecting code into other processes or even other machines must be done securely.
537 The remote process should cache the code to avoid additional performance issues.
538 Alternatively, the remote process may install the required module from CPAN.
539 Compiled modules have their own set of problems.
540 Modules may need to be built on the destination machine to guarantee they work.
541 Further Considerations
542 Blocking Constructors
543 Constructors are expected to return complete, usable objects.
544 Remote procedure calls imply blocking until responses are ready.
545 Promises can alleviate this somewhat.
546 Promises are permitted to work in the background until their information is needed.
547 They therefore block less than synchronous calls.
548 However they may still block for significant amounts of time.
549 Conserving TCP Sockets
550 One implementation could use a TCP connection per remote object.
551 TCP connection building and teardown are expensive.
552 It will be more efficient to multiplex object communication between the same processes.
553 The BXXP protocol seems designed for this task.
554 Reflexive Data Members
555 POE's early object environment experiments were very MUD-like.
556 Nearly every object was required to be in a container.
557 Changing an object's container required updates to its old and new containers' contents.
558 This was a fundamental aspect of the system.
559 The system implemented basic code to handle the referential integrity.
560 Procedure
561 Ask the object whether its container may be changed.
562 Ask the old container whether the object may be removed.
563 Ask the new container whether the object may be added.
564 Move the object from its old container to its new container.
565 Notify the old container that the object was removed.
566 Notify the new container that the object was added.
567 Notify the object that its container has changed.
568 Technology Questions
569 How are new Moose types defined?
570 New types may be needed for some of the container magic.
571 How may hooks be affixed to Moose members?
572 Attribute traits allow accessors and mutators to behave differently.
573 Member change advertisement may be implemented as traits.
574 Chris Williams suggested Variable::Magic as well.
575 How does Moose map to this framework's features?
576 Moose features seem to be coupled to classes rather than individual objects.
577 How can Moose implement the basic functionality necessary for the features listed in this document?
Something went wrong with that request. Please try again.