In .NET Rocks! episode 355, Richard and I talked to Ted Faison about event-based and event-driven programming. There’s more to it than you think.
Ted Faison has more than 30 years of experience in the software industry and has been involved with object-oriented-programming and component-based development since the inception of those technologies. He is currently working on .Net projects for the Motorcycle Industry Council and Amtrak. Ted is the author of the books Event-Based Programming: Taking Events to the Limit, Component-Based Development with Visual C#, and a few others.
Richard Campbell: Ted, I approached you to come on the show because we were talking about the whole event-based programming that really caught my attention, but as we’ve been doing a bit of a more fundamentals track on .NET Rocks! lately, the idea to sit down with someone who’s been in this industry a long time and really think about how events came about and evolved to what they are today, I think that was a really interesting conversation.
Ted Faison: Yeah, I agree. I’ve been looking at events for quite some time now and events didn’t materialize perhaps surprisingly for some people with the .NET Framework or with Java. In fact, you have to go way back into the 1970s to see the first inklings of what we call today events. The first big commercial project or product that came along to support events in the way that we know them today was probably Visual Basic. I would say early 1990s, maybe around 1991.
Carl Franklin: That’s right.
Richard Campbell: Yeah, yeah. Of course, that’s because we are now living in a GUI world; you have to deal with events. You have to trap the mouse click.
Ted Faison: That’s true.
Carl Franklin: I was never really-I was always confused as a VB developer about concurrency and even though I didn’t know the word concurrency, I didn’t know what a thread was. In the back of my mind I was always confused about when are things executing. While I’m in this event, is other stuff happening, right? Is my other code just waiting for me? That kind of stuff. I never really thought about it that much but it was always on my mind.
Ted Faison: Yeah, it’s an important consideration as with all code in fact. The Visual Basic paradigm of events belongs to a broader collection of programming techniques called event-driven program. Visual Basic is an event-driven environment. Windows itself is event-driven. That doesn’t mean it’s event-based. There’s a difference.
Richard Campbell: Oh, interesting.
Ted Faison: We’ll get into these differences a little bit later perhaps, but just as a fundamental discriminator, event-driven programs are those that essentially do nothing until they receive an event and then they go off internally and handle the event in some way. Now with event-based programs, they’re not necessarily idle until an event comes in and the biggest distinction between the event-driven and event-based is the fact that event-based relates to the internal structure of the program. In other words, the parts of the system internally talk to each other using events, whereas, an event-driven system can have any arbitrary structure internally, but it only does things when it receives events from the operating system.
Richard Campbell: Interesting. So, really, I guess event-based is a much more complex concept than the way your application communicates to itself by firing events back and forth.
Carl Franklin: Well, I would think an event from what you just said-if I could paraphrase-an event-driven application just sits waiting and doing nothing until it receives a notification, right?
Ted Faison: That’s correct, yes. An event-based system may be receiving events from the operating system or it may be any other type of system that’s not operating system-based. It could be a standalone program running on a portable device. If it’s event-based, that means it’s all the individual parts which could be objects, classes or components. They talk to each other using an event paradigm.
Richard Campbell: You bring up an interesting point here, which is are events owned by object-oriented programming? Do we have events before OO was around?
Ted Faison: Yes. We certainly did. The concept of events goes way back into the 70s, like I was saying before, and probably one of the first events-based or at least systems to consider the use of events was something called MIL75. That’s a Module Interconnection Language developed for the military in the 1970s along with a host of other types of module-oriented systems including POLYLISP and a few other that are basically unknown today, but those were the first times we saw dynamically routable events being used in published software systems.
Richard Campbell: What do you mean by dynamically routable?
Ted Faison: A lot of times, when we think of events, I suppose a Windows program for example, when you think about handling an event such as a mouse click, what happens is typically the mouse click is handled always in the same way. In other words, if a certain object is clicked, it always does the same thing.
Richard Campbell: Right.
Ted Faison: Event-driven systems are typical in that sense. Event-based systems are quite a bit different in the sense that the handler for an event can be changed at runtime and it’s typically changed at runtime. Usually, with event-based systems, the event handlers are only established at runtime so until the system starts running, there are no event handlers in the system so nothing is connected to anything until the system starts up and figures out what its wiring will be. The wiring can be changed during execution based on certain situations. For example, if the system is implementing the equivalent of a state machine, it can change the wiring between the parts so that events go to different places depending on what state the system is in. That’s a very powerful way to use events. So, there’s a tremendous amount of flexibility in how the events are wired dynamically and to this end, there are patterns of the use of event-based parts that allow systems to easily be configured using standard things like builders, binders, coordinators. These are entities that are heavily used in event-based architectures that are very easy to use and result in a very simple system diagrammatically. If you look at a diagram of an event-based system it looks a lot like a circuit diagram because the events, or the event notifications I should say, look a lot like signals travelling unwired. So, the wiring diagram of an event-based system tells you pretty much how the system is put together just like a schematic diagram would tell you how some electrical thing is put together.
Carl Franklin: Would you say fundamentally that an event is basically where a listener subscribes to something that happens at sometime and passes in or registers a code pointer at the very minimum and possibly an interface?
Ted Faison: That’s one way of looking at it, but events are a little bit more than that in general. The so-called observer pattern that’s used a lot today especially in Java systems is based on the concept of self-registration. In other words, an entity, a part that wants to get events or event notification from another part registers itself with that part. This is one way of connecting the parts together. In other words, the observer registers itself with the "observee", if you will. There’s another more powerful way to hook up the two entities together and that’s by using a third party or a third control called a binder. The binder, the observer and observee are connected together and that preserves the decoupling between the two parts. So, now the entities observer and observee can be developed independently and at some point in the future maybe they are hooked up together by a binder.
Carl Franklin: I see. So, the thing that raises the event, the observer-is the observer the right one that raises the event?
Ted Faison: The observee or the subject.
Carl Franklin: The observee, the subject, yeah. That just says, "I want to raise this event," and then the binder is the thing that has the list of observers that goes out of it.
Ted Faison: It’s not quite like that. Basically, in a simple system, at initialization time when a system is coming up, a binder will take over and wire all of the subjects to the proper observers. So, the subjects don’t know anything about observers. The observers don’t know anything about the subject.
Carl Franklin: Oh, so it does both?
Ted Faison: There’s actually more than a binder. There’s a builder first, so when a system starts initializing, it creates instances of all of the entities that will be wired together: observer, subjects, everything, any system typically; and then it passes control to a binder which then hooks the parts together.
Carl Franklin: Okay. So, as you said, that preserves the decoupling.
Richard Campbell: I guess the only reason to have these separations is so that you could switch out different bits. I could be collecting events from a different observee.
Ted Faison: Or subject. We normally call them subject.
Richard Campbell: Or subject, yes.
Ted Faison: Absolutely, and that’s where the dynamic wiring comes into play. As I mentioned earlier in the state machine example, you could have, for example, in state A the subject fires events and they go to observer A. Later a binder comes along and switches that wiring to a different part, for example observer B, so now when the subject fires that original event A, it goes to a different part now and in this case observer B, which could do something different perhaps because the system is in a different state.
Richard Campbell: Maybe we should cite some simple examples. I’m guessing maybe the mouse pointer might be one. Correct me if I’m wrong, Ted, if this is not a good example. The mouse pointer is an event driver because if I click on it, it does something and it has state effects because if I clicked and then clicked again, the timing between those two, that’s sort of a state management and now it’s a different behavior because of two clicks. The whole wiring part gets interesting when you start looking at I’m clicking on one form versus I’m clicking on a different form.
Ted Faison: Yes, that’s true. However, it’s more practical to look at event systems by not looking at the way a Windows program works with a mouse because people have a certain mental image of what a mouse does to their system when you right-click a menu.
Richard Campbell: Mice are special.
Ted Faison: Whereas, in an event-based system, the events are not related to GUI things at all. They can be.
Carl Franklin: I’m thinking of an ASP.NET context, where an ASP.NET service is running out there and events are happening from the client, they’re happening from the server and the context maintains the state of that session.
Ted Faison: Yeah. That brings us to something called a model-view controller design pattern and that’s certainly one of the best things that was discovered, I guess in the 1970s, for utilizing events. The idea there is that you have a model, which is shared by multiple views and so you might have multiple forms that are hooked up to the same database, for example, which might be the model or some list collection. When the collection changes, all of the views need to be notified so they can refresh themselves. Now, that’s a really good event example. If we have the controller acting as the binder, the controller then can wire together the model to all of the views, so the views don’t know anything about necessarily anything about the model and the model doesn’t know anything about the views. So, when the controller wires the model to the view, then any events that the model fires get routed to the appropriate view and then a view can then take whatever action it wants. For example, the typical event that would be exposed is that something is changed in the model so then the views would probably repaint themselves.
Richard Campbell: Right. Data has been updated…
Ted Faison: Yeah, exactly.
Richard Campbell: So, now the views need to redraw to show the new data.
Ted Faison: Exactly.
Carl Franklin: You do that in game programming all the time too, right? Graphics programming.
Ted Faison: Absolutely, yes. Now, there’s a misnomer in a lot of the event-driven and event-based systems out there right now related to the way event notifications should look and languages like Delphi and Java have language-dependent, I guess you could say, semantics on how the signatures of these invocations, the event notifications, look. For example, when you fire an event in Delphi or even .NET, it is considered normal to pass as the first parameter in this notification a reference to yourself.
Carl Franklin: Yes.
Ted Faison: So, whoever is getting the event has a reference to you. That is not necessarily a good way to handle events.
Carl Franklin: No.
Ted Faison: The reason is because whoever is handling the events doesn’t know anything about you, who’s firing the event, and may not even know what type you are.
Carl Franklin: Yeah.
Ted Faison: So, by passing that reference to yourself to the handlers and in this case with the model-view controller example, it would be the model passing a reference to the model in the data change event that goes to all of the views. Well, now the views have to know what type the model is and they have to know how to deal with the model.
Carl Franklin: Tightly coupled.
Ted Faison: That’s not a good use of events.
Carl Franklin: Yeah, it’s tightly coupling.
Richard Campbell: You really broke the whole decoupling concept.
Ted Faison: Exactly, exactly. The whole point of events is decoupling so you don’t want either party, either the observer or the subject, to know about each other, and so passing references to each other is bad. What you want to do in an event is pass all the information you can to allow whoever the handler is to handle the event successfully without having to contact the original subject again.
Carl Franklin: Right. You said we had to do that in some Visual Basic programs when we didn’t have any other tools and it was always a bad idea, but sometimes it was the only way to do it. Otherwise, you end up polling, right?
Ted Faison: Well, there are situations where you might want to pass a reference to the originator of the event in the event handler. It might be, for example, if you have a button click handler on a form, for example, and perhaps it manages clicks of different buttons, so you have three or four buttons on the form and a single handler handles all three or four of those. So, now the handler might take different actions depending on which button it would click. In that sense, I would argue that maybe you would want three or four different handlers, one for each button, as opposed to having a single handler for all the buttons, but, again, system architectures might dictate requirements so that you couldn’t do things exactly the way you wanted and in those cases you might have to deal with a reference to the event origin to the handler.
Carl Franklin: So, I worked on the spec for the MSComm control which is the serial communications control in Visual Basic. I don’t know if you knew that, Richard.
Richard Campbell: I did not.
Carl Franklin: Because you probably used it. You just said in the last recording you use that quite a bit.
Richard Campbell: I did.
Carl Franklin: And I remember having this discussion about the architecture of the event handlers. My original thought was that I wanted to have different events for the different signals, right? They wanted to, Microsoft wanted to-and so did the rest of the guys at Crescent-have one event that happened on COM or whatever it was, because it closely modeled the behavior of Basic and then you would basically check a parameter with a large Case statement to see which signal was thrown.
Richard Campbell: That to me seems broken. If the first thing you do as soon as an event rises is try and figure which event was it, shouldn’t they automatically be abstracted that way?
Carl Franklin: Yeah. I guess their reasoning was something to do with backward compatibility and something also to do with being able to keep all your code in one place, but I agree, Richard. I didn’t think it was a good idea. I mean, if DTS goes low, there’s only one piece of code that needs to handle that. It can go in a separate event and if there’s data that needs to be shared, it’s shared.
Ted Faison: That sounds like a good idea, yeah.
Richard Campbell: Yeah, one place for all the code just sounds like a mess to me.
Ted Faison: Yeah. If you need a switch statement to figure out what you’re doing; that means you’re essentially multiplexing signal path. You’re sending all the signals over the same pass and letting the handler figure out the mess.
Richard Campbell: Backing all the way back to this whole thought around the asynchronousness of this event model where we don’t know what else is running; we don’t know how much concurrency we’ve got; the more big gloves of code we’ve got versus small gloves of code we’ve got; the more trouble we get into with mutexes and things protecting simultaneous executions of the same block of code.
Ted Faison: That’s true.
Richard Campbell: So, I’m all over. Let’s spread those things out and give them a natural level of separation so that many different things could be happening at once are not going to run into each other.
Ted Faison: Yeah and even without events, it’s a good idea to break functions down into a more manageable part.
Richard Campbell: Just to make them understandable.
Ted Faison: Absolutely. I use a rule of thumb typically when I write code that the entire body of a function or method is seen on the screen. Without scrolling up and down 200 times. I should be able to see the body of the method right there. There are occasionally cases where that can’t happen, but most of the time a function should fit on a screen.
Carl Franklin: Yeah.
Richard Campbell: Well, ever since I got my 30-inch screen in portrait mode, I just don’t have a problem with that.
Carl Franklin: Yeah.
Richard Campbell: We were just walking down the stack here about events and notifications and, really, we’re talking about notification payload when we start talking about providing a handle to the calling object, which I guess we’ve all agreed wasn’t a good idea. What other payloads make sense?
Ted Faison: Well, regarding payloads, there is a-well, I would say a payload that makes sense is a payload that conveys information about what happened. Now, this is not necessarily the same as payloads that are currently being promoted in a .NET environment or in the Java environment. Typically, in the .NET world, if you read the Microsoft Best Practices documentation regarding events, they’ll say that when you pass a parameter to an event handler, it should be a parameter that’s derived from a class called EventArgs. So, all the payloads should be classes derived from EventArgs.
Carl Franklin: Okay.
Ted Faison: Why is that? That’s bad. Why should my payload have anything to do with a base class? I passed whatever information I need. So, if I need to pass a string, I pass a string. The problem with passing classes that are derived from EventArgs is that every time I fire an event now, every time I define an event, I have to define a new class just to pass those parameters over to the event handlers so you get what I call classic explosion. If you have 100 events of different types in your system, you have 100 types just to encapsulate the parameter of your passing and in most cases events don’t pass very many parameters and in many cases they don’t pass any parameters. That’s called the universal signature where you have passed nothing and receive nothing back. That’s what I call a universal handler. There are a lot of good things about universal handlers, but without getting into the details of them. I’m saying the Best Practices’ call for deriving all of your payloads from the EventArgs, I disagree with that. If you need to pass an integer to say, you know, what the button click count or the name of the string that indicates the caption of a form, whatever the arguments may be, just pass them directly. There should be no reason to create a new type for the sole purpose of passing parameters along. I don’t see any benefit whatsoever in that.
Richard Campbell: Transportation classes.
Ted Faison: Yeah.
Richard Campbell: Just for transporting data between layers.
Ted Faison: Well, there’s no tangible benefit that I can see and I’ve been using events for many years.
Carl Franklin: Here’s a question out of the blue. Where do SOA, service-oriented architectures, and events meet?
Ted Faison: That’s a good question. Actually, service-oriented architectures are the latest fad, but they really are an incarnation of something that was earlier called a component-based system. Back in the 1990s, a lot of research was done in component-based engineering and component-based software engineering. I did some work in that arena as well. A component-based system is what today is called an SOA. In other words, a component is defined exclusively towards interface and the interface does not marry you to any computing platform like .NET or Java. That’s what an SOA basically is. It exposes its interfaces through services potentially. So, the point of connection between SOAs and events is the same as it was between component-based systems and events. Basically, components can be considered clients or services. If it’s services, they can receive calls from clients, but they can also send information back to the clients using events. So, with an SOA, you can establish an event channel back to each of the individual clients that happen to be connected to you. That’s supported also using things like Windows Communication Foundation and other technologies.
Carl Franklin: Yeah, so component-based and not in the sense of like a .NET component, but component-based in the sense of discrete separate parts that operate independently of each other.
Ted Faison: Exactly.
Richard Campbell: That predates .NET by a long way. We were doing that for a long time.
Carl Franklin: Sure.
Ted Faison: Yes, but SOA became extremely popular once we were able to divorce the implementation from the platform. Now, with Web services, it doesn’t make any difference what platform was used to implement the service. Anybody can call it, so that’s really the magic that made all of this happen: the Web services layer.
The conversation continues at www.shrinkster.com/10aw.