Promises, promises

Pinky PromiseWill Corwin strikes again, offering a powerful new feature to the Strange feature set. This time, we introduce ‘Promises’, a simple, powerful pattern for handling asynchronous callback behavior. If you’re familiar with q-promise (or the AngularJS equivalent), you’ll know exactly where we’re going with this.

[EDIT] June 8. Attentive reader Stephan identified that I had oversimplified my examples by forgetting to inject RoutineRunner. I’ve quickly added in the missing bits — early on a Monday morning — hopefully I repaired it all correctly![/EDIT]

This will sound crazy at first (bear with me for a moment) inasmuch as we’ve always told you about dependency inversion, but with promises we will now “invert the inversion”. That does sound crazy doesn’t it? But it actually makes sense! We practice inversion because the proper job of setting dependencies lies outside the client class. Promises turn this on its head, because the responsibility for determining what to do with a job the client requested lies with the client itself.

“I went to the bakery and ordered a cake.” The baker doesn’t know why you asked (though you might add some detail so he can decorate), nor should he. Decoupling in this case means both client and service know as little about each other as possible. Client calls service’s API, asking for the “cake”. Perhaps a cake is already available. Perhaps not.

The baker/service responds with a promise to deliver the cake now, or whenever it’s ready. Responding with a promise for a thing instead of the thing itself allows greater flexibility whenever you know or suspect that the thing might not be instantly available.

Let’s take this from the theoretical to the concrete with something everyone is certainly familiar with: an HTTP call.

We all know this would fail:

string GetLevelName() {
    return new WWW('http://myserver/get/the/level');
}

This fails because this isn’t how WWW works. WWW doesn’t have the result sitting around for you. It has to go to a server to get it, and that takes time. To handle this, we write WWW with a yield:

IEnumerator FetchLevelName() {
    WWW www = new WWW('http://myserver/get/the/level');
    yield return www;
    CurrentLevel = www.text;
    //Now do something with the level name
}

So in a spaghetti-coded world, this is fine. You could drop this into any MonoBehaviour and be off to the races. But we’re in Strange, and that means we like to separate this sort of behavior into a service. So imagine a Command that triggers this service and wants to hang around until the result is ready. How do we do this?

Note that throughout the following examples we use the same RoutineRunner you can find in StrangeRocks.

 // The Command
 using System;
 using strange.extensions.command.impl;
 namespace strange.test
 {
     public class FetchLevelNameCommand : Command
     {
         [Inject]
         public IServerAPI service { get; set;}
         override public void Execute()
         {
             Retain();
             service.FetchLevelName();
         }
     }
 }

 // The Service
 using System;
 using System.Collections;
 namespace strange.test
 {
     public class ServerAPI : IServerAPI
     {
         [Inject]
         public IRoutineRunner routineRunner { get; set; }
         private string CurrentLevel;
         public void FetchLevelName()
         {
             routineRunner.StartCoroutine(Fetch);
         }

         private IEnumerator Fetch()
         {
             WWW www = new WWW('http://myserver/get/the/level');
             yield return www;
             CurrentLevel = www.text;
             //Now do something with the level name
         }
     }
 }

In the code above, I’ve obviously left a great big hole. The Command is Retained, waiting for the Service to return a value. But there’s not yet any way for the Command to get the data back, finish its business and release. Since the yield is inside the Service, there’s no real way for the Command to know when the data it’s awaiting is ready.

We could handle this by polling the service:

// The Command
 using System;
 using System.Collections;
 using UnityEngine;
 using strange.extensions.command.impl;
 namespace strange.test
 {
     public class FetchLevelNameCommand : Command
     {
         [Inject]
         public IServerAPI service { get; set;}
         [Inject]
         public IRoutineRunner routine { get; set; }
         override public void Execute()
         {
             Retain();
             routine.StartCoroutine(CheckForName());
             service.FetchLevelName();
         }
         private IEnumerator CheckForName()
         {
             yield return new WaitForSeconds(.2f);
             if (service.CurrentLevel != null)
             {
                 //Finally do something with the data
                 Release();
             }
             else
             {
                 routine.StartCoroutine(CheckForName());
             }
         }
     }
 }

 // The Service
 using System;
 using System.Collections;
 namespace strange.test
 {
     public class ServerAPI : IServerAPI
     {
         [Inject]
         public IRoutineRunner routineRunner { get; set; }
         public string CurrentLevel { get; set; }
         public void FetchLevelName()
         {
             routineRunner.StartCoroutine(Fetch);
         }

         private IEnumerator Fetch()
         {
             WWW www = new WWW('http://myserver/get/the/level');
             yield return www;
             CurrentLevel = www.text;
         }
     }
 }

Ok, that works for a definition of “works” that means “ugly, inefficient and unmaintainable.” It requires that the client knows a lot more about the inner workings of the service than you would ever want.

