Attach Pattern !

Pretty much everyone can put together a couple of Lego blocks.  You drop a couple of blocks in untrained hands and quickly, without instruction, you will find them stuck together within minutes.

One of the integral parts of Legos success is the "ease" of which blocks can be assembled.  No special fasteners, no glue, no documentation is needed.  Yet, with this simple assembly process they have been used to contruct prototypes for futuristic vehicles, cities, and of course robots.

I would propse "attach" be considered a keyword for MRL.  Where two services can be "attached" with the following command.

service01.attach(service02)

What does this do ?  It does our best guess of what is needed or wanted when two services are made aware of one another.

  • it creates a binding between a servo and servo controller so the servo can be moved
  • it represses talking to itself when a speech synthesis and speech recognizer are attached
  • it attaches sensors to sensor controllers
  • the list goes on and will grow ... 

We have done a great job of standardizing the publish/subscribe system currently in MRL.  It works with ease, over networks, without much complexity.  Now, lets do the same with attach.  

For clarity, attach should as much as possible be a method only for attaching services to other services. 

Attach Rules :

I find it easier to show by example so given the following

interface ServiceType1 {

Rule 1 Bi-directional

if this

For any two services which can attach to one another I would expect to find the following signatures :
s2.attach(ServiceType1 s1)
s1.attach(ServiceType2 s2)

When both directions of attach are supported it becomes trivial to 'attach' things.  However, this could generate a substantial amount of ambiquity or complexity, unless these simple rules are followed.

 

Given 2 different services service1 and service2 of types ServiceType1 & ServiceType2 respectively

  • s1.attach(s2) and s2.attach(s1) should result with the same outcome.  Both services should be in the expected state regardless of the direction of attach.
  • the minimal attach should only have a service and no other parameters
  • ServiceType2.attach

The two methods allow for s1.attach(s2) or s2.attach(s1).
The two methods are parameterless - they "only" contain the other service.
All data needed for s1 to attach to s2 is pulled from methods of s2.
All data needed for s2 to attach to s1 is pulled from methods of s1.

The patterns of the bodies of these attach functions follow the same flow.

  1. s1 check to see if your already attached to s2 - if so simply return
  2. s1 query necessary data from s2 in order to successfully attach (do not "set" data on s2, you should need to read only)
  3. last thing the method should do is call the inverse s2.attach(this)

The s2 body of attach follows the exact same outline - only difference is the details of 'attaching'

For simplicity and clarity these are 2 different methods.
So I would propose ServoControl.attach(pin) be changed to Servo.attachPin(pin)

The following method tests if a 'specific instance' of another service is currently attached.
This is important since multiple services could potentially be connected to a single service.
This can return specific information.
public boolean isAttached(ServoController controller) 

This method is not specific and should typically be avoided
public boolean isAttached()

"Helper" attach methods
In order to reduce lines of scripting of guide the user for the 'minimal' amount of data in order to get two services to successfully attach, methods with additional parameters can be created.

An example is the following 
servo.attach(arduino, 7)

The body of this method will do the following :
public void attach(ServoController sc, int pin){
      this.pin = pin;    // the pin is set
      attach(arduino); // the parameterless service attach gets called
}

Data elements are simply set in the "Helper" methods, but all the 'logic' of attaching is always done in the parameterless method.  Attaching by name vs reference can be a useful pattern, because attaching by name allows remote attachments

 public void attach(String controllerName, int pin) throws Exception {
    this.pin = pin;
    attach((ServoController) Runtime.getService(controllerName));
  }
 
 
The name is more important than the reference.  The name allows remote attachment.  If methods are used to communicate between services using names, and direct reference is not necessary, and the services should be able to successfully integrate with one another remotely.