Let’s show you the goods before you read how I achieved it. I present my first attempt at continuous client in the form of a video player that allows user experience transitions to cross between a Windows Phone 7 device, an iPhone and a Silverlight web player.
Is that not crazy awesome? I was amazed at how simple it was. Below is how I did it. I can’t wait to work on a more elaborate demo. Stay tuned! Follow my Twitter and this blog.
How I got to this point
My experiments in continuous client architecture has started to gain a lot of traction since I have been tweeting and creating working code and videos. My user experience rant on the potential of continuous client has spanned almost a calendar year now and for the people just following along recently based on my last video I’d like to recap a bit of history.
In July 2010 I posted my thoughts of how I thought the cloud plays a key role in continuous client. The cloud helps bridge the gap between cloud hosted code and on-premise hosted code. On-premise in the case of continuous client is devices such as PC’s, tablets, smart phones and any other device. At the time I wasn’t exactly sure of a way to implement it architecturally without introducing large amounts of complexity and synchronization code.
In the last 5 months I’ve been researching and learning enterprise integration patterns and a pattern called CQRS. Fast forward to a month ago (May 2011) and the stars seemed to align in my head one day. I wrote a post about combining some principals of both which helps us build an architecture that allows us to fairly easily implement some continuous client experiences. It dawned on me that the challenge is really an integration issue.
How did I build it
Enterprise integration patterns brings the value of integrating multiple apps, services and devices through messaging patterns. CQRS gives us the value of building an event driven architecture centered around our state changes. In CQRS the domain mutations only occur as a result of an event being handled. This allows you to support event sourcing where you can get replay ability. In this case we aren’t so much worried about a domain but the user experience state.
Let’s put these together to enable continuous client:
- Every user interaction generates an event. The application handles the event and mutates internal state.
- The event gets sent as a message to a service bus hosted in the cloud with a copy per device we want the user experience to be capable of transitioning to.
- The cloud hosted service bus enqueues these messages in a separate queue per device. This allows for each device to event source what happened on the other devices.
It would look something like this:
This gives us a system where event sourcing is essentially automating the user experience and since our application code is developed to handle events natively it operates the same. Another key thing to note is that the cloud infrastructure is holding the queue of events. Devices don’t have to be running the application to take part in the state transitions. Reliable messaging allows us to consume these messages whenever the application starts up.
To prove this out I developed a video player demo as my first attempt at continuous client. The video player has 2 basic functions which are play and pause. I created 2 port’s. One for Windows Phone 7 and Silverlight and my friend Martin Pilkington helped with the iOS iPhone port (thanks Martin!).
We utilized the new Azure Service Bus cloud platform for the messaging infrastructure. The upcoming Azure Service Bus platform has support for topics. I used a topic per user and separate subscription per device. This gives a queue per device, each having their own copy of the messages pushed into the topic. Filtering based on device id was used so that a device would only get messages generated by other devices and not self-generated messages.
In a weekend I had my first continuous client demo working. Most of that time was spent learning Azure Service Bus and writing ports. The actual application code was very simple and I used the Greg Young’s CQRS sample as a reference point.
Show us the code
One thing to keep in mind here in the Windows Phone 7 and Silverlight code is I did not implement this using the MVVM pattern. I’m a fan of MVVM but the purpose is to keep the sample code as simple as possible. Implementing this in MVVM doesn’t change a whole lot.
Here is the WP7 and Silverlight web application code. It is exactly the same and shared between both:
|1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113||
Notice here when the interaction event occurs all we do is fire an event. This event is self handled. The events published to the EventAggregator get sent to Azure Service Bus so that all messages are delivered to the topic which each device subscribes to.
I am receiving messages from Azure Service Bus over HTTP. I serialize messages as JSON and when a new message is received we deserialize the JSON into the message type and pump them through the EventAggregator.
|1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18||
Since a user interaction is publishing a message to the EventAggregator and our Azure Service Bus topic subscription is also publishing to the EventAggregator our application code is now architected to be natively event driven and our application code has no concept of the source of the event.
Messages have an id that is canonical so that it is not specific to any platform. I chose to use a URI format such as http://kellabyte.com/samples/VideoDemo/Messages/PlayMessage and we use a MessageMapper to get the app specific type that message relates to for deserialization purposes since we can’t share types across platforms who don’t share languages. This could probably be done cleaner, I didn’t spend much time here since it wasn’t the primary focus of the sample.
I’m not covering all the Azure Service Bus code in this post there is already a lot of content out there for Azure. If you feel I should blog about it I can do a specific post for that, let me know!
It’s really very simple and straight forward. As long as you adhere to the rules your application operates the exact same whether it is interactions as a result of a user action or event sourced from the cloud.
Here’s Martin’s Objective-C iOS application code for the iPhone:
|1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149||
Keep an eye out because I will be working on a more elaborate continuous client sample! I’ve begun work on a mobile RSS reader so that I can prove that the architecture shown here can carry over to all kinds of applications while enabling all sorts of user experience transitions.
If you would like to help port it to a specific platform and work with me on the continuous client concepts feel free to contact me on Twitter
Shout out to Martin Pilkington for working on the iOS port in parallel with me and the Azure Service Bus team (Clemens Vasters and Will Perry) for answering my questions on Twitter and logging some bugs that I encountered. I really enjoyed working with Azure Service Bus. It’s very easy and handy to use on multiple platforms.
I’m excited about this progress. Stay tuned for more continuous client!
- Mencius and Fast Mencius a high performance replicated state machine for WANs
- Tuning Paxos for high-throughput with batching and pipelining
- Scalable Eventually Consistent Counters
- Create benchmarks and results that have value
- Routing aware master elections
- My new test lab
- Responsible benchmarking
- Understanding hardware still matters in the cloud
- The “network partitions are rare” fallacy
- Messaging and event sourcing
- Further reducing memory allocations and use of string functions in Haywire
- HTTP response caching in Haywire
- Atomic sector writes and misdirected writes
- How memory mapped files, filesystems and cloud storage works
- Hello haywire
- Active Anti-Entropy
- Lightning Memory-Mapped Database
- Write amplification
- Amortizing de-duplication at read time instead of write time
- LevelDB was designed for mobile devices
- March 2014
- February 2014
- January 2014
- November 2013
- October 2013
- August 2013
- July 2013
- June 2013
- May 2013
- April 2013
- March 2013
- January 2013
- October 2012
- September 2012
- August 2012
- May 2012
- April 2012
- February 2012
- January 2012
- December 2011
- September 2011
- July 2011
- June 2011
- May 2011
- April 2011
- March 2011
- February 2011
- December 2010
- November 2010
- October 2010
- September 2010
- August 2010
- July 2010
- June 2010
- May 2010