Sun Nov 08 2009

AppHistory app idea

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.

Sat Oct 31 2009

Last day of NetNewsWire introductory pricing

In a nutshell: the price of the for-pay, ad-free versions of NetNewsWire for Macintosh and for iPhone will go up at midnight tonight. If you were thinking of buying, please don’t miss out. (Last day to save $5 on the Mac version and save $3 on the iPhone version.)

See the sale ends today post on ranchero.com for more detail.

Use the money you save to buy other cool iPhone apps! A few I recommend are Pickin’ Time, Postage, and Word Spin.

Thu Oct 29 2009

Vaccines

An interesting link on Daring Fireball today has me thinking about vaccines.

I’m still living with the effects of the chicken pox I had in third grade.

There was no vaccine then. Every kid just got it. It swept through school, and nobody tried too hard to prevent the spread, because every kid would get it, and it was better to get it when you were young.

It was just a thing. We thought we were modern because it was just chicken pox — not polio or smallpox or one of those scarier diseases that had been conquered.

But now there is a vaccine, and I wish like crazy there had been a vaccine when I was a kid.

I was nearly hospitalized — my Mom tells me I was within an hour or so of having to go the hospital when I could finally sip a few drops of water without vomiting.

I remember vomiting so much that the vomiting itself didn’t even bother me any more. I started crying out of frustration. Just when I started to feel a little better, a little cooler, and hungry and thirsty, I’d try the smallest sip of water, and whatever was left in me to come up would come back up. It just went on and on.

For days? I don’t know. It seemed like weeks of nights. Trying to sleep. Itchy, exhausted, unable. The screaming heat inside that wouldn’t end. Then the stomach convulsions.

I was told I had chicken pox not just on my skin but inside me, too. Could that be true? Was that possible? I still don’t know — but I didn’t question it, because it sure felt like it.

Of course I had chicken pox on my head. So I had pink hair — pink with the Calamine Lotion my Mom applied. The pink was mortifying to a third-grade boy.

A friend of my Mom’s, a woman from down the street, came by one day. (She was cool: she drove a white Corvette. Here’s one.) I can still feel the embarassment of my pink hair. The spots all over my face I could deal with: the pink hair was devastating.

I was finally able to drink water, and then I moved up to jello and then on to chicken noodle soup. I was able to sit at the dinner table and watch the network news. (ABC news broadcast from WPVI in Philadelphia.)

I got better. After about three weeks of the chicken pox, I could return to school, even though still slightly scarred. Prepared to be teased.

I was the smartest kid in the grade. I won every spelling bee. I got 100% test scores. I always had.

And though I was prepared to be teased for the visible remains of my chicken pox, I was not prepared to get in trouble with my teacher for cheating.

Cheating? Me? People cheated off me, not the other way around.

But I was looking at someone else’s paper. Because I couldn’t see the chalkboard anymore and I couldn’t read the questions to copy them down.

I kept getting in trouble, and I kept getting teased, and I was angry and hot-headed a whole bunch of the time. I started getting in trouble for accidents, and for things other kids had done. (Which wasn’t that new, actually: I was in trouble at school, or about to be and dreading it, most of the time as a kid.)

It was a few weeks before news got to my parents and they took me for an eye exam.

Chicken pox had ruined my eyesight.

So I got glasses, and that worked. But my vision, once gotten a head-start down that path, kept getting worse for a few years.

Though it pretty much stabilized while I was in high school, it got bad enough that it’s dangerous for me to walk around my own house with my contact lenses out.

I can tell you that my staircase has 16 steps. (Easy number for a programmer to remember!)

To read with my contacts out, I have to hold the book so close that I have to close one eye.

I can look down at my feet and not see the cat.

My parents were both near-sighted — they both got glasses in the eighth grade. Their eyesight is better than mine. Odds are I would have gotten glasses around the eighth grade too, and had eyesight about like theirs. Not great, but not terrible.

I wish, to this day, that there had been a chicken pox vaccine.

I later got shingles when I was 20. I won’t be surprised to get it again, but I sure hope not. Shingles hurts.

So I was out about three weeks from school. I hated school anyway.

But we were doing a special unit on the history of native Americans, which I thought would be pretty cool.

I missed some arts and crafts things — creating a diorama, carving a miniature dugout canoe out of Ivory soap. I was just as glad to miss that stuff, as I liked reading and writing better.

I also missed out learning about the history of native Americans, though I did pick up some later.

Which brings me back to the subject of vaccines. And, you know, I thought I was going to, but I don’t really need to state the obvious.

Wed Oct 14 2009

