StrangeIoC v1.0 RC1 is here!!!

Will Corwin just pulled us over the finish line! Or the starting line…whatever. The first release candidate for Strange v1.0 is now on tip.

https://github.com/strangeioc/strangeioc/tree/tip

Also check out Will’s post in the Google Group (you are a member right?): https://groups.google.com/forum/#!topic/strangeioc/IWRTPE4jc0w

Please start using it…find all the flaws…let us know what you like and what you don’t. We’d like to have it blessed and official in time for Unite Boston.

As always, a huge thanks to Will for pushing things forward, and a further thanks to all of you for your patience and interest. Let’s make Unite Strange!

v1.0 and BSHT latest

Once again, just keeping you up-to-date on our progress.

The Big, Strange How-To proceeds at a reasonable pace. We’ve received quite a lot of excellent feedback on everything released so far, and I can’t begin to tell you how grateful Will and I are for that. Please keep it coming!

I thought I’d share the table of contents, as it’s beginning to take a more concrete shape. I’ve also included the status of each chapter, so you can get a feel for how far along we are. Compare it to this article and any thoughts you’ve had, and let me know if you see anything missing.

Intro (open for review)

Walk through (wip)

Deep dives

Best Practices (first draft open for review)

Unit testing with Strange – wip

Platform-specific issues (TODO)

  • IL2CPP
  • iOS and Trampolines
  • Known unsupported platforms and why
  • Other?

As for the state of v1.0 itself, we’re honestly not moving forward as quickly as I’d like. Will and I have had some difficulty coordinating schedules. We need to review each other’s work, and firm up the release so you all can get some time with an RC before it goes live. Here’s our TODO list, along with the state of each item.

Best practices – Draft

These are my ideas so far around Best Practices for the v1.0 of the Big, Strange, How-To. Let me know what else we might want to say. What have I forgotten? What am I dead wrong about? Let’s work up a great list to help users get Stranger than ever.

My idea of a Strange Best Practice.

My idea of a Strange Best Practice.

General

“Render unto Unity that which is Unity’s”

What is the core purpose of Strange?

Dependency injection? That’s just one of many features. Decoupling? That’s simply a means to an end. No, the core purpose of Strange is to make your life easier. It’s a tool, like any tool. And like any tool it should be applied to the correct set of jobs. However much you like drills, you wouldn’t drive a nail with one. In the end, all the DI/IoC/Decoupling magic has to be judged against that standard. So after giving it a reasonable try, consider every recommendation, “rule”, and philosophical tenet here by evaluating exactly that. I already know the extreme value of what I’m advocating. It won’t hurt my feelings if you disagree (well, maybe a little).

Does the feature you’re working on fit well into Strange’s structure? If you’re trying to rethink physics into a Strange controller because that’s “proper” MVC, then I guarantee you’re doing it wrong. Unity already has a very nice physics system. Let it do its job. A third-party AI designed to be attached to a specific GameObject is more of a grey area. So ask yourself: is this likely to change? Is there a sensible way to decouple (perhaps apply the AI MonoBehaviour as a secondary Mediator)? If you can do these things, make it Strange. If you can’t, you have my permission to let it be.

Injection

Minimize injection at performance-critical moments

Strange is at its best for application-level architecture, and at its worst in your game loop. Supplying Mediators and injections to thousands of enemies at a performance critical moment would not be a very efficient use of resources. Be realistic about your performance requirements. If your game is entirely turn-based, maybe the performance issue is irrelevant to you. If you’re trying to create a massively multiplayer action game that runs on an older smartphone, make sure you think this through!

Wrap a third-party Singleton

Lots of very fine (and some not so fine) third-party libraries are written as Singletons. While we disagree with this choice architecturally, it’s a simple fact of the Unity world. If you need to use a third-party library written as a Singleton, simply wrap it in an interface that is useful to you. We provide instructions on exactly how to do this in the injection deep dive.

If you need named bindings, use supply-binding where possible.

As of v1.0, you can apply named bindings through inversion.

Signals/Commands

Models and services should never listen to Signals

When models and services listen to Signals, they make two critical errors. First, they become tightly coupled to the rules of the specific game/application, which limits portability. Second, they bypass Commands, which tends to result in models and services bloated with logic. Logic is for Commands. Models handle state. Services communicate outside the app.

Dispatching Signals (as opposed to listening) is a bit more of a gray area. It still limits portability, but there’s less of a tendency to bypass Command logic. Stylistically, some people prefer to make Commands completely stateless, so that they are never retained. I prefer the following pattern.

Use Promises in retained Commands

