Wednesday, April 25, 2007

Large Cocoa Projects

Brent Simmons has posted some good tips for managing large Cocoa projects.

Notifications can make code hard to follow

Singletons, of which the notification center is one, are basically global variables. They’re useful, and they can decouple two classes from one another, but only at the expense of coupling them to the global thing. So I agree with Brent’s advice that two objects that have a relationship should just talk directly; if they’re logically coupled, don’t obscure things with notifications. I think NSNotificationQueue is underappreciated, and perhaps a good smell test is that if you don’t mind your notification being queued and delayed, then your objects are coupled loosely enough that notifications are the right choice.

Key-Value Observing: for prefs only

None of my apps use KVO. I just haven’t had a situation where I thought it would help enough to be worth the expense in complexity. To me, it’s like less explicit notifications with a more convoluted control path. Plus, I get a bad code smell from +setKeys:triggerChangeNotificationsForDependentKey:. The idea that my objects should publish the interdependencies of their properties seems wrong. The whole KVC/KVO system seems to be designed around the idea that objects are dumb structs, and I prefer smart objects that manage their own state and interactions. Other objects should ask them to do things, not set or observe key paths into them.

Bindings are for basic stuff

I really wanted to like bindings, and at one point in the Jaguar days I started designing a framework that would address the same problem that bindings do (in a different way). But after giving them a good try, I’ve decided that they’re not for me. The only place my code currently uses them is in DropDMG’s Automator plug-in, where it’s sort of mandated. Bindings are like the opposite of Perl. They make the easy things a little easier but the harder things much harder. Since the benefit is small, and simple requirements may grow with time, I stay away from the garden path of bindings. Also, I don’t like the code structure that results from using bindings. I find it harder to write automated tests for, harder to debug, and harder to do what Brent calls “research” because some of the information is in nib files, which aren’t as easily searched or diffed. Plus, I don’t like putting my logic into nib files or strings. That’s what code is for. I wish Apple had provided a controller framework that was based on objects.

High-level Interface

I agree with the general idea of having different “levels” of interfaces and being conscious of where everything goes. This ties in with the point about notifications; generally, I use notifications to let lower (inner) objects broadcast messages to higher (outer) ones. Using C functions rather than methods is a neat trick to make the levels stand out visually. Personally, I prefer classes because (a) they force me to think about whether I should pass in an object or use a singleton, and (b) it’s easier to access classes/methods via AppleScript or PyObjC.

Use #pragma mark, use the function popup

Both are great. I have BBEdit’s function pop-up bound to Command-Control-N to avoid killing kittens.

Opening Files

I don’t use Open Quickly (though I do use Open Selection) because neither BBEdit nor Xcode offers auto-completion of the filename. Instead, I use LaunchBar, and I have sub-searches setup for each project that I work on. Or, if the file is already open, I use Command-Control-F to open the file pop-up menu and then type-select a file. Plus Control-Tab to switch between counterparts, of course. I also have Command-Control-B bound to a script that opens the current file in a BBEdit disk browser.

Managing Files: flat folder on disk

I go with multiple frameworks, each with a flat list of files.

(More comments from Daniel Jalkut and Jonathan Rentzsch.)

8 Comments RSS · Twitter

Open Quickly in Xcode does offer filename completion - type part of the name and hit F5 and it expands. (Unless I'm misunderstanding your objection.)

Steve: Thanks for the correction. I was thinking of automatic completion like in Safari's location bar or LaunchBar, where it always shows you the closest match and you can use the arrow keys to pick related ones.

actually, hitting F5 in any cocoa app presents a drop down with likely completion options.

its cool for words you would spell so horribly even spell check couldn't fix.

I primarily use BBEdit, so it doesn't matter to me too much how it works in Xcode. However, I just tried the suggestions above and couldn't get the completion to work properly in Xcode's Open Quickly. The menu of completions comes from the spell checker, not from the list of relevant filenames. Plus, I want it to work like in Safari where you don't have to press a key to get a completion.

Steve Kalkwarf

BBEdit does autocomplete the Open by Name dialog. The menu of completions is the history of previously successful Open by Names.

While arguably not as useful as completing from a project list, I find it works well in practice.

Steve K: Thanks. I'll give that a try and see if it ends up being more convenient than LaunchBar.

I just did a reasonably big vertical app with Cocoa and used bindings throughout the relatively complex user interface. They worked _brilliantly_, reduced the code volume and allowed me to get stuff done really fast.

More responses from Rainer Brockerhoff, Quentin Carnicelli, Andy Finnell, Jean-François Roy, and Blake Seely. I disagree with some of Finnell's comments about NSNotificationCenter. I think it's much better than the traditional GOF/Java implementation of the Observer pattern. It can do everything Observer can do and more, and it's great to be able to specify your own callback selector.

Leave a Comment