views:

197

answers:

5

I think that you have heard of message/event buses, it's the single place when all events in the system flow. Similar architectures are found in computer's motherboards and LAN networks. It's a good approach for motherboards and networks as it reduces the number of wires, but is it good for software development? We don't have such restrictions as electronics does.

The simplest implementation of message bus/event bus can be like:

class EventBus {
    void addListener(EventBusListener l}{...}
    void fireEvent(Event e) {...}
}

Posting events is done with bus.fireEvent(event), receiving messages is enabled by bus.addListener(listener). Such architectures are sometimes used for software development, for example MVP4G implements similar message bus for GWT, read:

It's just the popular Observer (Listener) pattern made 'globally' - each object in the system can listen to each message, and I think it's bad, it breaks the Encapsulation principle (each object knows about everything) and Single Responsibility principle (eg when some object needs to a new type of message, event bus often needs to be changed for example to add a new Listener class or a new method in the Listener class).

For these reasons I think, that for most software, Observer pattern is better than event bus. What do you think about event bus, does it make any good sense for typical applications?

EDIT: I'm not talking about 'big' enterprise solutions like ESB - they can be useful (what's more ESB offers much, much more than just an event bus). I'm asking about usefulness of using message bus in 'regular' Java code for object-to-object connection - some people do it, check the links above. Event bus is probably best solution for telephone-to-telephone communication or computer-to-computer communication because each telefone (or computer) in a network can typically talk to each other, and bus reduces the number of wires. But objects rarely talk to each other - how many collaborators one object can have - 3, 5?

+2  A: 

Some people like it because it is the embodiment of the Facade or Mediator pattern. It centralizes cross-cutting activities like logging, alerting, monitoring, security, etc.

Some people don't like it because it is often a Singleton point of failure. Everything has to know about it.

duffymo
The event bus concept is implemented in Server Side ajax.
Suresh S
Not always. I've seen it in pure Java.
duffymo
@SureshFor centralizing cross-cutting activities aspect-oriented programming is invented. It's typically much easier and powerful.
iirekm
@iirekm i was telling were it is used.
Suresh S
@Suresh, there is not one single way to implement a message bus.
matt b
Sorry, the word about AOP wasn't to you but to duffymo, I mislooked user name.
iirekm
No, AOP distributes them to the components that own them. It's the opposite of a centralized enterprise service bus. I agree that it might be a better approach, but the word "centralized" is misplaced in my opinion.
duffymo
With advanced AOP solutions (like AspectJ) I can control or change behaviour of any class loaded into JVM. It is centralized - I can do it from just one aspect (from one *.aj or *.java file). The examples you mentioned (logging, alerting, monitoring, security) are the major examples for using AOP.Most 'extensibility' problems can be solved with good AOP tool (of course Strategy or Observer patterns can be better in many cases). But bus? Doesn't offer anything better than strategy+observer+AOP.
iirekm
"It is centralized" - not if it's associated with distributed components it's not. Yuu'd have to configure aspects for each component, which may be deployed on different servers. Don't get me wrong - I like the AOP solution. I'm not a defender of centralized buses. But your way *is* different, and I'm trying to highlight what the difference is.
duffymo
A: 

A good analogy is that of a telephone exchange, where every handset can dial to every other handset. A compromised handset can tune into other conversations. Program control flows like wires(cyclomatic complexity anyone!) This is similar to the requirement of having a connection/physical medium between two end points. This is So for N handsets instead of having NC2 (Combinatorial logic) flows for every new handset we tend to get N flows.

A reduction in complexity implies easy to understand code. Lets start with the prominent points you have highlighted: 1. Global knowledge 2. Intrusive modifications.

Global Knowledge: Consider message event to be an envelop. From event handler/sender perspective there is no data being exposed, it is seeing an envelop (unless an derived class tries to do some inspection using 'instanceof' checks). In a good OOP design, this would never occur.

