Feb 2009

On doing better than just dumb text

waffle: “If we did all that, and we should, we would finally be able to write intelligent code to manipulate code — cross-language. Consistently, using open and established formats.”

Super-simple Xcode user script for header files

Sometimes a little naggy thing can be solved really, really easily.

Here’s the thing:

I usually create my methods in my .m file, then decide if I want to copy and paste the top line into the .h file.

If I do, then I have the issue where I’ve copied something like this...

- (void)someMethod {

...but I want the following in the .h file:

- (void)someMethod;

I wrote a little Xcode user script to deal with this. I gave it a cmd-{ keystroke. I find that I use it all the time.

The incredibly simple script looks like this:

#!/usr/bin/env ruby
s = STDIN.read
s.gsub!(" {\n", ";\n")
print s

The way it works: I copy from the .m file, hit cmd-option-upArrow to go to the .h file, paste, select the line (shift-upArrow, since the cursor is on the line immediately below), then hit cmd-{ to run the script. Saves me from manually changing the { to ;.

It’s safe to run over multiple lines, too.

That’s still too many steps, by the way — I’d really love to be able select the line in the .m file, then hit a keyboard shortcut to insert it in the .h file at the end of the list. But I haven’t gotten that far yet. (Though this page on Cocoa with Love might provide some good tips.)

Update: I’m fully aware that both of the following are legal in .m files...

- (void)someMethod; {

- (void)someMethod;
{

...but, no offense to Andrew Stone (who I first saw write about this), I don’t like it. The ; is unneccessary, and I’m compelled to delete it. I know myself — I will never, ever, ever allow that extra ; to sit there. I don’t think I could even sleep, knowing there are lovely little semicolons to delete.

Moving to libxml2 SAX2

There are two types of code I especially love writing: very high-level code that reads like human thought and low-level code that solves a specific problem.

(Aside: the problem with AppleScript is that it’s high-level like speech instead of high-level like thought. But people don’t speak programs, they think them.)

I’ve just about finished moving my XML parsers from libxml2’s xmlReader API to libxml2’s SAX2 API. This would fall into the category of “low-level code that solves a specific problem.” So it’s fun. :)

Why make this move?

There are a couple main reasons to do this:

  1. There’s a small memory leak in xmlReader, at least in the version of libxml2 that appears on Macs and iPhones. It’s not a bad bad leak — but every leak should be fixed.

  2. The SAX2 parser can process XML in chunks. You can pass it part of a document, then the next part, then the next, until finished. This means you don’t have to have the entire document in memory — which is great if you’re downloading and parsing a large feed: each time you get additional data, you can pass it to the parser then release the data (that chunk). (None of NSXML* has this same capability.) This is obviously a good thing on iPhones, but not at all bad to have on Macs as well.

One drawback of libxml2’s SAX2 API is that it’s a C API. Which, for me, isn’t much drawback — I don’t mind C at all. (In fact, I like it for code like this.)

But still, my approach is to write a simple base class that handles the complex bits, then do sub-classes that are easy to write. It’s the thinnest of wrappers, using the guiding principle of not creating objects unnecessarily — but it’s enough of a wrapper to let me use Objective-C and Foundation data types.

For more info

If you’re interested in more about this, I recommend Apple’s XMLPerformance sample code. (Somewhere on the iPhone Dev Center.) It compares NSXMLParser and libxml2 SAX2.

Good for Macs too

There’s a third type of code I especially love writing: code that gets used in all my projects, all my iPhone and Mac software.

It’s cool how working on iPhone software has caused me (and lots of other Mac developers) to concentrate on memory use and performance in ways we haven’t had to for many years — which will also benefit our Mac apps.

PS You get to write a state machine

I was talking SAX with some local developers the other day. I hope Gus won’t mind my reporting that he loves SAX, because “you get to write a state machine!”

Which to me is like saying, “You get to have your eyes slowly gouged out with moldy bananas!” And I don’t like bananas.

For anyone used to DOM parsers, SAX seems, at first, to be inside-out, backwards, and upside-down. Tesseract-y and vicious.

But you can wrap your head around it quickly, and, depending on what you’re processing, you may not have to deal with that much state at all. (The hardest thing I’ve had to do — which is easy, face it — is parse hierarchical OPML documents. A LIFO stack does the trick.)

Anyway, I’m just saying, don’t let Gus scare you off.

PPS Now I get to delete some code

I’m off to delete my old xmlReader API code. Now that is fun.

Part of me wonders if I went through all this just so I could use the delete key a bit. No. Couldn’t be.

Could it?

Variety iPhone app (plus an observation about RSS and technical details)

We just shipped a free iPhone app based on NetNewsWire 2.0 — based on our iPhone media app framework, which is the same thing — for Variety.

Here’s a screen shot:

Variety iPhone app screenshot

Hidden RSS

It’s an RSS reader, yes, but nowhere is RSS mentioned on its page on the App Store or in the app.

Marco Ament wrote today, “I think we’ll see more products and features that are based on RSS but don’t call it that.”

Or, as Greg Reinacker has said, “RSS is plumbing.”

RSS is so massively useful — it’s how stuff moves around on the web. As technologists we all know how important RSS is. And yet the typical web surfer probably has no idea what RSS is — and they use it without knowing it.

You know what? There’s nothing wrong with that. If it’s plumbing, then cool. Our job as software developers is to create stuff people like. Acronyms and buzzwords don’t mean anything. People want fun things and useful things — hopefully both at the same time.

That isn’t to say RSS readers are going away. They’re not. But a lot of the future of RSS is in doing apps that use it without talking about it.

iPhone media app framework

As part of working on NetNewsWire 2.0 I’ve developed an iPhone media app framework. The idea is that, to build an app for a media company, we work with them to gather their artwork, color choices, and a list of tabs and feeds. Then we create a new target with its own configuration file, then build it.

You know what? It works. Good idea. ;) And we have more of these in the pipeline. (In fact our first-to-ship wasn’t this Variety app: it was an app for Brad Feld of the Foundry Group.)

Of course, I’m still adding features, on the theory that anything one customers wants will probably be requested by other customers too. And I’m continuing to work on NetNewsWire 2.0. (Many of the requested features will appear also in NetNewsWire.)

App design

I have a simple theory about apps like this: they should just work.

While people who use RSS readers always ask for super-fine-grained control over refresh periods and things like that, an app like this shouldn’t even have a refresh button.

That is, there’s no indication that you’re reading RSS. There’s no indication that there are feeds to go out and get. The news just appears.

The app is set so that it refreshes on launch, but only if at least 15 minutes has passed since the previous refresh. In this app, RSS is just plumbing, so I hide the mechanics.

Putting pieces together

One thing I seriously love about this app (and the media app framework) is how it puts together different systems we’ve built.

The running app is of course NetNewsWire/iPhone, but it also uses our content service and syncing platform to read the feeds. It provides editorial control over the feeds via Editor’s Desk — folks from Variety can pick and choose items to appear in the app.

Editor’s Desk was originally written for widgets (and there is a new Variety widget too) but it works great for iPhone apps like this too.

Using our syncing platform is a cool thing too — because it’s efficient. Instead of reading entire feeds on every refresh, it asks our system just for the new items since the previous refresh. This means the iPhone app is doing a lot less work than it would do were it reading feeds directly from the source.

(It also means the feed provider doesn’t have to concern themselves with a ton of iPhone users suddenly hitting their servers: the app talks to our servers.)

I like it when the pieces come together like this. We’ve spent years building some of these parts, and we get to reap the benefits now.

People

And, of course, there are people as well as technologies. I thank the inestimable Ed Manning for putting this deal together. Ed totally rocks.

And I thank Walker Fenton for all the work he did on getting the product finished.

Especially at the end. We had a deadline, and it was already nighttime when I was trying to finish it and upload it. It went sort of like this:

Me: Oh noes! Can’t ship today! Need -----!

Walker: Oh, relax. Try this -----.

Me: That works. But! Something else! We’re doomed! Need ------!

Walker: Oh, this right here will do the trick. Try ------.

Me: Oh, yeah, good call. But look out! Something else! Halp!!!

Walker: Here’s what to do...

Etc. Repeat until shipped.

App wanted: crash log database and analyzer

I wish I had an app that gathered crash logs for my apps.

It would store them in a database, provided a searchable and customizable user interface (desktop, browser, I don’t care), and, most importantly, allow me to write scripts that do automatic analysis, classification, and prioritization.

As an example: since my Mac app uses WebKit a ton, I get a fair amount of crashes with lines like this:

Thread 0 Crashed:
0 ...romedia.Flash Player.plugin

(Yes, Flash, I’m complaining about Flash again. Flashy Flash crashes.)

When I’m looking at my crash logs, I’d love to be able to do a search with filters — to do something like “show me all crashes in the past week that are not Flash crashes.” I could write scripts that do pretty well at figuring out what’s a Flash crash and what isn’t.

At the same time, an app in beta right now has a crash with text like this:

Thread 10 Crashed:
...
1 libxml2.2.dylib

A crash like this means I’ve done something wrong with the XML parser: it should be top priority. Again, a script could figure this out. (By using logic something like, “if the crashing thread contains ‘libxml’ then set priority to highest.”)

This app would also give me the ability to mark crashes as fixed. In the example above, I’ve already fixed it — so I’d want to be able to mark that crash log as fixed, and have the app find all similar crash logs and give me the chance to mark all of them as fixed as well.

Maybe such an app exists and I just don’t know about it? I’ve thought about learning Python and doing it as a Django app (great excuse to learn Python and Django) — but if it already exists, or someone else wants to do it, then cool. (I do, after all, need to work on my other software.)

But one of the keys to this app is that there must be no copy-and-pasting of crash logs. It needs to be scriptable so that I can automatically add crash logs that come in via email or as files. If I have to spend any time getting things into the system, then it’s not worth it.

PS It would also do symbolicatifination for iPhone crashes.

Thank Willie Mays

Seattle P-I: “Hall of Fame center fielder Willie Mays, the man who inspired Ken Griffey Jr. that to wear the No. 24 as a Seattle Mariner, helped inspire Griffey Wednesday to return to Seattle.”

MarsEdit tip: shortcuts for weblog menu

MarsEdit weblog popup menu screenshot

In MarsEdit there are two weblogs I post to most often, and I don’t like pulling down the menu item via my mouse to choose the weblog. So, instead, I assigned them keyboard shortcuts: ctrl-1 for ranchero and ctrl-2 for inessential.

Saves a little time, makes me happy.

How I did it

I opened System Preferences, then clicked Keyboard & Mouse. Then clicked the Keyboard Shortcuts tab.

I clicked the + button, then chose MarsEdit from the list of apps. I entered ranchero for Menu Title, and gave it ctrl-1 for the Keyboard Shortcut. Then repeated that for inessential, but with ctrl-2 as the shortcut.

I didn’t even have to re-launch MarsEdit to make it work — though, if it doesn’t work for you, you might first try re-launching MarsEdit.

Notes

This was inspired by a similar tip for Mail — I use the same technique for choosing my From email account. (Since I have three email addresses.)

The cool curved-shadow in the screenshot above is done in Acorn via a script Gus made. Gus had first seen the effect in Cocoia's iLife ’09 UI Roundup, which is worth reading, if you haven’t already.

Python-based static website generators

Hyde is a static website generator written in Python. It uses Django templates. Could be cool. (Love the tag line: “we wants it. we needs it.”)

Hyde is based on Jekyll, naturally. Here’s the story of Hyde.

Also see Yaki, the Python-based system that runs Tao of Mac.

I love finding that the world of static website generators is way more alive than I’d realized.

Archive