The most common reason for retaining a Command is that you are calling outside Unity, waiting for some response. The new Promises package makes this sort of callback much cleaner and lowers the number of dependencies. It also strengthens the argument for keeping Signals out of services and models altogether.

Consider the following Command:

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 result
        Release();
    }
}

What I like about this pattern is (a) it’s very clean, readable code, (b) your service needs no injected Signals, (c) any adapter logic (up, down, or both) gets handled in the same place.

Using clear naming conventions, match Signal names to Commands

Ideally, Signals and Commands should be named such that they obviously connect. Obviously, the entire point of decoupling them is to allow you not to do this. That doesn’t mean you need to set out to make things any harder than they have to be. Start things in alignment, and don’t lose sleep when design changes dictate that they drift.

Pool Commands when possible

Every object created and destroyed must be handled by garbage collection. Marking Commands as Pooled() eliminates some of this collection. Provided you are careful to clean up after yourself, it’s usually best to mark Commands this way. See the section on Command pooling for details.

Follow the single-responsibility principle in your Commands

Treat each Command like a method that does one thing. If a single Signal results in ten different things happening, ganging all that up into one Command makes that code complicated, non-portable and inflexible. On the other hand, if you break all those responsibilities down, it becomes much easier to reuse the bits that may apply to other Signals. You’ll get less code duplication and more reuse, and other programmers (including you in three months’ time) will be able to understand with greater ease what the hell you were trying to accomplish.

Avoid injecting into Views

This is definitely a best practice, not a requirement. When a View goes through the mediation process we explicitly check whether it needs injection. So why tell you not to do a thing that we explicitly allow and provide a mechanism for? This goes to a philosophy that I call “I’m not your mother”.

There are plausible reasons for injecting directly into Views: you might have a bit of decoupled code you want accessible by the View; you might not buy our argument about the value of mediation; perhaps you want to couple a model directly to a View for convenience. I might disagree with these choices (or maybe not, depending on circumstance), but the choice on how to use our tool is ultimately yours.

Now, why is it “best” not to do this? Read the mediation section in the deep dive: keeping your Views as pure Unity probably serves you best most of the time.

“Gang up” a View into a useful component

We often observe that new users misconstrue the purpose of mediation, thinking that each GameObject, each button, each line of text must be its own View with a corresponding Mediator. This is manifestly incorrect. The point of mediation is to allow you a clean separation between the View and the app…nothing in that specifies a 1:1 control:View relationship. Create useful components, small or large, that meet your needs, and mediate those. With UI, I often find that this correlates to 1 screen = 1 View.

Keep Mediators thin

Mediators aren’t intended to do the work of the View. Nor are they intended to provide (much) logic. The sole role of the Mediator is to adapt between View and application. Keep it thin.

Consider using multiple Mediators

It is commonly assumed that each View needs only one Mediator. This is usually sufficient, but there are excellent cases for applying multiple Mediators. My favorite is for analytics. Rather than mixing up your analytics logic (was this button clicked? how many times? before or after the user did this other thing?) with either View or Mediator, consider adding an extra Mediator solely for the purpose of listening out for button clicks and the like. This can make the agonizing process of instrumenting your game clean and trivial.

Contexts

Use clear naming conventions plus implicit bindings to keep Contexts clean

In even a moderately complex application, your Context can start to look like a very long shopping list. We find that many bindings start to crystallize as development proceeds. Rather than enumerate the blindingly obvious, we recommend using Strange’s implicit binding feature to keep your Context spare. Implicit bindings are always overridden by explicit bindings, so you can make changes when special cases arise.

Part of the trick to keeping this easy, especially in large teams, is to maintain sensible naming conventions so you can intuit the most likely implementing class.

//Sensible naming convention
public class PlayerModel : IPlayerModel

//Less sensible naming convention
public class PlayerModel : IPlayer

//Full-on insanity naming convention
public class DefaultPlayerModel : IShip

Build platform variants at the Class level; put all platform-dependent statements in the Context

Have you ever waded through code like this?

public class FaceRegognizer {
 void Start () {


    #if UNITY_EDITOR
     Debug.Log("Doing a thing in Unity Editor");
    #elif UNITY_IPHONE
     Debug.Log("Doing a thing on Iphone");
    #elif UNITY_STANDALONE_OSX
    Debug.Log("Doing a thing on Stand Alone OSX");
    #else UNITY_STANDALONE_WIN
     Debug.Log("Doing a thing on Stand Alone Windows");
    #endif
 }        
}

And let’s be honest: it’s NEVER that clean. Instead of having this code mixed-in and littered throughout your code, we recommend sectioning off all platform-specific behavior into well-named classes. You’ll still have all that #if…#elif magic, but it’ll all be in one place, and each implementing class will tell a consistent, readable story for its use case.

