Fetching contributors…
Cannot retrieve contributors at this time
916 lines (915 sloc) 40.4 KB
[_] 40% Framework Requirements
About this Document
This document summarizes the best ideas from the patterns document.
It is also a master TODO list for Reflex.
It's in Vim Outliner Format.
A plain-text outline where tabs indicate indent levels.
Editing is easier using ... version 0.3.4 or later.
Suggestions welcome for a concise, plain-text outline format that's widely supported and software-neutral.
"[_]" is a checkbox denoting an incomplete to-do item.
"[X]" denotes a completed to-do item.
Checkboxes are followed by percentages of completion, including sub-items.
Items without checkboxes---like the one you're currently reading---are just notes.
The docs/patterns.otl document tries to enumerate all available options.
Even ones that have been discarded.
Even ones we'd like to do but may never get around to.
Patterns contains some sexy, interesting, and hard projects.
Volunteers are welcome.
A later specification document will attempt to reconcile the requirements into a syntax and semantics.
This will probably become the documentation. :)
Project Philosophy
Desirable Qualities
Best practices should be encouraged.
Base classes should set precedents for best practices.
The design should encourage continued use of best practices.
Substandard qualities should be possible but gently discouraged.
People like to have options.
People like to exercise those options, whether or not they're good.
It's not the framework's duty to prevent people from doing what they want.
Undesirable Qualities
Avoid implicit constructs.
Implicit constructs cause action without visible indication.
They are disorienting.
They interfere with comprehension.
Avoid unnecessary magic.
Magic is scary.
It also implies action at a distance.
Avoid cleverness.
Cleverness leads to brittle design.
It also leads to unnecessary magic.
It also leads to implicit constructs.
Avoid metaphors.
Metaphors are harmful when writing abstract frameworks.
Metaphors are useful tools for creating systems that mimic real things.
When designed properly, metaphors provide conceptual and contextual information about a framework.
Metaphors are contradictory to abstract design.
Metaphors provide specific conceptual frameworks.
System designs that fit within these frameworks are elegant.
Systems that wish to use other concepts are generally awkward.
Adapters can connect between metaphors, but they should not be needed.
[_] 16% Documentation Requirements
Many "requirements" are really recommended conventions.
For example:
If we require return values to be typed, or ignored.
Obviously we can't force code to do that.
So we document it.
[_] 0% Style guide?
[_] 0% Event naming conventions.
Event names should read well following "on".
On failure.
On success.
[_] 0% "stopped" role for Reflex::Collections?
[_] 0% How to document these interactions?
[_] 0% Command naming conventions.
[_] 0% Normalize names in Reflex
[_] 0% Helpers
[_] 0% Internals
[_] 0% Traits
[_] 0% Parts and Reified Objects
[_] 50% Reflex::Manual
[_] 50% Nomenclature
[X] 100% Sandbox namespace name.
[X] 100% Reflexive - USING THIS ONE
Same purpose as the -X namespace convention.
Easiest to type... no modifier key (shift).
Reads better.
Sounds better when speaking.
[X] 100% ReflexX - NOT USING
Difficult to say: Reflex-ex.
Or difficult to hear: Reflex
Pretty easy to type, though.
[X] 100% Reflex::Ex - NOT USING
It's taxonomically superior, being hierarchical and all.
Aesthetically unappealing, visually, physically and phonetically.
Sounds like you're stuttering.
More difficult to type.
[_] 0% Reflex is a curated namespace.
[_] 0% Define rules for inclusion.
Threshold for usage on CPAN?
Threshold for requests on mailing list?
Other namespaces are fine.
Elsewhere? I don't care.
[X] 100% Namespace Requirements
[X] 100% Choose a short base name for the namespace.
Large class names are unwieldy.
Objects should be under a single top-level namespace.
What single top-level namespace should be used?
Bacon - Basic Asynchronous Cooperative Object Networks?
Reflex <- chosen one
[X] 100% Choose a relatively flat namespace for the framework.
Excessive namespace nesting is unwieldy.
The namespace should be organized.
How should the namespace be organized?
[_] 40% Class and Object Structural Requirements
[X] 100% Support full object orientation.
[X] 100% Support composition of smaller objects into larger ones (has-a).
[X] 100% Support composition through direct inheritance.
[X] 100% Support composition through class roles.
[X] 100% Support composition through runtime watcher roles.
[_] 0% Method parameters should follow a single standard.
[_] 0% Methods should receive only two parameters.
$self - The object being called.
$message - A Message object, or a subclass.
[_] 0% What about out-of-band information, such as other continuations?
Additional parameters?
Standard members of $message?
Lexical magic?
Not in the base.
Maybe as an extension.
[_] 0% Methods should standardize their return semantics.
[_] 0% What are those semantics?
Ignore return values?
emit() as return?
Maybe as an attribute?
[_] 0% Returned messages must be typed.
[_] 0% Function parameters should follow a single standard.
[_] 0% What should that standard be?
[X] 100% Procedural design should be supported.
Some people will prefer procedural design.
[X] Objects are their own condvars.
$object->next() waits for the object to emit a new event.
[X] 100% Wait for a particular event or one of several events.
A lot of time we're just waiting for an object to enter a particular state.
Event order is maintained; intermediate events are discarded.
[_] 0% Determine whether "role" is a confusing name.
Interestingly ambiguous.
Parts as in objects that assemble into other things.
Parts as in roles or duties in the whole.
Uninterestingly unambiguous.
Dreary name.
No longer than role or part.
Shortest alternative.
Ambiguous, since "job" may mean a work unit.
Perhaps drearier than duty.
Not: responsibility
Too long.
Res. or resp. are ambiguous abbreviations.
[X] 100% Object Containership Composition Rules
[X] 100% Containership rules are delegated to the objects themselves.
[X] 100% Runtime roles may be assigned as part of the observation, not the sub-object.
[X] 100% Multiple watchers may have the same runtime role.
This is already possible.
Currently roles address watchers.
Multiple watchers for a role requires additional addressing.
Possibly passing the watcher object into the callback.
[X] 100% Implement a _sender parameter supplied by Reflex::Role::Object.
[X] 100% Default handler method names may be derived from roles and message types.
Sender is a DNS resolver.
Sender's role is "resolver".
Sender emits a "success" event.
Container may define an on_resolver_success() method to handle the event.
[X] 100% Methods
[X] 100% Containership methods are defined by Moose traits.
[X] 100% Moose Observer trait implies that the stored object will be observed by the owner.
[X] 100% Moose Emitter trait implies that changing the attribute emits an event to observers.
[X] 100% Moose introspection allows objects to find their contents.
[X] 100% Class Inheritance Rules
[X] 100% Class inheritance rules are delegated to Moose.
[_] 24% Messaging Requirements
[_] 0% Object command interfaces must be methods.
[_] 0% Methods on the objects themselves may pass messages into themselves.
Synchronous method calls are translated into asynchronous messages.
[_] 0% Methods on the objects may trigger activity that emits new events.
Synchronous actions may start or stop messages emitted by an object.
[_] 0% Objects may be interfaces (proxies) that pass messages to other objects.
Objects may act as interfaces to local or remote services.
Synchronous method calls are translated into asynchronous messages.
[_] 0% Local accessors and simple mutators must be synchronous.
Messages for local accessors and mutators is unnecessary overhead.
[_] 0% Maybe make this part of the style guide.
[_] 44% Objects must be permitted to emit messages into their containers.
[_] 0% Message emission is optional, depending on the use case.
[_] 0% Define a use case where message emission is required.
[_] 0% Define a use case where it's not.
[_] 83% Emitted messages are first handled by the object emitting them.
[X] 100% Subclasses may handle messages emitted by base classes.
[X] 100% Subclasses may emit new messages.
[_] 50% Subclasses may emit the same message without re-catching it.
Implies that events bubble out of the object.
Base class emits, and subclasses pass it outward.
[X] 100% Implement as small methods that re-emit events.
Easy to implement.
Tedious, because you have to implement one for every event.
Slow because of the extra method indirection.
[_] 0% Implement some kind of event mapping.
Hard to implement.
Syntactically messy because the mapping must be made explicit.
This could probably be cleaned up later.
Faster since it avoids the indirection.
[_] 50% Emitted messages are next handled by explicit and role-based observers.
[_] 0% Explicit observers.
[X] 100% Role-based observers.
[X] 100% All forms of message handler (callback) must be supported.
[X] 100% Anonymous Coderefs
Anonymous coderefs support closures.
Anonymous coderefs and closures may be used to implement faux continuation passing style.
[X] Simple.
my $t = Reflex::Timer->new( ..., on_event => \&coderef );
[X] Observer.
$object->watch( watched => $object, event => "name", callback => \&coderef );
[X] Traits.
has member => ( traits => ['Reflex::Trait::Observed'] );
[X] 100% Object Methods
Is this not obvious?
[X] Simple.
my $t = Reflex::Timer->new( ..., on_event => rcb_method($watcher, "method_name") );
[X] Observer (array).
my $t = Reflex::Timer->new( ..., on_event => rcb_object($watcher, \@methods) );
[X] Observer (hash).
my $t = Reflex::Timer->new( ..., on_event => rcb_object($watcher, \%methods) );
Traits not supported at this time.
[X] 100% Class Methods
Classes may be used as singletons.
[X] 100% Do we want to support this?
[X] 100% Promises or condvars.
Named Subroutine References
Named message handlers are exportable as reusable interfaces.
Not needed. Roles perform this task.
[_] 0% Messages must be associated with their triggers.
[_] 0% One message may trigger another, inner message.
[_] 0% The inner message must be associated with the outer message.
If object represent tasks, then messages are not needed.
[_] 0% Do objects represent tasks?
[_] 0% Canceling the outer message must trigger cancelation of all associated inner messages.
[_] 0% Generally, all inner messages should complete before an outer message completes.
This emulates asynchronous call/return semantics for messages.
Task coordination is simplified.
[_] 0% Consider Enterprise Integration Patterns
[_] 0% Determine relevant patterns.
[_] 0% Reconcile competing patterns.
For example, make sure polling and event-driven consumers work together.
Even if one polling consumer is competing with an event-driven consumer.
[_] 0% Specify the roles and classes to implement these patterns.
[_] 0% Implement them.
Integration Styles
Not as applicable for event processing.
File Transfer
Shared Database
Remote Procedure Invocation
Messaging Systems
Message Channel
Pipes and Filters
Message Router
Message Translator
Message Endpoint
Messaging Channels
Point to Point
Publish Subscribe
Datatype Channel
Invalid Message Channel
Dead Letter Channel
Guaranteed Delivery
Channel Adapter
Messaging Bridge
Message Bus
Message Routing
Content Based Router
Message Filter - remove uninteresting messages from a stream
Dynamic Router - routing changes based on input from other entities
Recipient List - route a message to a list of dynamically specified recipeints
Splitter - process a message containing multiple elements, each of which may be processed in a different way
Aggregator - combine the results of individual but related messages so they may be processed as a whole
Resequencer - convert a stream of related but out-of-sequence messages back into the correct order
Composed Message Processor
Maintain overall message flow when processing a message consisting of multiple elements.
Each element may require different processing.
Maintain overall message flow when a message needs to be sent to multiple recipients.
Each recipient may send a reply.
Routing Slip
Route a message consecutively through a series of processing steps.
The sequence of steps is not known at design time.
The sequence may vary for each message.
Process Manager
Route a message through multiple processing steps.
The required steps may not be known at design time.
Steps may not be sequential.
Message Broker
Decouple the destination of a message from the sender.
Maintains central control over the flow of messages.
Message Transformation
Envelope Wrapper
Allows existing systems to participate in a messaging exchange that places specific requirements on the message format.
Examples: Message header fields, encryption.
Content Enricher
Allows communication with another system if the message originator doesn't have all the required data available.
Adds required data to messages, bringing them in compliance with recipients.
Content Filter
Discard uninteresting parts of messages.
Used to pare down large messages when a significantly smaller data set is required.
Claim Check
Cookie based communication.
Reduces data volume of messages without sacrificing information content.
Process messages that are semantically equivalent but arrive in different formats.
Canonical Data Model
Minimize dependencies when integrating applications that use different data formats.
Messaging Endpoints
Messaging Gateway
Encapsulates access to the messaging system from the rest of the application.
Messaging Mapper
Move data between domain objects and the messaging infrastructure while keeping the two independent of each other.
Transactional Client
How can a client control its transactions with the messaging system?
Polling Consumer
Allows an application to consume messages when ready.
Event-Driven Consumer
Allows an application to automatically consume messages as they become available.
Competing Consumers
Allows a messaging client to process multiple messages concurrently.
Each consumer competes for messages from the source.
Message Dispatcher
How can multiple consumers on a single channel coordinate their message processing?
Selective Consumer
How can a message consumer select which messages it wishes to receive?
Durable Subscriber
How can a subscriber avoid missing messages while it's not listening for them?
Idempotent Receiver
How can a message receiver deal with duplicate messages?
Service Activator
How can an application design a service to be invoked both via various messaging technologies and via non-messaging techniques?
System Management
Control Bus
Effectively administer a messaging system distributed across multiple platforms and a wide geographic area.
Route a message through intermediate steps to perform validation, testing or debugging functions.
Wire Tap
Inspect messages that travel on a point-to-point channel.
Message History
Effectively analyze and debug the flow of messages in a loosely coupled system.
Message Store
Report against message information without disturbing the loosely coupled and transient nature of a messaging system.
Smart Proxy
Track messages on a service that publishes reply messages to the Return Address specified by the requester.
Test Message
What happens if a component is actively processing messages but garbles outgoing messages due to an internal fault?
Channel Purger
Prevents 'left over' messages on a channel from disturbing tests or running systems.
[_] 0% Session Location Rules
[_] 0% Sessions should only be exposed for POE compatibility.
[_] 0% Multiprocessor Concerns
[_] 0% Reflex must support multiple processors with minimal syntax.
[_] 0% Define units of concurrency.
[_] 0% New objects may be started in other processes.
[_] 0% Processes may be forked at session creation time.
Caveat: The new session is executed in isolation.
[_] 0% Processes may be already established and attached to.
[_] 0% Processes may be local to the current machine.
[_] 0% Processes may also be located on other machines.
[_] 0% Ad-hoc remote processes.
Started by ssh, inetd, or other means.
[_] 0% Remote services.
[_] 0% Already running.
[_] 0% Started as needed, and running as long as needed.
[_] 0% New objects may be run in other threads.
[_] 0% Investigate whether we want to support threads directly.
Threads support may be more efficient on Windows.
Perhaps transparently thread/fork depending on $^O.
Or use fork() only, and allow Perl to choose whether to use processes or threads.
[_] 0% Define possible locations for concurrency units.
[_] 0% Local to the current machine.
Fork and exec a thin manager to proxy the object.
The manager instantiates the object in the subprocess.
[_] 0% On a remote machine.
Requires a valid network between machines.
Attach to an existing service on the remote machine.
Create an ad-hoc service on the remote machine.
[_] 0% Normalize as much as possible.
Use services locally to minimize special cases?
[_] 0% Possible RPC transports.
Good at any distance. Equally good for localhost and internetworked RPC.
Multi-language convenience.
Ability to support multiple transports.
Concurrently would be "nice to have".
However a single transport of any type would also be nice.
Fails "multi-language convenience".
[_] 0% ZeroMQ
Chip Salzenberg recommends.
I've had trouble getting the Perl bindings built.
Lack of wide compatibility makes this troublesome.
[_] 0% AMQP
[_] 0% Thrift.
Multicast UDP
Fails "good at any distance".
[_] 0% Consider MDNS for finding objects.
[_] 0% Continuation Rules
[_] 0% Continuations may be associated with objects.
$self is such a continuation.
[_] 0% Object-scoped resources (watchers, etc) should be stored in the object's continuation.
[_] 0% Object destruction triggers associated resource cleanup.
[_] 0% Continuations may be associated with messages.
[_] 0% A message's sender and receiver may have their own continuations associated with the message.
[_] 0% Data stored in the sender's continuation is not visible to the receiver.
[_] 0% Receiver data is not visible to the sender.
[_] 0% Message-scoped resources should be stored in the message's continuation.
[_] 0% Message cancelation triggers associated resource cleanup.
[_] 12% Distributed Messaging
[_] 0% General Tasks
[_] 0% Choose a transport.
[_] 0% ZeroMQ.
I'd like to use this, but it doesn't install on OSX.
[_] 0% XMPP.
Help Nick Perez with his stuff, especially Reflexifying it?
Inspired by ... serial over XMPP.
[_] 0% IRC
Ho ho ho!
[_] 0% Make it pluggable?
Not everyone wants to use the same language.
Introduces complexity.
Need a way to minimize additional overhead.
How much is this an issue?
Already introducing network delays.
[_] 0% Make it multiprotocol?
Not every network is homogenous.
Introduces complexity.
Need a way to minimize additional overhead.
How much is this an issue?
Already introducing network delays.
Use Erlang's?
Other languages support this.
[_] 0% Can we use a Reflex thing in Reflex to ferry under-Reflex messages?
[_] 25% Erlang Inspiration
[_] 0% Process ID / Pid
Mortals might understand Erlang processes to be akin to threads.
Each Erlang process tends to perform a single task.
Reflex's closest relative might be the object.
[_] 0% Pid ! Message
[_] 0% Send a message to a process.
Reflex's closest relative might be asynchronous remote method invocation.
[_] 0% Currently Reflex treats local method invocation as commands.
To extend this, we'd need proxy objects on the local side.
Proxy objects are deceptive---you can't call accessors on them, for instance.
However, Reflex::Trait::EmitsOnChange notifies interested parties when attributes change.
[_] 0% Alternatives.
[_] 0% String-and-parameter based messaging.
More flexible than proxy objects.
The design isn't as clean as proxy objects, however.
[X] 100% Erlang's "receive" BIF (Built In Function).
Erlang's "receive" acts as a blocking message receipt and dispatch table.
It's pretty close to the actor pattern.
Erlang can get away with this because its processes are small and cheap.
[X] 100% Reflex objects already receive messages via callbacks.
[_] 0% Erlang Port Mapper Daemon
Erlang Process Information
What things Erlang knows about processes.
Erlang Processes.
Process registration.
Process links.
Erlang Port Information
Kind of sparse information, but it's a lead to more details.
More about ports.
Erlang Process Mapping Daemon
Started automatically when Erlang starts a distributed node.
Listens on a standard port.
Speaks a standard protocol.
Erlang BIFs map to epmd activities.
Uses DNS to find remote nodes.
When connecting to a remote pid, one uses name@host.
You at least need to know the remote host.
A bit rigid?
Erlang External Term Format
Used to serialize Erlang data between nodes.
We could use it---or provide it as an option---to speak directly with Erlang processes.
Interoperability with Other Languages
C Nodes are specifically nodes written in C.
Generically, they're nodes written in other languages.
Perl being one possibility.
Distributed Erlang
General reference.
Erlang Namespace BIFs (Built In Functions)
register(Name, Pid)
$my_namespace{$name} = $pid;
Can now use $name wherever $pid would be used.
delete $my_namespace{$name}
return $my_namespace{$name}
return keys 0%my_namespace
Erlang Remote Process Management BIFs
spawn(Node, Module, Function, Args)
Connect to the remote Node.
Instantiate an object of Module.
Invoke its Function, with Args.
TODO - What does it return?
spawn_link(Node, Module, Function, Args)
Connect to the remote Node.
Instantiate an object of Module.
Invoke its function, with Args.
The linkage implies exception notification.
monitor_node(Node, Flag)
If Flag is true, begin monitoring the node.
Otherwise stop monitoring.
The local node will receive a {nodedown, Node} event if the remote Node ever goes down.
Returns the current Node's name.
Returns a list of known Node names.
Returns a Node's name, for a given Pid or Port.
Disconnects from a remote node.
Erlang Group BIFs
Returns the Pid of the current Node's group leader?
group_leader(Leader, Pid)
Sets the group leader of process Pid to be Leader.
Other Erlang BIFs?
[_] 71% Common primitive classes must be provided.
[_] 50% Callback Abstractions
[X] 100% Reflex::Callback
[X] 100% Reflex::Callback::CodeRef
[X] 100% Reflex::Callback::Method
[X] 100% Reflex::Callback::Promise
[_] 0% Reflex::Callbacks
Syntactic sugar for callback creation.
[_] 0% Need to make this a declarative thing.
[_] 84% Low-level event watchers.
[X] 100% I/O Watchers
[X] 100% Reflex::Role::Readable
[X] 100% Reflex::Role::Writable
[_] 75% I/O Performers
[X] 100% Roles
[X] 100% Reflex::Role::Reading
[X] 100% Reflex::Role::Writing
[X] 100% Reflex::Role::Streaming
[_] 50% Classes
[X] 100% Reflex::Stream
[_] 0% Integrate Data::Transform
[X] 100% Time Watchers
[X] 100% Roles
[X] 100% Reflex::Role::Timeout
[X] 100% Reflex::Role::Wakeup
[X] 100% Reflex::Role::Interval
[X] 100% Classes
[X] 100% Reflex::Timeout
[X] 100% Reflex::Wakeup
[X] 100% Reflex::Interval
[X] 100% Signals
[X] 100% Roles
[X] 100% Reflex::Role::SigCatcher
[X] 100% Classes
[X] 100% Reflex::Signal
[X] 100% Clients and Servers
[X] 100% Roles
[X] 100% Reflex::Role::Connecting
[X] 100% Reflex::Role::Accepting
[X] 100% Reflex::Role::Recving
[X] 100% Classes
[X] 100% Reflex::Acceptor
[X] 100% Reflex::Connector
[X] 100% Reflex::Client
[X] 100% Reflex::UdpPeer
[_] 66% Pool Management
[X] 100% Reflex::Role::Collectible
[X] 100% Reflex::Collection
Manage a collection of Reflex objects.
Removes objects from itself when they shut down.
Reflex servers can use this to manage client objects.
[X] 100% has_many syntactic sugar for Reflex::Collection.
[_] 0% Worker Pools
(These are intial names I'm throwing out to get discussion started.)
An object repesenting a unit of work needing to be completed.
Composite Job.
A job comprised of smaller jobs.
A resource that can perform tasks to increase the completeness of a job.
A job may not be fully completed without the cooperation of multiple workers.
A job may require multiple passes from a single worker to become fully complete.
Workers from multiple pools may be needed to fully complete a job.
Worker pool.
A group of related workers that share common resources.
Pool Manager.
An object that manages a worker pool's resources.
This object may also consider workers to be resources.
Generic Design
A program has zero or more lifeguards.
Strawman API
Release API
Worker Pool
Each lifeguard configures and manages a single worker pool.
Strawman API
Release API
Each worker pool dynamically manages zero or more workers.
Strawman API
Release API
Each worker performs tasks for zero or more jobs.
Strawman API
Release API
Agorman Specific Business Requirements
Present for practical ideas; not everything will apply a general, base worker pool.
Loading and Unloading Code
Jobs can be created and dropped into one or more libraries (directories, databases?).
Job functionality can be added, removed and improved at runtime.
Jobs as roles can specialize a generic job class by implementing the guts of the job, e.g. work().
Jobs as classes can consume a generic job role, implementing the interface required by the role.
Jobs as classes can inherit a generic job class and implement the work interface.
Unloaded job code should be removed from memory, if possible.
Job Workflows
Job data should be passable between multiple workers, each worker implementing a step or stage of a larger task.
See the Enterprise Integration Patterns elsewhere in this document. I think some of them may apply. --Rocco
Multiple Configurable, Concurrent Worker Pools
A single WorkerPool instance should be able to run multiple pools at once.
Although it might be more logical to instantiate different pools, each with a different configuration.
In this case, however, it may be desirable for all pools to share some global resource limit.
TODO - What is the purpose of job_types?
| my $pool = WorkerPool->new(
| max_concurrent_jobs => 1,
| min_concurrent_jobs => 1,
| job_types => [ qw( Job1 Job2 ) ],
| );
Pool/Job Coordination
Worker pools must be able to watch for management events from the jobs they run.
A new job has started.
A job has succeeded; here is an optional result.
A job has updated.
TODO - Updated what?
A job has failed. Here is some error condition.
Workers should be able to manage jobs in the pool.
Add new jobs.
Remove jobs.
Find jobs.
Retrieve job counts.
Implies that jobs have access to their pools and other pools.
Generic Worker Pool Concepts
[_] 50% Process Watchers
[_] 0% Reflex::Role::ProcReaper?
I can't find a good reason to write this role.
This seems highly dynamic.
Contributions are welcome.
[X] 100% Reflex::PID
[X] 100% Containership Traits
[X] 100% Reflex::Trait::EmitsOnChange
[X] 100% Initial implementation, with explicit syntax.
[X] 100% Make declarative syntax so we can avoid the icky explicit use of traits.
[X] 100% Reflex::Trait::Observed
[X] 100% Initial implementation, with explicit syntax.
[X] 100% Make declarative syntax so we can avoid the icky explicit use of traits.
[X] 100% POE Interfaces
[X] 100% Wheel wrappers.
[X] 100% Reflex::POE::Wheel
Generic base class for POE::Wheel watchers.
[X] 100% Reflex::POE::Wheel::Run
Specific subclass for proving the concept.
[X] 100% Generic Component shims.
[X] 100% Create a postback analog for components that expect postbacks.
Creates a coderef that, when called, posts a message to the object's session, with routing information back to the object.
Postbacks use closures to pass @passthru_params to the callback.
Closures can also handle routing information.
Usage syntax must be identical to Reflex postbacks.
Creation syntax may differ from Reflex postbacks.
Identical creation syntax would be to allow others to create them for us.
However, most eternal postback creators use $_[SENDER]->postback().
$_[SENDER] is the Reflex object's session, not an individual object.
Therefore, components that call $_[SENDER]->postback() will not work.
Therefore, $_[SENDER]->postback() syntax is not needed.
To support identical creation syntax.
$_[SENDER] must be a session that maps directly to a single object.
It could be a dynamically created session for the purpose of interfacing.
Indirection would be heavy.
Consider it for a future revision.
[X] 100% Create an event analog for components that expect events.
Many components allow callers to specify return events.
We create a unique, anonymous event that calls a specific object and method upon dispatch.
We can pass this event to components that expect them.
Syntax if anonymous events may be blessed objects
my $event = Reflex::POE::Event->new(...);
$_[KERNEL]->post($event, @callback_params);
Syntax if events may not be blessed
Some explicit cleanup must be provided and adhered to.
Rely on object DEMOLISH to automatically clean up for us.
CAVEAT: Components that stringify event names will fail.
Sorry, but they must be blessed for now.
The bless and DEMOLISH tracking is very convenient.
I haven't found a good, reliable way to avoid it.
Dispatch Mechanism
Events that are objects in the Reflex::POE::Event class are invoked to deliver themselves.
[X] 100% Session subscription.
A client Reflex object creates the component, to be used as a service.
The client Reflex object registers interest in the service's events.
The service's events are posted to all interested Reflex objects.
POE::Component::IRC will be a good example component.
Reflex::POE::Session watcher.
Dispatch Mechanism
Sender Interest
The object creates the component.
The object registers interest in all events from the component.
[X] 100% Components that emit specific events require Wheel-like wrappers.
[X] 100% Is this worth supporting?
No. The Session subscriber can detect any events emitted by the component.
[_] 80% Basic Modules
[X] 100% Reflex::Base
[X] 100% Reflex::Role::Reactive
[_] 0% MooseX::Role::Reactive
[_] 0% Fork git project.
[_] 0% Remove all nonessentials.
[_] 0% Fix up dist.ini.
[_] 0% Rename things.
[X] 100% Reflex::Role
[X] 100% Reflex
[_] 13% Primitive program pieces.
[_] 0% Clean up this branch of the outline.
[_] 0% Reflex::App
[_] 0% Does it offer anything in particular?
[_] 0% Strawman implementation.
[_] 0% Determine API.
[_] 0% Reflex::Cron
[_] 0% Strawman implementation.
[_] 0% Determine API.
See POE::Component::Cron for clues.
Would Chris Fedde like to work on this?
[_] 0% Wait for repeating times.
[_] 25% Reflex::Client::HTTP
[X] 100% Reflex::Connector
[_] 0% Reflex::Connector::Keepalive
[_] 0% Strawman implementation.
[_] 0% Determine API.
[_] 0% Reified version of Reflex::Role::Connector::Keepalive?
[_] 0% Reflex::Resolver
[_] 0% Determine API.
[_] 0% Determine how to make asynchronous.
[_] 0% IPV4
[_] 0% IPv6
[_] 0% Reified version of Reflex::Role::Resolver
[_] 0% Is this a reified version of Reflex::Role::Client::HTTP?
Do we really need to be that dogmatic about roles?
What would a role allow us to do?
[_] 0% Reflex::Conduit
[_] 0% Reified version of Reflex::Role::Proxy
[_] 0% Based on the example proxy.
[_] 0% Between-endpoint flow control?
[_] 0% Generic rate throttling?
[_] 0% Reflex::Process
[_] 0% Strawman implementation.
[_] 0% Determine API.
See POE::Wheel::Run for clues.
[_] 0% Reflex::Tail
[_] 0% Strawman implementation.
[_] 0% Determine API.
See POE::Wheel::FollowTail for clues.
[_] 0% Reified version of Reflex::Role::Tail
[X] 100% Reflex::Collection
[_] 0% What else? Probably a lot!
[_] 25% Optimizations.
[X] 100% Only $kernel->call() when we need to switch sessions.
[_] 0% Do we need call() at all?
[_] 0% Explore IO::Lambda's cheat.
[_] 0% Consolidate POE-specific code out into a single role.
From Sartak's slides on roles:
| package Database;
| has backend => (
| is => 'ro',
| does => 'Backend::Transactional',
| handles => 'Backend::Transactional',
| );
Allows other event loops to be supported directly rather than through POE.
me> Let's say I have a class Mumble that's a generic API for something with platform-specific implementations. I have Mumble::Yay and Mumble::Boo with the bits that the Yay! and Boo! platforms need.
me> I want to use Mumble, and Mumble->putty() to do the putty() thing regardless how the platform needs to putty mumbles.
ether> you want a Mumble factory, that will construct a Yay or a Boo for you depending on your platform
doy> yeah
rafl> for example using Module::Implementation
ether> $obj->isa_ok('Mumble'); $obj->can_ok('putty');
doy> Mumble->new->putty is a lot easier to deal with, generally
PerlJam> sounds like the DBI/DBD dichotomy
doy> well, probably something other than ->new, but you know
ether> new_for_my_platform
ether> but shorter
me> Thank you.
[_] 0% POE::Session singleton
[_] 0% has session_id
[_] 0% sub run_all
[_] 0% sub run_within_session
[_] 0% sub call_gate
[_] 0% Abstract event loop things.
[_] 0% Reflex roles must not emit() messages by default.
Stylistic difference.
Roles are statically composed.
emit() is dynamic composition.
Useless overhead.
Many emitted events will go unhandled.
Finding this out at runtime is slow.
Allow the programmer to choose this overhead, only when it's likely to be necessary.
[_] 0% Remove the default emit()s.
[_] 0% Provide a consumer syntax to concisely specify emit()s at "with" time.
[_] 80% Parameterized role cleanup.
[X] 100% Role units of reactive behavior should not emit() events.
[X] 100% Remove event_parameter() from Reflex::Role.
[X] 100% Remove use of event_parameter() entirely.
[X] 100% Remove event_parameters declarations.
[X] 100% Sort the role parameter declarations.
[X] 100% Remove $ev_ variables.
[X] 100% Roles should not define default public "interface" callbacks.
[X] 100% Roles should require consumers to define cb_* callbacks.
[X] 100% Consumers should define cb_* methods, often in terms of Reflex::Callbacks make_emitter() or make_terminal_emitter().
[X] 100% Remove default $cb_* methods from roles.
[X] 100% Attribute parameters should begin with att_ to avoid confusion with simple value parameters.
[X] 100% Rename the attribute_parameters declarations.
[X] 100% Rename corresponding variables in the parameterized roles.
[X] 100% Rename attribute parameters in the consumers.
[X] 100% Require consumers to define the attributes.
[X] 100% The various parameters automatically add their named things to the list of required methods.
[X] 100% Make sure this plan works.
[X] 100% It doesn't.
The things being required depend on the values of specific parameters.
These values aren't known at role definition time.
They are known at role composition time.
[X] 100% Go back to explicit requires().
[X] 100% Rename references in callback_parameter declarations.
[X] 100% Rename references in method_parameter declarations.
[X] 100% Remove the default methods.
[X] 100% Implement the methods in the consumers.
[X] 100% Remove the methods from the roles.
[X] 100% Test all examples.
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[X] 100%
[_] 0% Revise all documentation.
Boolean role parameters are opportunities for new roles or role subclasses.
Static behaviors should be determined at role consumption time.
Not continually evaluated at runtime.
Runtime behavior toggles are only appropriate when behavior should change at runtime.