We can improve on this with a signal from the service.

 // The Command
 using System;
 using strange.extensions.command.impl;
 namespace strange.test
 {
     public class FetchLevelNameCommand : Command
     {
         [Inject]
         public IServerAPI service { get; set;}
         override public void Execute()
         {
             Retain();
             service.NameReadySignal.AddOnce(OnName);
             service.FetchLevelName();
         }

         private void OnName(string name)
         {
             //Do something with the data
             Release();
         }
     }
 }

 // The Service
 using System;
 using System.Collections;
 using strange.extensions.signal.impl
 namespace strange.test
 {
     public class ServerAPI : IServerAPI
     {
         [Inject]
         public IRoutineRunner routineRunner { get; set; }
         private string CurrentLevel;
         public Signal NameReadySignal = new Signal();
         public void FetchLevelName()
         {
             routineRunner.StartCoroutine(Fetch);
         }

         private IEnumerator Fetch()
         {
             WWW www = new WWW('http://myserver/get/the/level');
             yield return www;
             CurrentLevel = www.text;
             NameReadySignal.Dispatch(CurrentLevel);
         }
     }
 }

This a substantial improvement. The service has a defined API, which the client accesses. When the data is ready, the Service fires its signal and the client is informed.

The promise pattern is similar, but it trims the API considerably.

 // The Command
 using System;
 using strange.extensions.command.impl;
 namespace strange.test
 {
     public class FetchLevelNameCommand : Command
     {
         [Inject]
         public IServerAPI service { get; set;}
         override public void Execute()
         {
             Retain();
             service.FetchLevelName().Then(OnName);
         }

         private void OnName(string name)
         {
             //Do something with the data
             Release();
         }
     }
 }

 // The Service
 using System;
 using System.Collections;
 using strange.extensions.promise.api;
 using strange.extensions.promise.impl;
 namespace strange.test
 {
     public class ServerAPI : IServerAPI
     {
         [Inject]
         public IRoutineRunner routineRunner { get; set; }
         private IPromise promise = new Promise();
         public IPromise FetchLevelName()
         {
             routineRunner.StartCoroutine(FetchLevelNameFromServer);
             return promise;
         }
         private IEnumerator FetchLevelNameFromServer ()
         {
             WWW www = new WWW('http://myserver/get/the/level');
             yield return www;
             promise.Dispatch(www.text);
         }
     }
 }

Note how clean the Promise structure is from outside the service. Just a simple promise.Then().

One beautiful aspect of this pattern is that the promise can be (but does not have to be) resolved immediately. So imagine we now cache our server data. This change means that the data may or may not be local at any given moment. The Promise handles this possibility very elegantly (note changes in red):

 // The Command
 using System;
 using strange.extensions.command.impl;
 namespace strange.test
 {
     public class FetchLevelNameCommand : Command
     {
         [Inject]
         public IServerAPI service { get; set;}
         override public void Execute()
         {
             Retain();
             service.FetchLevelName().Then(OnName);
         }

         private void OnName(string name)
         {
             //Do something with the data
             Release();
         }
     }
 }

 // The Service
 using System;
 using System.Collections;
 using strange.extensions.promise.api;
 using strange.extensions.promise.impl;
 namespace strange.test
 {
     public class ServerAPI : IServerAPI
     {
         [Inject]
         public IRoutineRunner routineRunner { get; set; }
         private string CurrentLevel;
         private IPromise promise = new Promise();
         public IPromise FetchLevelName()
         {
             if (CurrentLevel != null)
             {
                 promise.Dispatch(CurrentLevel);
             }
             else
             {
                 routineRunner.StartCoroutine(FetchLevelNameFromServer);
             }
             return promise;
         }
         private IEnumerator FetchLevelNameFromServer ()
         {
                 WWW www = new WWW('http://myserver/get/the/level');
                 yield return www;
                 CurrentLevel = www.text;
                 promise.Dispatch(CurrentLevel);
         }
     }
 }

See how that change is completely invisible to the client? Whether that data is available or not is no longer the client’s responsibility. The contract between promisor and promisee is “I’ll deliver it when it’s ready.” That’s all.

The promise structure is very simple and flexible, every promise method returns a promise. In the same way that a binder can Bind.To.To.To… a promise can Promise.Then.Then.Then… allowing you to create chains of resulting actions.

There are also methods for Progress, Fail and Finally which you can use for reporting percentage of job completion, errors and irrespective conclusion, respectively.

Promise is yet another new feature in the upcoming next release of StrangeIoC, now available on the tip branch. For the full set of planned features see this wiki page. As always, we encourage you to test out the new features and help us find any problems before we make this build official.

Thanks!

Advertisements

Do you Strange?

Today’s post is just a quickie.

Alongside our rapidly developing next version of Strange, we’ve been working on an updated website. The new site contains two new community-oriented pages:

Strange Projects

