This is the third post in a series on the architecture of mobile applications. In the first post we looked at the classical architecture of mobile apps that evolved from web apps. In the second post we looked at event driven architecture and when it should be used. Now we're going to dive a little deeper into event driven architectures and in particular talk about some of the significant design decisions that must be made and the pitfalls that need to be avoided.
So you say you want an event driven architecture? I'll assume you've done your homework and aren't just doing this to because it seems like the cool thing to do. I'll assume that it really fits your application. One of the first things that you will realize as you get started is that event driven architecture does not exempt you from many important aspects. Security is a great example. You must figure out how you will authenticate with your server and how to secure any sensitive information that you send over the wire. Just because you are no longer in the world of HTTP and HTTPS does not mean that you get to send over people's credit card numbers in plain text. It's not any harder to sniff your bits and chances are that you are just as vulnerable to things like man-in-the-middle attacks. So go read up on things like TCP headers and TLS.
Once the basics are in place, you can think more about the architecture of your application. Your servers are going to be sending events to your application. So what is going to receive them? Do you have each UI (controller, Activity, etc.) receive them? How about something that is more long-lived. The most important thing to remember is that whatever receives events generally has to be able to deal with any kind of event. You can never assume that just because your controller only cares about some small set of events that those will be the only events that it ever receives. Thus you probably need to have an event receiver whose lifecyle extends beyond that of any given screen in your application and can handle any and all events. Now keep in mind that it will often delegate events to other components in your application, so no need to worry about this global receiver being stuffed with knowledge of your app. On Android you could use a Service for this or even a subclass of Application. You could also create some other singleton object that is tied to your application's lifecycle.
Now you might ask does this really need to be a singleton? Not necessarily. However I think that in many (most?) circumstances that a singleton will simplify things for you. What happens to those events that are not needed by the UI? Such events probably mutate some internal state of your application. If that internal state is transient, then it probably makes sense for there to be only one copy of it. If it is persistent...
Inevitably there will be some events coming in from your server that you do care about at the UI level. These things will probably be "second-hand", i.e. the events will have been received by the longer-lived object we talked about above. Now you need to deal with how to get these events to the UI. The most accepted way to do this is to use an Observer pattern. You define an interface for an object that cares about a certain event (or certain set of related events potentially.) Then the object registers itself with the central receiver. When a new event comes in from the server, the central receiver examines it and decides on who to delegate it to.
I must add a few words of caution here. For each event you can easily wind up with a class for the event's data structure, an interface for the observer, and an implementation of the observer. The last of these things is often handled by having the Activity/Fragment/controller implement the interface, or by using an anonymous inner class to implement it. In any case, you wind up with multiple types being defined for each event. So if you have many types of events that your server will push to your application then you can end up with an explosion of code. Android developers should consider using Handlers and Messages as a leaner, more de-coupled solution. The big downside is that you may windup doing manual type checking and casting. This can be avoided by late binding, i.e. keep the data from the server raw as long as possible and do the parsing after the dispatch to the observer.
Finally I will close this long series of posts with a brief word about server side technologies. This post in particular has focussed on how to write your mobile/client applications with an event driven architecture. There is a flip-side to this and that is how to implement an event driven architecture on your server. Just like in our classical architectures, most servers are dominated by HTTP. That is not only the default interface into them, but it is at the heart of the server's architecture. A connection is a short-lived, usually stateless object. There is generally a one-to-one mapping of HTTP requests to either threads or processes. This is a poor fit for event driven architectures where a connection is extremely long lived. It only dies when the client app dies or explicitly closes it for some reason.
Fortunately there are numerous server side technologies that do not use the request-per-thread/process model. Certainly the most hyped one of these is Node.js. The Internet is chock full of benchmarks showing how Node's non-blocking out-scales Apache, Nginx, etc. However there are numerous other event driven app servers in Python, Java, Ruby, etc. Personally I have a bias towards my ex-colleague Jamie Turner's Diesel framework. The point is that there are many choices on the server and I expect that you will see many more moving forward.
I must add a few words of caution here. For each event you can easily wind up with a class for the event's data structure, an interface for the observer, and an implementation of the observer. The last of these things is often handled by having the Activity/Fragment/controller implement the interface, or by using an anonymous inner class to implement it. In any case, you wind up with multiple types being defined for each event. So if you have many types of events that your server will push to your application then you can end up with an explosion of code. Android developers should consider using Handlers and Messages as a leaner, more de-coupled solution. The big downside is that you may windup doing manual type checking and casting. This can be avoided by late binding, i.e. keep the data from the server raw as long as possible and do the parsing after the dispatch to the observer.
Finally I will close this long series of posts with a brief word about server side technologies. This post in particular has focussed on how to write your mobile/client applications with an event driven architecture. There is a flip-side to this and that is how to implement an event driven architecture on your server. Just like in our classical architectures, most servers are dominated by HTTP. That is not only the default interface into them, but it is at the heart of the server's architecture. A connection is a short-lived, usually stateless object. There is generally a one-to-one mapping of HTTP requests to either threads or processes. This is a poor fit for event driven architectures where a connection is extremely long lived. It only dies when the client app dies or explicitly closes it for some reason.
Fortunately there are numerous server side technologies that do not use the request-per-thread/process model. Certainly the most hyped one of these is Node.js. The Internet is chock full of benchmarks showing how Node's non-blocking out-scales Apache, Nginx, etc. However there are numerous other event driven app servers in Python, Java, Ruby, etc. Personally I have a bias towards my ex-colleague Jamie Turner's Diesel framework. The point is that there are many choices on the server and I expect that you will see many more moving forward.