Code relationship between TapLynx and NetNewsWire

The code behind TapLynx and NetNewsWire for iPhone are similar — there is plenty of overlap — but they’re not the same.

Database engine

TapLynx is the engine I originally wrote for NetNewsWire 2 for iPhone. But then, in a decision that’s easily second-guessable, I wrote a new engine for NetNewsWire for iPhone. The TapLynx version is mature: the one in NetNewsWire for iPhone is much less mature.

TapLynx was originally an iPhone OS 2.x project: it uses SQLite (via FMDB) instead of Core Data. But when I went to write NetNewsWire 2, Core Data was newly-available on the iPhone, and I was convinced that it’s the future.

And it is the future, and I plan to switch TapLynx over to Core Data — but the code needs some more work first.

So, in a nutshell, NetNewsWire for iPhone is the more cutting-edge of the two apps in terms of code. But I’m fixing those cutting-edge bugs: and, once fixed, I believe the Core Data version will be great for TapLynx.

The syncing difference

Another big difference between TapLynx and NetNewsWire is how it reads feeds. NetNewsWire syncs with Google Reader; TapLynx reads feeds directly from the source. TapLynx doesn’t have to sync subscriptions or read states or starred items or anything like that.

Syncing and reading feeds directly are very, very different, and will get more so as I make NetNewsWire’s syncing more efficient.

TapLynx has it easy. :)

TapLynx 1.0

TapLynx is a framework for building media-based iPhone apps without needing to do any programming.

It’s a tool for developers, though — you still use Xcode to build the app. You configure it via a property list file, add artwork and feeds, build it, upload it. (You build a fully-native Cocoa app: it’s not like compiled Flash or something like that.)

Though programming isn’t required, you still can do some programming: a tab can have a custom view controller. An example case: you’re building an app for a sports team. TapLynx provides the news display, photo galleries, and audio and video. But you want a tab that shows scores and stats — that’s the tab that you write. But since TapLynx provides the other features, you can save time, make more money, and concentrate more on the part that makes your app special.

Some technical details

TapLynx is a static library. It’s a whole app in a static library. Since the views are things like UITableViews and UIWebViews, there’s no need for xib files. (I’m not anti-xib, by the way. But when a view is just a table — and it needs to be configured in code — a xib doesn’t make sense.)

The SDK provides a sample skeleton app that links to the library. The skeleton app has no code other than its main method.

The features, colors, feeds, and so on are all configured in a single property list file. Artwork is added to the Xcode project just as you would with any other project. There’s no black magic going on, in other words.

It’s 1.0

The future of TapLynx will be driven by the needs of developers. We can’t know in advance everything you’ll want and need, but we’ve had some experience building iPhone apps and we know what the basics are.

For instance, I’m sure you’ll need more programming hooks, ways to customize and add features via your own code. But I don’t know in advance what those will be. (The custom tab was obvious: the next step isn’t obvious.)

So we’ve set up a Google Group for TapLynx as a place for feedback. I’d love to hear what would help you make apps faster, make your clients happy, and make you money.

It’s also for web developers

We’ve seen people build apps who aren’t Cocoa developers — or who hardly ever even use a Mac, let alone Xcode.

We quite definitely had website agencies and web developers in mind. For example: when specifying a color, you just use the hex value, as in #48EF93. We were thinking of you. :)

My favorite feature: over-the-air updates

When we were working with All Things Digital on their app, they wanted to have the same kind of immediate control over the app as they have over their website.

Well, in the world of iPhone development, we all know there’s no such thing as immediate. (At this writing, I’ve had a crashing bug fix — a two-line change — for NetNewsWire for iPhone in review for 10 days now.)

We came up with this: the config file that you edit to create the app can also be hosted on the web. The app will read that config file periodically (a period you can configure). Whenever there’s a new config file, it will re-configure itself.

This way you can add and remove feeds, change look and feel, etc. You might add a tab for a special event (Olympics, election, winter weather, whatever) and take it down later. Or add a photo gallery.

It even downloads the necessary artwork.

So you don’t have to do an App Store update and hope it gets up in time for the special event.

(It can’t download code, though, since that’s against the developer agreement with Apple. New code requires a new build and uploading to the App Store.)

A sort of homecoming

You probably don’t know this, but my experience before NetNewsWire was six years at UserLand Software where I worked on tools for developers and web publishers. I was there during very exciting days, during the early days of weblogs, during the development of RSS, XML-RPC, and OPML. I’ve been working with this same technology ever since.

