I like software archaeology—it’s interesting to see how far things have come. It looks like I was still calling my app NetNewsWire Pro—I hadn’t yet decided to just call it NetNewsWire. WebKit didn’t exist yet (there was a basic HTML renderer before WebKit).
This is probably on OS X 10.2, autumn of 2002. In those days folks thought drawers were pretty cool.
I have no idea why I was separating paragraphs with two brs. There was probably a technical reason for it, but it completely escapes me.
One thing that stands out about the older OS X releases is the boldness of the stripes. Wow. But another big deal, that didn’t get nearly the attention it deserved, was the improvement in text rendering that came in with 10.3. Look how blurry that text was.
Update a couple minutes later: the post I was writing in the screenshot was actually posted.
It doesn't post! It doesn't store your password in the keychain! It doesn't automatically refresh! It's useless! Just a demo! Don't worry, Craig! ;)
(BS... my initials come in handy sometimes. ;)
The idea behind this app is to show some basic use of the technologies that folks writing hybrid apps in Cocoa use. It uses NSXMLDocument and XPath to parse the friends tweets, WebKit to display the tweets, and NSURLConnection to download the tweets.
It also demonstrates that just doing the plumbing—downloading and parsing—is only the barest beginning. For Mac apps, the magic is in the user interface. This doesn’t have any of that magic.
(Folks who aren’t developers sometimes think that apps like Twitterrific are 90% under-the-hood plumbing and a 10% sprinkling of user interface. The truth is more likely the opposite: 10% plumbing, 90% user interface.)
The coolest part of this is the code that parses the Twitter friends timeline. The parser is really very small. (And I’ve heard that there are ways to do it in even less code.) The central part of the parser is +[BSTwitterParser _parsedObjectWithNode:], which shows some very basic use of XPath to get data from an NSXMLNode.
Hybrid apps are no longer the future—they’re now.
In my career I’ve heard lots of predictions—Apple will go out of business; soon there will be only six or seven websites; the browser is dead; we’ll all be running “thin clients”; Java will replace C/C++ everywhere—that I haven’t believed.
The most recent is the prediction that desktop apps are dead, that soon everything will be a web app.
I actually believe that’s correct, in a way—you’re going to see fewer and fewer desktop apps that know nothing about the internet.
But the thing about software industry predictions is that they’re usually somewhere between dead wrong and partly right in a way. This particular prediction is partly right, in a way—but it misses out totally on all the fun.
What’s a web app, what’s a desktop app?
Where does the code run? What kind of code is allowed to run? What kind of resources can the code access?
And then, of course, you can trick out your browser (depending on which one you use) by installing some cool extensions—which then run on your desktop too, even though they’re all about the web.
However, widgets can also contain Cocoa code and can access local resources. They can also have nothing at all to do with the web, even though they’re made of web dust.
iPhoto is perhaps a desktop app—except that I’ve installed FlickrExport, and iPhoto itself reads and writes RSS feeds. Similarly, iCal subscribes to calendars published via Google. My Address Book syncs over the web.
Text editors know about FTP and can usually display HTML. SubEthaEdit even does collaboration over the network. VoodooPad is a wiki—a web thing, clearly—that can generate websites, yet is a Cocoa app. Skitch makes it super-easy to share locally-created images over the web.
Delicious Library talks to Amazon. Coda is clearly a web app, in the sense that it’s entirely about the web and does HTML, networking, and so on. Google Desktop lets you search your Gmail messages on your desktop. Webmail is a special browser just for GMail. QuickSilver is web-savvy, and it’s also pretty savvy about the files and apps on my hard drive.
And then there’s iTunes. I can’t imagine wanting to store my songs anywhere but on my desktop, especially when I sync my iPod. But I also like the integration of the music store—which may not be HTML (I don’t know what it is), but it’s something conceptually similar. And of course the music store exists somewhere in the internet, even though the code to display and interact with it lives in iTunes. iTunes is a specialized web app container.
Look, it works the other direction too
The idea behind these is to write web apps that run on your desktop.
Here’s what the Joyent site says about Slingshot: “Joyent Slingshot enables Rails to break free of the browser. It breaks down the wall between a Web application and a desktop application without losing what makes a Web application great...”
Well, that sounds pretty cool. I haven’t tried any of these yet, but it’s an exciting direction. (Aside: we did similar work at UserLand years ago. But that was then, and the world is slow to catch up.)
Last thing: Twitterrific
I’ve said before that I wouldn’t use Twitter were it not for Twitterrific. None of my browsers can provide the user interface that Twitterrific provides: floating window, not in widget space, doesn’t crash when my browser crashes.
The Twitter folks were smart to provide an easy-to-use API that makes apps like Twitterrific possible. And Twitter works with IM and phones, and you can put a widget on your weblog, and who knows what all else.
It’s smart because we live in a multiple-platform world—and in a world where different people have different tastes. There’s not one soda everybody drinks: there’s diet, and vanilla and cherry, and diet-vanilla-cherry, and caffeine-free. Plus root beer.
It’s a hybrid world
Rather than make a prediction—like “Look out! Hybrid apps are coming!”—I’m just recognizing what is true right now: hybrid apps are here.
Anyone who wants to do everything in just one desktop app, the browser, can—provided they don’t mind giving up protected memory and all that modern goodness.
But most folks are going to make app-by-app decisions, and developers are going to try a whole bunch of different approaches.
If it looks like an exciting age of experimentation, that’s because it is.
My app isn’t huge compared to Photoshop or Word—it’s teeny in comparison—but it’s large compared to some Cocoa apps. (It has 345 .m files and an executable size of 3.2MB when stripped.)
It’s big enough that, were you to ask me how _____ works, I’d have to go look. There’s no way I can remember, with any level of detail, how every part of it works.
I call it the Research Barrier, when an app is big enough that the developer sometimes has to do research to figure things out. (“Research” just means reading the code and following some paths of execution, sometimes running in the debugger.)
It’s no surprise, then, that I have a few thoughts on managing Cocoa projects of this size. The below is my thinking right now—it could all change in six months. Or later today. And I could be wrong on every single point. ;)
Most of this is about making research easier—making it so that when you go back to _____ six months from now, you can quickly figure out what’s going on.
Notifications can make code hard to follow
When I first started writing Cocoa apps, I used notifications (NSNotificationCenter) all the time. They’re great for encapsulation: object x doesn’t need to tell object y that something happened: object x sends a notification, and any object that cares about it can listen for it.
But I found that notifications sometimes made code difficult to follow.
It’s difficult, when doing research, to know what’s going to happen when I encounter a notification-send. If I see something like this...
[[NSNotificationCenter defaultCenter] postNotificationName:SomeNotificationName object:self]
...how do I know what’s going to happen next? What code will run, and what other notifications will be triggered?
What I often found was that a given notification was listened for in only one place. If object x and object y truly have a relationship, why not make it easier to discern?
I still use notifications—but I often use delegates now instead, since it’s a little easier to figure out what’s going on, and since the delegate pattern shows that the two objects are related. (Which they are.)
Another thing I do—which may sound like heresy—is just to admit that class x and y know about each other. If they’re not truly re-usable in other projects, and if they really do work together, then why not take all the guesswork out and just have object x call object y directly. It makes research easier, the code is more straightforward, and the relationship between the classes is obvious. You can hide the fact that they work together with a level of indirection—but that makes things more complex, not less.
(It’s always a judgment call, of course.)
So, if I see something like this...
[[SomeClass sharedController] updateStuff]
...then I know what’s going to happen next: or, at least, I can easily jump there and find out what happens next. And it’s more honest—I know that the classes work together.
Key-Value Observing: for prefs only
Key-Value Observing (KVO) makes code paths even harder to follow than notifications. With notifications, at least there’s a line of code saying that a notification is being posted. With KVO you have no idea if changing a value will trigger a bunch of other code.
KVO is wonderful technology, but its over-use can also lead to twisty code paths.
There is one major exception: prefs. I use KVO exclusively to watch for changed prefs. This is the thing that makes KVO rock.
But still, I try not to litter the field of code with a bunch of observers: there are just a few objects that are allowed to watch for changed prefs. Not having a tangle of observers means it’s easier to know what happens when a given pref changes.
(However, I should point out that I take care to make sure my code is key-value-compliant.)
Bindings are for basic stuff
Every time I wire up a checkbox or menu item with bindings, I sing a little song of joy in my head. The song is all about how wonderful the Apple engineers are for bringing us bindings.
But the few times I’ve used bindings with a table view, I’ve not sung that song. By the time I’ve done an NSArrayController subclass to get the behavior I need, and written some value formatters to get the display I need, I find I've created a little squirrel’s nest of code.
Instead, I prefer the more traditional route of creating a table datasource/delegate: one object which does all these things without tangles.
That doesn’t mean bindings aren’t useful—they are highly useful, and I use them all the time, with great glee—but that for tables and outlines I end up with something less straightforward than I would like. When it comes to research time, it’s easier to get lost (in these cases) when using bindings.
There are a few things in my app that lots of different objects need: current feed, current news item, a flat array of feeds, whether or not there’s a download session in progress, and so on.
I’ve created a high-level interface: a set of methods that any object can call to get these things. I even make these C function calls, though class methods would work as well. (I use C because it helps differentiate the high-level interface from other stuff: it’s easy to see at a glance.)
For example, to get the current news item, an object just calls
NNWCurrentDataItem(). These functions usually take no parameters and return some high-level state information. (If they take a parameter, it’s usually a boolean.)
This retains explicitness, while also having a small barrier between classes. It also helps with my goal: I want my code to read as much like scripting as possible, whenever possible. (Tip of the hat to Dave Winer, who suggested this to me as a goal for app writers. Much of the Frontier kernel reads like scripting.)
Use #pragma mark, use the function popup
My single favorite Xcode feature is the function popup menu. It has a few cool features:
1. You can pop it up with a keystroke. Ctrl-2 on my machines. (Remember, every time you touch the mouse, God kills a kitten. Use the keyboard if you have a heart.)
2. It puts all #pragma mark Section headers in bold, so you can easily see the structure of the current file.
3. The menu responds to type-ahead, arrow keys, home/end, page-up/page-down, making it easy to go where you want to go, all via keyboard.
It’s the fastest way I’ve found to get a quick look at what’s in a file. The function popup is my good friend.
Once your project is beyond a certain size, it can be a major pain to find files in the hierarchy. So I don’t: I use the Open Quickly... command. (Shift-cmd-D on my machine.) Pretty much always.
Once you’ve opened a file, if you want to see where it is in the hierarchy, there’s the Reveal in Group Tree command (option-cmd-T on my machine). I use it whenever I want to see a file’s neighbors.
Managing Files: flat folder on disk
Years ago I used to always keep the on-disk hierarchy in sync with the hierarchy in Xcode. Total waste of time.
Instead I put a Source directory inside my project directory. Inside Source is all the .h and .m files. Flat. No sub-folders.
Then I have a hierarchy in Xcode, though I try not to let it get more than two folders deep, because deep hierarchies are just a way of losing things and wasting time.
This setup is kind of like how some apps have a library which just contains everything as a flat list—but then has separate playlists or folders for organization. The Source folder on disk is the equivalent of the flat library.
Life’s way too short to be dealing with sub-folders for my source in addition to a hierarchy in Xcode.
The main thing for me is explicitness.
I want it to be as easy as possible to know what code is doing, because that saves me time, and it makes it more likely I’ll do a good job maintaining that code.
The bigger the project, the tougher this gets. But it’s manageable.
The late ’80s and early ’90s—it was morning in America still. It was the era of Reagan and Bush the father, the era of Just Say No and “Don’t Worry, Be Happy.” There was a New World Order and a “kinder, gentler” America.
Worse—REM was starting their slide into a Phil Collins tribute band. (“Everybody hurts sometimes.”) And worse still: the Clash, the only band that mattered, were done.
Punk rock itself was pretty much done: it was sub-genres of sub-genres, speed-thrash-this-and-that. The airwaves were dominated by Whitney Houston and boring hair bands.
Then, in the Northwest, some bands were mixing punk with Kiss, the Pixies with the Beatles, and coming up with some really cool songs. And they were not on board with the kinder-gentler-be-happy thing. While America was in love with kitsch, these guys and gals were grunge.
Nirvana was one of these bands, and the one most people probably think of when they think of this era. They were one of the first “alternative/college” bands to bust through that stupid label and get played like crazy on commercial rock radio.
I attribute this to a few things: they were charismatic performers, Kurt Cobain was undeniably magnetic, and—don’t underestimate this—those melodies were catchy. (If Lennon and McCartney had been born in 1967, this is what they would have sounded like.)
I actually lived in Olympia and then Seattle those days, even saw Nirvana play before they got good. (They were super-boring, I thought: I liked lots of other bands more.)
But there’s another reason they caught on: it was because teenagers are no strangers to angst and loathing.
Was there anyone writing about what it was really like to be a teenager, in this golden dawn of kindness and order? Well, sure, but Nirvana did it way better. Explosively better. These songs were phenomenal, with an assured-ness you rarely see from songwriters so young.
It’s easy to criticize Kurt Cobain—he killed himself, after all, and to a mature ear some of the stuff is so whiny it’s silly—but he didn’t invent teenage angst. I, and many of my friends, sure had their share of it long before we ever heard of Nirvana.
Kurt would have turned 40 a few months ago, and I’m still mad about not getting to hear those years of songs. But I’m glad that the old songs still get played, and teenagers learn that their feelings are not just theirs, and get the comfort and inspiration that they get from that.
Since I was born in 1968, I didn’t have Nirvana as a teenager. But I had plenty else. Here’s John Lennon, “Yer Blues”...
My mother was of the sky My father was of the earth But I am of the universe And you know what it’s worth
Lifehacker reviews Tumblr: “Experienced bloggers looking for advanced, detailed CMS features in Tumblr will be disappointed. There are no comments, trackbacks or categories; there’s no ability to change the timestamp on a post and no search capabilities.”
Sounds simpl: I lik.
I was looking at the comments on TUAW’s coverage of the Leopard-delayed-till-October news.
Some selections: “*cry*” “Noooooooohohoho!!!! Waaaaah!!!! Tears form in my eyes (for real).” “Unbelievable & sad.” “I just died inside. I have no words to express my grief.”
Not all the comments are as silly—but still, I have to wonder about people who proclaim, even hyperbolically, that it’s making them cry. Developers doing a Leopard-only release—I can understand their being upset, because it means they can’t ship until October. But other folks? Tears? Really? 10.4 is such a burden to use, we can barely stand it?
(I wonder if the fashion treadmill is a mistake, kind of like using protomatter in the Genesis matrix. Eventually it blows up, even if early results are spectacular.)
Anyway—take it from me, a veteran of 27 years of Apple OS upgrades. A few extra months will be okay. ;)
Seattle Times: King for a day.
Last night’s complete game, one-hit shutout keeps Felix Hernandez’s ERA at 0.00 with 17 innings pitched in two games. 18 strikeouts, four walks, four hits. Opposing hitters: four for 52. More info at U.S.S. Mariner.
He turned 21 last Sunday.
I love his books. Vonnegut will be remembered as one of the great American writers.
I hope that wherever he is he’s with some friends.
Here’s how I know I’m a geek.
It’s been years since I’ve been on the Paris Métro, but I still remember a little sign that was in the subway cars: tout abus sera puni.
I don’t remember that phrase for what it says—I translate it as “all abuses will be punished”—but for its mathematical properties.
tout abus sera puni: four words, 16 letters. Four letters per word: two consonants and two vowels.
It’s a square sentence, if there is such a thing. And, as such, I’ve always remembered it, and I always remember sitting or standing in the subway and being fascinated by it.
If I were one of those authors of Templar/Mason/Grail conspiracy novels, I’d probably use this as a coded message of some kind. The sacred 4 x 4 clue printed all over “underground” Paris, with a bland message that should really be translated more grandiosely as a clue to what we will do to our enemies, the heirs to the Spanish Inquisition, or whatever.
Sometimes I wonder about the complexifying instinct.
Entropy for software isn’t disorder—it’s more features. It’s caused by people wanting more features. And wanting them quite reasonably and intelligently: wanting good and useful features.
Think of the initial appeal of Blogger: you type into some little text field, and it appears on the web, and everyone can read it. Easy and delightful.
But blogging didn’t stop there, because people quite reasonably wanted to have titles. Sure, titles, of course, we need titles, I agree.
And then, of course, Slashdot had departments, so don’t weblogs need categories or something like that? A weblog is a kind of knowledge management app, after all, and categories are a pretty lightweight addition. Okay, sure, categories, let’s add ’em.
How about summaries? Sure thing. And hierarchical categories? Trackbacks? Ja. A setting for enabling comments. A setting for appearing on the home page. Sure, sure, everything’s reasonable—everything’s needed, even. Extended entries. Tags. Enclosures. Yes.
The only thing that’s lost is the sheer delight of that simple text field for posting to the web.
So then there’s Twitter, which is, basically, a service where you type into some little text field, and it appears on the web, and everyone can read it. Easy and delightful.
Sometimes I see feature requests for Twitter, and this makes me nervous. I hope that it adds zero features.
Even if weblog writing has turned baroque, there should be space for at least one thing on the web that stays simple and fun.
If weblogs are the city of the web, then Twitter is the lone tree on the prairie, cool for just standing there among the grasses, a home for birds.