Intrusive modifications: Instead of having a event specific listener approach, one can use a global event handling approach. As such we have a global event type (on which data is piggy backed and down-casted). This is much like the PropertyBeanSupport model in Java. With a single event type we are required to have a single sender and listener types. This implies you need not modify the bus/listeners every time you see something new. The ugly down-casting can be soothened using Adapter pattern (Please don't start that another level of redirection quote!). Programmers can write assembly in any language. So need for commonsense and smartness can not be substituted. All I intend to state is it can be a effective tool.

The actual event receivers can use the listeners (composition/proxy) easily. In such a Java code base, listeners would look like stand alone inner class declarations (with unused warning being flagged in certain IDEs). This is akeen to two players on the beach playing a ball game, the players don't react until they see the ball.

'@duffymo' points out another interesting aspect: 'Single point of failure'. This would/can in theory effect any object residing in memory(RAM) and not specific to MessageHandlers.

questzen
I guess that we are speaking about 2 different kinds of message buses: buses with lots of message types and buses with few message types, but general ones (your analogy with envelope) - no data exposed, but in order to extract this data, the class that knows how to do extract it needs to use ugly instanceof, casts etc; some solution to the instanceof problem is Visitor pattern, but with it we get back to one big class which knows about all types of messages (you have to add all visitXXXX methods to the Visitor)So with event bus you have either to use instanceof or big listener classes. Bad
iirekm
As for your analogy with ball, that 'the players don't react until they see the ball' - the same is true for event bus: all players must see event bus in order to communicate. Every nontrivial application has thousands or millions of objects in memory. How many people can play football - typically it's 11, but I think that even this is too many. Can you image 1000 people playing football at the same time in the same football field? That would be quite interesting :-)
iirekm
@iirekm, In the code base I use, the global event looks like this MessageEvent event = new MessageEvent("EventId",oldValue, newValue). The actual constuctore def: MessageEvent(String id,IAdapter oldValue, IAdapter newValue). So to extract the new value all i need to do is MyObject value = event.getNewValue(MyObject.class). No big listener!
questzen
@iirekm, regarding the issue of ball game. An application with 1000 control flows is even more scary! To achieve 1000 flows, Nc2 == 1000, the value of N=45 (45*44/2 == 990). All you need to have is 45 objects each aware of each other to achieve this complexity. However with an Event bus, the same is achieved using 1000 flows (assuming every event sender and listener implicitly knows the message exchange). So which one would you prefer :). 1000 players on the field is a good one, a better one would be rushhour traffic on the road. (Road being the message bus)
questzen
@questzen - which object in any real application communitates with each other. When object communicate with each other (like each telephone can call each other telephone) then yes, message bus is the wisest solution - reduces amount of wires. In programming most objects talk to no more than (let's say) 3 other objects. In telephony or ESB we need anyone-to-anyone communication, in programming its rarely needed.
iirekm
+2  A: 

I'm having trouble understanding what you're really asking in your question. You give an example of a simple event bus which is actually just Observable with a different name, then you say;

For these reasons I think, that for most software, Observer pattern is better than event bus. What do you think about event bus, does it make any good sense for typical applications?

..but given your example, they are the same. This makes me wonder if you have ever used something like a Enterprise Service Bus. At a base level an ESB logically does the same thing as the observer pattern, but commercial products add much, much more. Its like an event bus on steroids. They are complicated software products and offer;

Message pickup
Generate events by listening to various endpoints. The endpoint can be a listener (such as a HTTP server), a messaging system (such as JMS), a database or pretty much anything else you want.

Message routing
Take your event and send it to one/many endpoint. Routing can be pretty smart, the bus might route the message depending on the message type, the message contents or any other criteria. Routing can be intelligent and dynamic.

Message Transformation
Transforms your message into another format, this can be as simnple as from XML to JSON or from a row on a database table to a HTTP request. Transformation can occur within the data itself, for example swapping date formats.

Data Enrichment
Adds or modifies data in your message by calling services along the way. For example if a message has a postcode in it the bus might use a postcode lookup service to add in address data.

..and lots, lots more. When you start looking into the details you can really start to see why people use these things.

Qwerky
I'm not talking about "big" message buses like ESB - they can be useful in big enterprises. I'm talking about using similar approaches in application architectures - some people do it for 'regular' programming, for example read this: http://code.google.com/p/mvp4g/wiki/EventBus
iirekm
+1  A: 

I use it heavily in JavaScript. There can be so many various widgets that all need to do some sort of action whenever something else happens -- there is no real hierarchy of ownership of objects. Instead of passing references of every object to every object, or just making every object global, when something significant happens inside a particular widget, I can just publish "/thisWidget/somethingHappened" -- instead of filling that widget with all kinds of code specific to the API of other widgets. The I have a single class that contains all the "wiring", or "plubming" as they like to call it in the Java Spring framework. This class contains references to all of my widgets, and has all of the code for what happens after each various event fires.

It is centralized, easy to access and maintain, and if one thing changes or I want a new process to occur on a specific event, I don't have to search through every single class/object/widget to try to find out where something is being handled. I can just go to my "operator" class -- the one that handles all the "wiring" when a particular event happens, and see every repercussion of that event. In this system, every individual widget is completely API agnostic of the other widgets. It simply publishes what has happened to it or what it is doing.

Bal
Controlling everything in one place isn't always good, technically speaking it breaks Single Responsibility Principle. For smaller applications such breaking doesn't make problems, but for big appz it IS a problem.Take EJB or Spring for example. In first versions of them all their configuration was stored in XML files, which were quite huge for big applications, in fact they were most often changed files in bigger applications.So newer versions of Spring or EJB seem to favour annotations over XML. Annotations are added 'locally' on classes, just like xxxx.addListener() is called 'locally'.
iirekm
@iirekm "in fact they were most often changed files in bigger applications" - do you have a source for that?
Nicholas White
@iirekm - I can see what you mean for large, enterprise level applications. I actually found this pattern emerge after a couple of years of development - I used the pub/sub system for certain things out of necessity, then it grew, and next thing I knew I found it much cleaner and much easier to maintain... for my JavaScript (Dojo) code. Now I develop all of my client-side web apps this way from the start. I find it very clean and very easy to maintain. I haven't used Spring in quite a while and didn't know they moved away from using the XML file to take care of the "plumbing".
Bal
@Nicholas: practical experience; big applications have lots of Spring (or EJB, or JSF, ...) beans, if we use XML for configuring them, whenever you add, remove or change a bean, you have to reflect that change in XML. Beans are being constantly added/removed/changed in a growing project, so this XML is also changed, grows, and is often a subject of SVN/CVS conflicts. The same is true for event bus: if it contains lots of events (like suggested by eg MVP4G), it can grow and grow. You can divide event bus to smaller buses to avoid this problem, but this leads to normal Observer pattern.
iirekm
@iirekm: I'm confused. It seems like you're just against it and have your mind made up, which is fine, but I don't understand your stance exactly. Qwerky stated that they are very useful for bigger applications and you said you weren't talking about bigger applications and even edited the original question. But here you keep using big applications as a reason why they're bad and hard to manage.
Bal
ESB is not for 'regular' programming, it is for connecting multiple modules in enterprise. It often turns out, that application modules in bigger system often talk to each other (just like any telephone owner can talk to any other). But below those multiple modules there are 'normal' objects (like Spring/EJB beans) - using event bus is bad there - given object doesn't need to communicate to all other objects.
iirekm
A: 

I've seen it before. I detest it but I cannot find anything in particular wrong with it.

Joshua
Maybe you detest it for the same reasons as I mentioned: event bus in 'normal' code breaks two important OOP principles: Encapsulation and Single Responsibility.
iirekm