//All common capabilities in an abstract class
abstract public class AbstractFaceRecognizer : IFaceRecognizer{}

//Each of these implements the functionality as required by the platform
public class DefaultFaceRecognizer : AbstractFaceRecognizer{}
public class IosFaceRecognizer : AbstractFaceRecognizer{}
public class WindowsFaceRecognizer : AbstractFaceRecognizer{}
public class OSXFaceRecognizer : AbstractFaceRecognizer{}

//Now bind with all the #iffyness
#if UNITY_EDITOR
injectionBinder.Bind<IFaceRecognizer>().To<DefaultFaceRecognizer>().ToSingleton();
#elif UNITY_IPHONE
injectionBinder.Bind<IFaceRecognizer>().To<IosFaceRecognizer>().ToSingleton();
#elif UNITY_STANDALONE_OSX
injectionBinder.Bind<IFaceRecognizer>().To<OSXFaceRecognizer>().ToSingleton();
#else UNITY_STANDALONE_WIN
injectionBinder.Bind<IFaceRecognizer>().To<WindowsFaceRecognizer>().ToSingleton();
#endif

Stick to a strict, Context-based hierarchy

As we explained in the Mediation deep-dive, the Context-based hierarchy — i.e., childing a GameObject to a chain that can “bubble up” to a ContextView — is only required in a multi-Context situation. That said, starting this way, even in a single-Context situation, gives you the flexibility to choose the multi-Context approach at a later time.

Build modularity using multiple scenes, each in its own Context

One of Strange’s superpowers is connecting multiple Contexts. We often talk about it as a special use-case, but the utility of this concept shouldn’t be underestimated, especially when working in teams. This basically brings decoupling to the macro level, since one person/team can work on one chunk of a game, completely abstracted from others. A scene can be a mini-game, level, store, UI screen, what-have-you, built to stand all on its own, yet able to be integrated into the larger whole when necessary. This can greatly speed up workflow and even make it possible to share whole sections of a project between multiple games. I mean, seriously, once you’ve created an in-game store for Age of Jellyfish, do you really want to build it again for Age of Anchovies?

Inching towards v1.0

This is just a quick update to let you know we haven’t been entirely idle. Progress on V1 .0 continues on two fronts:

  • Preparing the release candidate
  • Writing sections of the new Big Strange How-To

Will and I have been discussing the fastest route towards getting a release candidate to you so y’all can start playing with it. We apologize that this is taking longer than we anticipated. Some of this boils down to our work for Unity: there’s quite a lot of urgency around the release of 5.1, and even 5.2 behind that.

As to my work on the BSHT, I have partial (almost complete) chapters on injection, mediation, reflection, signals, and commands. I also have a great deal of the walk-through complete (I write a lot via dictation as I walk to and from work, as I’m doing now). In each case, there are some details that require investigation before I’m ready to put these chapters out for review.

Apologies for the delay. Rest assured we are as eager as anyone to get the new version shipped.

One Strange Week in Spain

will_aurimas_marc

Let’s start with what this article will not be about. Dependency injection will not be a native feature in Unity. Not, at least, for the foreseeable future.

But for one exciting week, it was.

A question I got more than once when I joined Unity was “will Strange become a part of Unity?” I answered, “No, Unity are hiring me. Not buying Strange.” Nevertheless, the idea of integrating certain features of Strange  directly into Unity has never been far from my mind.

Last week, Unity engineers from all over the world met up in Malaga, Spain for a big hackweek: one hundred and fifty engineers, all brainstorming and blue-skying projects they thought might be fun or useful for the company and/or community.  And a mighty assembly of ideas it was.

Among these brave souls, our friend Will Corwin proposed the integration of dependency injection directly into Unity as a native feature. Obviously, this was something I couldn’t pass up. Together with colleague Aurimas Cernius, we leapt in and made it so.

Our goals:

  • Create a simple, easy-to-use DI system
  • Explain the value of DI to hackweek participants

We were not attempting to make Strange a native feature. The MVC construct on which Strange is based is a useful application paradigm, but it’s certainly not the only one. None of us thought that the larger framework was appropriate as a native feature. What we did (and do) regard as appropriate, was the injection feature itself. To do this we needed the following pieces:

  • The injection system, obviously
  • The reflection system, for efficient caching
  • A context, for writing bindings

We started by copying the appropriate packages from Strange, stripping out anything that wasn’t useful to our case. Mostly this meant simplifying the Context.