But I forgot, until recently, how much I love doing developer tools. They’re fun to make — yes, totally — but even more fun is working with the folks who use them. It’s been coming back to me, and it’s like coming back to a great place I thought I’d never see again. (And some of the same people are there!)

Twitter

Yes, you can follow TapLynx on Twitter.

Thu Jul 30 2009

NetNewsWire 3.2b6 - public beta

NetNewsWire in space

The public beta of NetNewsWire 3.2b6 is on nnwbeta.com. Includes Google Reader syncing, send to Instapaper, and a new app icon.

Anatomy of a feature

“Oh, it’s easy, just a quick http call. I could write a script to do it in like 20 seconds.”

I recently added a pretty easy feature to NetNewsWire — a Send to Instapaper command. (It will appear in 3.2.)

It really is just a quick http call to the Instapaper server to add a URL to the Read Later list.

Piece of cake.

But of course it’s not as simple as just writing a quick script. It’s tempting to think that adding a feature like this is just about adding the functionality — but there’s a bunch more to it than that.

Decisions

It’s not enough just to write the basic functionality and add a menu item that runs it. Even a feature as simple as this one requires some up-front thinking, some design.

Should it support multiple Instapaper accounts?

This would complicate the feature. Each time you post you’d have to choose the account (if you have more than one).

And we’d have to include some UI for creating, adding, deleting, and editing your Instapaper accounts, which would require a whole new screen, probably in the Preferences window.

I’m willing to bet that most people who use Instapaper use just one account, or at least are willing to use just one account when saving from NetNewsWire. So I decided that support for multiple accounts was not nearly worth it.

But!

While a person may have just one account, they might change that one account some day. So I had to have a way to change your Instapaper credentials. I already knew I’d have a menu item — I took the simple way of adding an alternate item (that appears when you hold down the option key) for switching your Instapaper account, so you can enter new credentials.

I don’t necessarily love this, because it can be hard to discover — and sure as shootin’ I’ll get questions about it, even if it’s in the Help book — but at least the capability would be there for the rare times it’s needed.

Should there be a toolbar item?

Tough call. I decided no for 3.2, but yes for 4.0.

Toolbar items need artwork, and artwork doesn’t grow on trees: they cost money and time, and I’m on a tight schedule.

But still, this was a tough one, because I know there are users who barely look at menus. If a command is not in the window, they won’t know about it. To make things worse, even if I made the send-to-Instapaper command a default member of the toolbar, anybody who’d previously customized their toolbar wouldn’t see it. And they wouldn’t necessarily think to check if the toolbar has any new items with the new release.

Discovery is always an issue. And there are two types of feedback:

“I don’t know why you put that in my face — I’ll never use it.”

And...

“I don’t know why you buried that feature!”

Should it work like syncing?

If you’re offline or the Instapaper server is down (not that I’ve heard of it going down), and you choose Send to Instapaper, what should happen?

If it works like syncing, then it would try to contact the server, but if it fails, it would remember and keep trying later until it succeeds. Even across runs of the app.

If I did that, I’d have to:

  • Add a persistent list (using a database, property list, Core Data, something) to remember URLs that need to be re-tried.

  • Add code that keeps trying to send items from the list.

More importantly, I’d have to deal with the following user experience:

  1. User does a send-to-Instapaper from within NetNewsWire.

  2. The call fails for some reason and is queued up, to be re-tried later.

  3. User goes to their Instapaper Read Later list and does not see the item they remember adding. User goes, “Whisky! Tango! Foxtrot!”; user is, quite rightly, less than happy.

There would have to be some kind of UI for dealing with this. It could be as easy as notifying the user that the call failed but would be re-tried — but, worse, I suspected that a way to view the queue would also be needed.

Which meant, probably, a new window with a table diplaying the queue, and another menu command to open the queue. And probably buttons for deleting items from the queue, and maybe a button to re-try all right away, and maybe some more info about the failures (the reason why the requests are queued). And there would probably have to be some indication in the main window that there are requests in the queue.

Totally not worth it.

The experience of most Instapaper users is with using a bookmarklet: they know that it won’t work if off-line, and they know that it tries once, right away. Given that, I could make it easy and do what current Instapaper users already expect: try the call, and if it fails, present an error message to the user.

How and when should credentials be entered?

The easy and obvious answer is to display a username and password sheet if you choose the command and haven’t entered credentials before. Because Instapaper has some special requirements, this couldn’t be a generic username/password sheet (one where I just update the text before displaying) — it needed its own sheet.

How should feedback be displayed?

This feature is different from the send-to-weblog, send-to-delicious, etc. features in that no more action is required after choosing the command. (Once you’ve entered credentials the first time, that is.)

