November 2009

The air smells richly of lavender and venison. There’s a peregrine falcon perched on my left shoulder.

The bonfire in the closet, now on its 1,019th day, shows no signs of burning out.

I can hear, but faintly, the screams, shrieks, lamentations, and phone calls of the damned coming up through the hot air register.

The at-one-time category-five filing-cabinet hurricane has been downgraded all the way to topical storm.

The resident family of ceiling chipmunks is behind on their rent. Freeloaders.

My assistant Igor is wearing leather footie pajamas, even though I keep it at a comfortable 98.6 in here. Just looking at him steams my feathers.

While he stirs a giant vat of chicken noodle soup that I’ve been aging for a fortnight, I’m hunched over NetNewsWire, trying not slice myself with my surgical instruments, wondering if that one finger will grow back quickly, wondering if I can go out in public with this new third eye.

This is counter-intuitive, so I don’t think most users of software understand it.

Picture a situation like this: an app crashes every time you click a certain button. What does that say?

Well, a crash is a very bad thing, so it probably means a great deal of effort to fix it. It seems like there should be a relationship between the badness of a result and the time it would take to fix it.

But there isn’t. Not necessarily, at least.

A crash can be the simple result of a single missing or mis-placed character. (A very embarrassing crash in NetNewsWire 3.2 was the result of a missing :. I think 3.2.1 differed from 3.2 only in that it added that : at the right place.)

There’s another level of non-linearity: just because a fix is really, really, easy to implement (such as just adding a : at the right place) doesn’t mean the level of effort is small. It may take a week to find exactly what the problem is. Once figured out, it may take 3 seconds to fix it.

Or… not. It may take only seconds to figure out the problem, and just a few more to fix it. Sometimes a crash log and a peek at the code are all that’s required. Sometimes the worst, most obviously bad results have the quickest find-and-fix time. Sometimes.

What had me thinking about this was some coding I did over the weekend.

In a new operation (not in the current shipping version), I noted the app was allocating about 100MB of RAM, for something that should never have gone above about 50K or so.

About 10 minutes later I had it down to 4MB.

But I still need to get it down to about 50K — I still need to shave off about 4MB.

If it took 10 minutes to reduce memory usage by 96MB, then — were there a linear relationship — it should take under half a minute, less than 30 seconds, to go the rest of the way.

That’s the way things work in the real world, after all. If you have 100 bags of leaves to carry out to the curb, each bag will take about the same amount of time as the others.

Instead, it will probably take me about two hours, maybe more, to get rid of that last 4MB.

It’s almost as if you carried out 96 bags of leaves easily and quickly, then realized you can’t get those last four bags, even though they’re exactly the same as all the others, without pouring a new driveway first.

Which is crazy, right? If the real world operated like that all the time, we’d go completely nuts.

Anyway. Enough rambling.

Now it’s time to do a prime number of handstands, then touch all the walls of my office (twice) with the index finger of my left hand, then iron my tinfoil hat, then get back to programming.

The idea behind the lecture was to talk about what makes a great Mac app. I took that as an excuse to talk about everything from work habits to UI to marketing. In other words, I threw in just about everything I know — which, it turns out, only takes about an hour to deliver. :)

It goes chronologically — getting to 1.0, releasing 1.0 and the follow-through, on to working on 2.0.

I don’t actually have time right now to write it up properly. But, at least, here are my notes:

Road to 1.0

More money to make in Mac software than in iPhone software

Mission statement
Photoshop example

Work habits

stay in the chair
will have to give up things - games
exercise is very good for brain and morale

motivation - gumption
think of thing you want, rationalize that this is how you get it
fear is good too

nearby small notebook works as short-term memory and to-do lists
break tasks down real small

Design

keep 1.0 feature list very, very small
polish the hell out of those features
you don’t really know what users will ask for

Pretend you’re a toy-maker - Kris Kringle
Delight your users
Peacock feathers
Do lots with one click
The extra step to make things easy
Feedback - animations - never “what just happened?”
Performance is UI
Stability is job #1
Look at lots of other apps, esp. by those you admire, but also look at apps that don’t work as well
Coherency of UI
Going beyond the merely utilitarian means you understand the human spirit - and your app is more usable and thus more useful

Sketch out UI
Use Acorn or whatever to do actual mockups
Cabel Sasser working on Coda