One of the cool things about adding injection directly to Unity is the ability to ditch some of the shoehorned functionality Strange copes with on startup. UnityEngine.Injection, as our system came to be, had C++ hooks to kick off certain processes, making those early milliseconds cleaner and more reliable.

It all started with this player setting.

Use_DI

With this Boolean switched on, the DI system went to work, searching for a Context marked with the [BindingContext] attribute. This meant that a ContextView in our system was optional. Sure, you’d want one to mark out sub-contexts, but a viewless Context is probably a better choice for your first Context, which shouldn’t have to be tied to a view in any way, and shouldn’t be destroyed if your scene changes (we’ve even thought of implementing this idea in Strange itself).

Of course we have our familiar [Inject] and [PostConstruct] tags. The only other place where our injection system touches the developer is in MonoBehaviours. Aurimas wrote this native hook:

[InjectDependencies]
public class SomeClass : MonoBehaviour {
    [Inject]
    public ISomeService YouKnowTheDrill { get; set; }
}

Any MonoBehaviour so marked seeks out and finds the correct Context, based on the same set of rules Strange uses. The results of these simple changes were pretty cool.

  • A developer can start playing with DI with as little as a button click and about 5 lines of code (An Inject tag and a simple Context). Compare that with what it currently takes to get into Strange for the first time.
  • MonoBehaviours can request injection directly. They don’t need to extend View.
  • Strange (or other IoC systems) could be layered on top of this system.
  • A colleague pointed out that resolving bindings should really be a compile-time operation, not runtime. We agree. That could potentially be fixed by internalizing DI.

We had most of the functionality working by Wednesday morning, so we had accomplished our first goal. But for the second goal — explaining the value — we didn’t yet feel like we had an ideal presentation. Fortunately, inspiration struck late Wednesday: we quickly re-tooled a one player game to two player and wired it up with a real-time server.

Actually, we used not one real time server but two! We leveraged an experimental server written by another hackweek team, then showed how using DI bindings we could instantly swap between the experimental one and UNet.

The video below (no audio) shows our presentation “slides” along with some side-by-side video of the game running with the experimental server.

[BindingContext]
public class MyGameContext : Context
{
  protected override void mapBindings()
  {
    InjectionBinder.Bind<GameManager>().ToSingleton();
    InjectionBinder.Bind<IPlayer>().To<PlayerModel>().ToSingleton();
    InjectionBinder.Bind<IDispatcher>().To<Dispatcher>().ToSingleton();
    //InjectionBinder.Bind<IRealtimeServer>().To<NullServer>().ToSingleton();
    InjectionBinder.Bind<IRealtimeServer>().To<UnetServer>().ToSingleton();
    //InjectionBinder.Bind<IRealtimeServer>().To<CloudCodeServer>().ToSingleton();
  }

  protected override void postBindings ()
  {
    InjectionBinder.GetInstance<GameManager>();
  }
}

This was a fun project. It led us to consider more deeply than we ever had before what it would mean to integrate DI directly into Unity. As I said at the top, this isn’t something we see being implemented in real product anytime soon, but we made more folks within Unity aware of what we do and why. We met some great people, heard about some amazing ideas, and started some conversations that may someday bear fruit.

Babel Naming

Journey From BabelThis just tickled my funny bone, and I thought I’d share. As I’m working on the documentation for the next version of Strange, I thought I’d go through some of my early notes, looking for ideas. And I stumbled across this blast from the past.

The development codename for what eventually became Strange was Babel. As the framework was nearing completion — and we knew we were going to open-source it — we decided we needed a cool name to get it noticed, so we threw together a brainstorming document. Submitted for your amusement, here are all the Stranges that could-have-been…


Babel is the working title for the framework I’ve been building. We’re looking for a name. Feel free to add ideas.

Things to consider

  1. At its heart, Babel is not an injection library. It’s a binding framework. The most important thing Babel does is bind something to something else. One (very important) application of that binding is dependency injection.
  2. Consideration #1 might not matter.
  3. It might be nice to use our initials, TM, to reflect back upon us.*
  4. Consideration #3 might be unnecessary.
  5. Babel is lightweight and modular, something that appeals to developers.
  6. Babel is written for C# and Unity, and will be (so far as we know) the first “serious” attempt to provide a Inversion-of-Control/Dependency Injection framework for this purpose.
  7. If you care, you can see the names of some IoC/DI libraries here.