Since NetNewsWire has a status bar, I decided that that’s the place for feedback: a spinning progress indicator and some “Sending to Instapaper...” text.

You’ll note that this got revisited later.

While thinking about all of the above, I actually wrote the simple little code that actually sends the URL to Instapaper. I barely remember doing it. It was a piece of cake.

What about sending multiple items at once?

My theory: anyone who needs to be able to send multiple items with one call is somebody who’s using Instapaper as storage rather than as a to-read-later list. I figured this wouldn’t be an issue for most people.

Consider the UI implications of partial success: say, for whatever reason, 3 out of 7 calls failed. How do you notify the user? It gets complicated and un-fun at this point.

So, no, just one item at a time.

On to the implementation...

After all this, “Now vee may perhaps to begin.”

Menu items

I put the Send to Instapaper menu item in the News menu, next to similar items. Added the alternate Switch Instapaper Account... menu item. I gave the menu item a keyboard shortcut.

The next step was to validate the menu item: it should be enabled only when there’s a single selected news item or an open web page.

But, of course, that’s not enough — there is also the issue of contextual menus. There are several contextual menus where it was added:

  • News items table.

  • News item description.

  • Tab.

  • Web page open in tab.

The actual server call

This part was the easy part. Just a quick NSURL* thing. Cake.

Error handling

There is more error handling code than the code to actually call the server. It’s necessary to handle random connection difficulties, 403 authentication errors, bad-request errors, and so on. Any time an app makes an http call, all kinds of things can go wrong.

For example, if the server returns a 403, then it’s necessary to ask the user for credentials. Even if they’ve entered them before.

Authentication

There’s a special authentication sheet for posting to Instapaper. And a special window controller just for that sheet. Again, there’s more code there than for the http call itself.

Even just the code to get and set the password in the keychain is longer than the actual http-call code.

Feedback

When I first sent this to private beta testers, they liked the feature, but thought it should have some kind of feedback.

Well, of course there was feedback — some text and a spinning progress indicator in the status bar. But, unsurprisingly, people didn’t notice it.

I thought to myself, “You know, 10 years ago, that would have been fine. It would have been the right thing to do, to use the status bar.”

And I wondered why that was no longer true. The answer, I think, is monitor size. With bigger displays people create bigger windows, and it’s much less likely they’ll notice something in the status bar, since the status bar is so much farther away from where their focus is.

I went back to the drawing board and did a little popup window. My first quick version just had the Instapaper icon and a spinning progress indicator. I figured I’d add some “Adding to Instapaper...” text of some kind to it.

The code behind the feedback window is, again, bigger than the http-call code. (By now you’ve gotten the idea that the core functionality of a feature is often the very smallest part.)

When I first saw the feedback window in action, it happened so quickly that I realized it doesn’t need a “Posting to Instapaper...” message on it. In fact, that would have been a bad idea, since it happens so quickly you don’t even have time to read any words. So I left it at just an icon and a spinning progress indicator.

A reasonable question you might ask: why not just use Growl?

Two reasons.

  • Not everyone has Growl.

  • You want feedback to appear immediately — you want to know that something is happening right away, and you want to see that it’s continuing to happen. You don’t want to wait for a Growl notification.

And it’s nice that the feedback is similar to how the send-to-Instapaper bookmarklet works, so it will feel familiar to Instapaper users.

Finally

Private testers eventually got the new version with the feedback window, and I don’t have any bug reports. But of course I do have feature requests to implement all the things I decided not to do or to leave for later. Plus more things — an entire Instapaper treatment, even, with the ability to see your reading lists in NetNewsWire and create groups and so on.

Applying the 80/20 rule means you will get feature requests from the 20. (And beta testers are often power users, and they’re more likely to want those extra powerful features.)

But, in the end, this was an easy and small feature.

Fri Jul 17 2009

On that moron feeling

Mac small business dinner Macworld Expo 2006I was a moron five years ago. Five months ago, even.

I’ve heard this from other programmers, so I don’t think I’m alone. They look back at old code they wrote and say, “What idiot wrote this crap?”

I used to wonder if this feeling would ever go away — as if I’d just get to the point where I’m super-awesome and that’s it.

But over the years I’ve learned to rely on this feeling. Were it ever to go away, then I’d be worried like hell. It would mean I’m not learning and not improving.

So, yes, I’m proud to have been such a moron so recently.

Get back to work...

I’m using Disqus for the comments system here. I moderate all comments. This is only the second comment I’ve turned down. (The first one was only semi-jerky.)

get back to work, fucking developer...

Archive

© 1995-2009 Brent Simmons