Shoot for ADAs and Eddys - by that I mean: don’t pander, just aim high
wwad
wwpd

Code

unit tests
version control
bug tracker

Support latest OS, not OS minus one, on major releases
use latest technologies
Multi-threading only if you have to
AppleScript support might make sense

don’t fight frameworks
learn the Cocoa way
Don’t subclass very much, at least not beyond one level
Don’t waste time on wrappers
Don’t over-use categories
Pretend someone else who knows Cocoa will use your code

architecture is important
write it down

Error checking – with recovery when possible
Especially important if works with cloud

Use Sparkle
Use Growl

Beta testing

Hallway UI testing – wife, husband, kid, cat

don’t do public betas
get beta testers
remember they’re geeky

Have crash logs sent back to you

Use Shark and Instruments

Random testing

Charge enough money for your app: $19.95 usually a minimum

File bugs with Apple

1.0 Release and marketing

listening to users
remember that people who actually submit request may, on average, be slightly geekier than the entire population
Good stories are important
never panic and add a feature
Use Twitter - for you and for product
Have forums or mailing list or something
Have weblog - point to other cool stuff, not just yours
Be human
There will always be complaints. Pretend to yourself that you have a thick skin.
Don’t make promises before shipping
Keyword searches for your app

Give back to dev community if possible
Other developers also have influence
Go to WWDC etc.
Read developers weblogs

Let world know what you’re working on in general - don’t need details

Take the long view

2.0 and up

it’s okay to have users wanting more
it’s okay to bring your users along - make simple things a little more complex later on

Some great-seeming architectures are hard to remember and understand
Don’t be afraid to re-architect

remove features

Keep learning

I will make mistakes, sometimes a series of them. You will make mistakes. And some of what I’ve said is wrong, or wrong for you or your app.

I’ve often wished I had a little app that just tracks the history of apps I write. On what day was Whatever.app 2.0.3 released? On what day was MyiPhoneApp 3.0 sent to the App Store for review? On what day was it approved? Etc.

I don’t keep track of these things too well, but I always mean to. Seems like it might make a nice little app. There would be standard actions (initial beta, released, uploaded, appeared on App Store). Maybe add things like URLs to reviews on the web, so you could go back to them later. Maybe have a free text option too, or the ability to define events. (Don’t forget an awarded event: Macworld Eddy and ADA have to be pre-defined types.)

It would know the platform for each app (Mac or iPhone and so on) — and probably save minimum system requirements too, so I could find out, for instance, when the last Tiger-compatible version of SomeMacApp.app was released. If a given release has a permanent download URL, it would store that.

Since it would be competing with any calendar — or any text editor, or something like Bento — it would probably have to be free. More of a get-your-name noticed thing.

The thing is, I do have to refer back to this information more often than I expect. So I usually end up just looking through ranchero.com to see when I announced whatever-it-is. But not every piece of info I might want is there, and it’s a pain anyway.

For bonus points: graphing, timelines, and export-to-web. And it would have to let me go back through history and add events from the past.

(For the record: I’d pay money for this app, if done well, of course. But I don’t think it’s a money-maker in general, which is why I recommend it as a free app, as a reputation-maker.)

Update 2:15 pm: When you do a release, it should congratulate you in some delightful but not too time-consuming way. A fun little animation or something. The amount of fireworks (or whatever) in the congratulation should depend on the version: 4.0 is a big deal, while 4.1 is less of a big deal, and 4.1.1 is a small deal (but still worthy of congratulations). (Similar for awards. Heck, it could even be smart about things like how many mice in a Macworld review. Any 4-mouse-or-higher review is worth a song-and-dance. Same with appearing in the top-selling apps in the App Store.)

The question every app has to ask itself these days: what’s the Twitter integration? Here’s an answer: how about none. It’s just for personal use. (I’m not knocking Twitter: I’m just saying that not every app has to be able to tweet.)

Update 2:30 pm: I’d also want to store change notes — quick highlights and long version — for each release too, so I could easily refer back. When did Whatever.app get that one cool feature? The whole mess of data would have to be searchable, naturally.

It would possibly display the app icon next to each entry for an app. But it would have to be smart about this — icons change. I’d want the icon for 1.0 to display with 1.0 entries and the icon for 2.0 to display with 2.0 entries, etc.

It might also let me add screenshots whenever, so I have a memory of how things looked at a given moment in time.