This page will feature released projects that have utilized StrangeIoC. We’re encouraging you to submit anything you’ve built…a game or app, on web, mobile, standalone, etc, that shows how you are putting Strange through its paces.

Other resources

This page is part of our ‘Help’ section, and provides, alongside all our other documentation, links to code samples, tutorials, videos, and anything else that can help a developer learn and grow with StrangeIoC. If you’ve written a blog post, created a presentation, or done anything else that could help your fellow coders learn to do Strange things, we’d love to include it in our list.

Thanks friends. Keep it Strange!

The Good, The Bad and The Strange

This is a presentation I gave awhile back, which I finally got around to recording. It explains the core principle of dependency inversion upon which Strange is based. It’s largely intended as an intro that explains why writing Singletons is such bad practice (and writing Factories only marginally better), and why injection is a better way to go.

Part 1 (theory)

Part 2 (practice)

Implicitly Delicious

One great new feature in Strange v0.7 (release candidate now on dev) is implicit bindings. This work comes to us courtesy of Strange super-contributor Will Corwin, author of Strange Signals. Implicit bindings adds a groovy mechanism for cleaning out the ‘routine’ mappings that sometimes clutter your Context.

As usual, let’s start with an illustrative example. Let’s say you’ve created an AvatarService for your game to handle the saving and retrieving of avatar data. Because you’re a diligent programmer, you also have an IAvatarService interface. Here’s the mapping as it would appear in your Context:

injectionBinder.Bind<IAvatarService>().To<AvatarService>().ToSingleton();

Awesome. You’re doing the good IoC thing: injecting and writing to the Interface rather than the concrete class. But, er, come over here where nobody can hear us. Now, between you, me and my ravenous DeathDroid, the truth is that you only have one AvatarService, right? Or you have one that you use 90 percent of the time? In fact, you probably have many classes like this, where the mappings are the same each and every time you build a new Context. These are routine mappings — bindings that look the same nearly every time you map them. Wouldn’t it be nice to have all the advantages of binding without cluttering up your Context with all this pro forma boilerplate? Don’t we all just want to walk into the Strange Bar and bark out “Gimme the usual?”

This is exactly what implicit bindings are for. By allowing you to specify default implementations, we can now reserve the Context only for mappings that are different from “yer usual.” For now, Implicit bindings allow you to do the following things:

  • Tag an interface with the class that implements it by default
  • Tag a class with one or more interface(s) it implements by default
  • Tag a View with the default Mediator
  • Tag a Mediator with a default View

Implicit Injection Bindings

The first two bullet points above describe injection bindings. For example, you could achieve our AvatarService binding by doing either of the following:

// Tagging an implementor
namespace com.example
{
    [Implements(typeof(IAvatarService))]
    public class AvatarService : IAvatarService
    {
        //body of the class
    }
}

// Tagging an interface
namespace com.example
{
    [ImplementedBy(typeof(AvatarService))]
    public interface IAvatarService
    {
        //body of the interface
    }
}

While you can tag either Interface or Implementor, as a best practice we recommend tagging the Implementor. Tagging the Interface probably fits a special case for library distribution, but is not ideal for standard use. Note that there is a priority order to implicit injection binding, as follows:

  • Interfaces give way to
  • Implementors, which give way to
  • Explicit bindings in the Context.

Also note that you can create Singleton, named, single-Context and cross-Context bindings implicitly. You cannot yet create factory or value bindings (maybe in a future release).

Implicit Mediation Binding

We apply the same idea to Mediation.

// tagging a View
namespace com.example
{
    [MediatedBy(typeof(ShipMediator))]
    public class ShipView : View
    {
        //body of the class
    }
}

// tagging a Mediator
namespace com.example
{
    [Mediates(typeof(ShipView))]
    public class ShipMediator : Mediator
    {
        [Inject]
        public ShipView view { get; set; }
        //body of the class
    }
}

As with injections, there’s an order of priority for Mediation bindings:

  • Views give way to
  • Mediators, which give way to
  • Explicit bindings in the Context.

We consider it best practice to tag the Mediator, not the View.

Magic: The Binding

Now, there is one more step you need to do to get all this automagic binding to work. Like Signals, Will’s made implicit bindings an opt-in feature, so you need to tell Strange (1) that you want to use it and (2) which namespaces you want scanned for binding. Yes, that’s right, implicit binding requires namespaces. The required code is simple (we suggest putting it at the top of your mapBindings method).

override protected void mapBindings()
{
    string[] namespaces = new string[]
    {
        "somenamespace.i.want.scanned",
        "another.namespace"
    };
    implicitBinder.ScanForAnnotatedClasses(namespaces);
    // add other bindings here
}

Scans include child namespaces, so if you scan “com.example”, the scan covers “com.example.myproject” and “com.example.myproject.services”, etc.

And there you go! Implicit bindings that go down smoother than a sherry-finished Balvenie.