Archive for April, 2007

In Defense of Observers

Recently Brent Simmons posted his thoughts about large cocoa projects, which elicited a lot of responses within the Mac programmer community about what makes code easier to “research.” There’s a lot of good stuff there, but I wanted to focus on one facet of the discussion that was brought up, namely NSNotificationCenter.

First, anyone who has read the Design Patterns book knows that NSNotificationCenter is the observer pattern. It is useful for decoupling objects, in which is a good thing, because it makes classes more reusable (because they have fewer dependencies) and more maintainable, because, if done correctly, it insulates changes in one class from another class. These are all good things, and observers are good, and you should use them.

The problem comes up with Apple’s implementation of NSNotificationCenter, and I’ve often wondered why they chose the implementation they did. There are a few problems with it:

  1. As noted by Michael Tsai, NSNotificationCenter is a singleton, and thus essentially is one big honkin’ global. Globals are bad ™.
  2. NSNotificationCenter allows a many-to-many relationship between observers and their subjects. That is, many different subjects can send the same notification, and several observers will listen for the notification, regardless of the sender.

    This breaks the observer pattern, which was intended as a one-to-many relationship, because it breaks the idea that the observer observes the subject. Instead it produces the idea that the observer observes the notification, which is wrong. The notification is simply a convenient way to pass information between classes, it is not really a part of the relationship between the subject and the observer.

  3. The syntax of using NSNotificationCenter puts the notification center as the receiving object, and thus puts the focus on the notification center, instead of focusing on the relationship between the subject and its observer.

These problems are compounded by the fact that just about all sample code that I’ve seen, from Apple and others, use NSNotificationCenter in the many-to-many relationship, instead of a one-to-many relationship.

Of course Cocoa uses another design pattern that can be used as a stop-gap for the observer pattern: delegates. Delegates define a simple one-to-one relationship between the subject and its delegate. It has the benefit of being easy to implement and clarifying the relationship between the subject and delegate. The problem is, it’s not appropriate for the observer pattern, for a couple of reasons:

  1. As the name implies, a delegate is delegated tasks or decisions. That is, a subject is dependent on the decisions a delegate makes, and will change behavior depending on if, and which, delegate is attached. This is the opposite of an observer pattern. The subject does not care who is listening, or if anyone is listening at all. The observer, however, will often change behavior or take action, depending on what the subject does. In other words, the dependency is modeled in the exact opposite direction in the delegate pattern.
  2. The delegate pattern is a one-to-one relationship, but the observer pattern is a one-to-many. It makes sense that a delegate subject would only have one delegate making decisions for it, but it doesn’t make sense that an observer subject can only have one observer listening to it.

Still, you can trivially implement a one-to-one version of the observer pattern using the same technique as implementing a delegate. You just shouldn’t call it a delegate because you’re implying the wrong direction for dependence.

All this said, there’s a much better way to implement the observer pattern, which I’ve seen in just about every other framework I’ve used. Things get a little tricky in Objective-C because the lack of multiple inheritance disallows use of mix in classes. However, it can still be done. Essentially you’d need two classes: ObserverSubject and Observer.

ObserverSubject maintains a list of Observer objects that are listening to the subject. It has hidden methods, called only by Observer, for connecting and disconnecting interested Observers, and a notify method for the actual subject to notify all listeners that an interesting event has happened.

The Observer class maintains a list of all ObserverSubjects that it is currently listening to. This is for the express purpose of automatically disconnecting from them when the Observer object is destroyed. The main method on the Observer class is called watch, and connects the Observer with the Subject. The Observer class also keeps a pointer to the actual observer, which it forwards all notifications to.

A simplified example of how these classes would be used:

@interface MySubject {
- (ObserverSubject*) subject;

@interface MyObserver {
- (Observer*) observer;

MySubject* mySubject = [[MySubject alloc] init];
MyObserver* myObserver = [[MyObserver alloc] init];

[[myObserver observer] watch:[mySubject subject]];

In this design, the one-to-many relationship is enforced, and the syntax puts the focus on the relationship between the subject and its observer. Also note the lack of globals.

In conclusion, observers are a good thing, and you shouldn’t write them off just because Apple did a shoddy job of implementing them. Modeling simple one-to-one observers is trivial to implement, and modeling a true one-to-many observer pattern isn’t all that difficult either.

I have arrived, geographically speaking

Charity has informed me, via Elaine, that I need to post. Since I haven’t fully formed any of the technical articles that have been banging around in my head, I guess this will be a personal post.

As you can tell from the sidebar to your right, I have arrived in the Bay Area, and have begun to hate the driving situation already. Elaine’s sister commented that I drive somewhat aggressively for someone from Tennessee/Texas. It’s true, but it’s because when I first arrived in the Bay Area about four years ago, I couldn’t even getting on the freakin’ freeway until I started driving like I robbed the local 7-Eleven. And yes, I mean that you have to openly brandish firearms before anyone will let you merge, if only begrudgingly.

On the home front, I have an alarm system that seems pissed at me personally. It waits until I feel safe and comfortable, then emits a high pitched screech, designed to scare the bejezus out of me. Before you think the screech is benevolent, let me assure it is not. It is not the beep of “there might someone trying to break in,” it is the beep of “This home’s alarm system is not working! Free furniture!” The landlord has apparently not paid the monthly upkeep on it, so it feels the need to berate me about it, despite the fact it won’t even tell me where to send the check. Fortunately I think I have finally located its lifeline, and me and my friend, Phillips Screwdriver, have already set plans into motion to end its miserable life.

I’ve also attempted to get some sort “programming” for my television set. My first choice was to try Comcast, because I was feeling particularly masochistic that day. I meticulously entered in all my information at their website, selected a package, and made an appointment. This data is carefully translated into Kannada, printed out, and handed to a Comcast associate who promptly shreds it. Meanwhile, I was waiting in line to chat with a janitor — or maybe the groundskeeper, I had forgotten who by now — in a Java applet specially designed for people who wish to go blind by staring at impossibly small fonts for hours at a time. “Willy” (I forget what English name he gave me) helpfully asked me all the questions the form already had, but with much longer pauses and more grammatical errors. I was then informed I could only have the package I selected if I paid twice what they advertised. Apparently they have make up for not buying an ordering system that actually connects with their backend somehow.

It was about this time I remembered that my TV had a built in HD tuner, and I lived in the Bay Area, which has lots of off-air HD content, all from PBS. All I needed was an antennae, and loss of will to live. I ordered both off Amazon, which went smoothly. Unfortunately, it was shipped on Friday via DHL (motto: “You’ll never have to ask ‘where’s my package?’ again, because damn if we know.”) using “next business day.” It arrived on Wednesday, which clearly is the next business day, if you willingly block out Monday and Tuesday with liberal amounts of alcohol, wishful thinking, and pixie dust.

I’ve stayed pretty busy working on my current contract. It never ceases to amaze me how much money they pay people to code, who so obviously have no skill to do so. If you can’t design a class without making most, if not all, data members public nor can you handle errors or exceptions without a lot of goto statements, maybe you should seek other employment opportunities. Seriously, there’s one coder in particular that I wonder why he hasn’t been fired, or at least barred from ever touching the code. Code wilts when he gets near it.

There Charity. You are now officially up to date. Bring back sweet tea and Chik-fil-a.