Name ideas (feel free to add)

  • TieFighter
  • TinMan
  • ThinMan
  • TinType
  • Babel
  • Babylon
  • Unification
  • UncleBob (a reference to the guy who devised the Dependency Inversion Principle)
  • Stingray
    • Ampule
  • IssacNewtonsBinding or the bindingofIssac
    • FirstMotion
    • Newton
  • Boson – “the ‘glue’ that holds matter together”
    • Higgs
    • DarkMatter
  • Fondant (UK: /ˈfɒndənt/, US: /ˈfɑndənt/ or /ˈfɑndɑnt/, from the French: /fɔ̃.dɑ̃/) is one of several kinds of icing-like substances used to decorate or sculpt pastries.
  • Agar or agar-agar is a gelatinous substance derived by boiling[1] a polysaccharide in red algae, where it accumulates in the cell walls of agarophyte and serves as the primary structural support for the algae’s cell walls
  • A carboy (or demijohn) is a rigid container with a typical capacity of 20 to 60 L (5 to 15 gallons).[1] Carboys are primarily used for transporting fluids, often water or chemicals.[2] (as cider maker, I just find these to be funny words)
  • Strange – A strange attractor generates predictable patterns, often in the scope of a chaotic system.
  • Gloo
    • Glue
    • BluTac (thinking of the virtue of sticking things together, but not permanently)
    • Paste / LibraryPaste / PasteLibrary / PasteBoard
    • Duct tape
  • Vulcan MindMeld
    • My mind to your mind
    • Sneaky sci-fi references
      • Liberator
      • SonicScrewdriver
      • Tanstaafl – see here, particularly in relation to Newton’s Second Law of Thermodynamics
      • Klaatu
      • Illudium
      • Tholian (web)
      • Federation
  • Octopus
    • Tentacles
    • TentacleMotion

* The “Us” in this context was ThirdMotion, the company responsible for me bringing Strange to you.

It’s Big, It’s Strange, and I’m Rewriting It

[EDIT]First draft of Introduction is now open for comment[/EDIT]
[EDIT2]The revised architecture diagram is now open for comment[/EDIT2]

Gentlemen, you can't fight in here! This is the War Room!

The Big, Strange How-To has been the standard (and, er, only) textbook on Strange since its inception. But with the exception of a handful of corrections and the addition of a couple of new features, it has remained largely unchanged since it was first written way back alongside v0.5. With the upcoming release of v1.0, I reckon that it’s high time for a proper update.

With the benefit of hindsight and whisky, I’m looking at everything in the BSHT to see what needs updating, adding, or even removing. And that’s where you come in, my friends!

What could we explain better? What has frustrated you most, especially when you were first learning? I especially want to concentrate on the new user: what can we do to flatten the steepness of our learning curve?

Here are my ideas so far. Please leave comments below and I’ll keep this post updated with your input.

Things to add to the Big Strange How To

Re-work the Introduction

New section: opening Strange for the first time (walk-through)

  • Explain the broad structure of the repo.
  • Walk-through of MyFirstProject project
  • Walk-through of MultipleContexts project

Updated section: Signals

  • Beef up the Signals section.
  • Add explanation for the (new to v1.0) ListensTo feature.
  • Change all examples (across all of BSHT) from EventDispatcher to Signals.

Updated section: Mapping across Contexts

This section is really thin. Let’s clarify the concept and the execution. Particularly, explain the reasoning behind multiple Contexts, along with practical info on how to structure them.

Updated section: Reflection

I don’t want to confuse a new user with too much about this…but then the understanding the principles is important.

New section: Pools

Explain how the Pools extension works

New section: Promises

Explain the (new to v1.0) Promises package

New section: Implicit Bindings

Explain the ImplicitBind package

New section: runtime bindings

Explain the (new to v1.0) feature runtime bindings

New mini-section: Strange for extending Unity

A mini-section because it will essentially just link to a separate document specifically about using the (new to v1.0) Editor extension. The current plan is for the Editor extension to live outside the main Strange repo as an optional plug-in.

New section: Testing tutorial

Explain how to run unit tests and write your own.

Enumerate Exceptions for each package

In each package, list and explain each of the thrown errors. In an appendix at the end of the document, put all Exceptions in one place for easy reference.

Replace artwork

All that pesky text art (—–>). Let’s grow up and use PNGs or SVGs or something.

Tutorial

Lots of people asking for something more like a step-by-step tutorial. Particularly questions about uGUI. Should this be here or a separate document?

New Section: Platform Specific Issues

A request in the comments to explain iOS trampolines. Compile a set of other platform-specific gotchas?

New Section: Best Practices

Some cohesive section on Dos/Don’ts when using Strange.

Errata

Add named injection for constructors

How this will work

I’ll going to create the new BSHT as a Google Doc at first. I’ll edit this post and provide a link so everyone can weigh in. In the meantime, feel free to leave comments and ideas.

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!