I’ve mentioned, and my co-workers have mentioned, that we used a plist file to specify numbers, colors, fonts, and so on for Vesper. We did it this way because I wanted my designers to have authority and control.
I didn’t want them to have to ask me to change a color, or nudge a button a few pixels, or change a font. I’d rather they do it themselves – but I didn’t want them to have to dig through the code.
One option, of course, would have been to use Interface Builder to do layouts and set properties. But so much of the app is dynamic that we ended up using xibs for the Credits screen only. And, frankly, Interface Builder is a bit difficult, and it doesn’t have slots for every value we needed to specify.
So, instead, I gave them a single plist — DB5.plist — to edit.
The great thing about this is that they could edit, build, see the results, and continue. They could iterate quickly, and they had just one file to deal with. Editing a plist isn’t pretty, but it’s easy.
The code behind this is quite simple. Anybody could have written it, and I’m sure lots of people have written things very similar. We claim no revolution here — but we do claim that this little tool is great for our workflow. It’s one of the reasons we were able to collaborate so well and make a good app in just a few months.
Reminder from Dave Winer: download your Google Reader subscriptions list before Monday.
For me personally it’s not an issue — I’ve been off Google Reader for a couple years. I even deleted my Google account.
My RSS reader has been NetNewsWire 3.3.2 for Mac (running without syncing) up till the other day when I switched to the NetNewsWire 4 beta (which doesn’t have sync yet).
I could get away without syncing for a couple reasons: I work at home and I’m almost always home; as I go through my feeds on my Mac I send articles to Instapaper and then read on my iPhone and iPad.
(Still, though, I would like to have a synced RSS reader on my iPhone and iPad. But I’m patient.)
I’m excited for the end of Google Reader, which I never liked as software or as a syncing system. (To be fair, it was never designed to be a syncing system.) It’s going to be a pain for a lot of people, and I recognize that. It sucks. But a revitalized RSS world is a very good thing, and that excites me.
My co-worker Dave writes about the tools he uses:
…sometimes the best hammer is a coffee mug.
He doesn’t mention Xcode, but one of the things I like about working with Dave is that he knows his way around Xcode. It’s Dave, not me, who handles getting builds to beta testers and uploading to the App Store. Dave adds his graphics to the project. He even changes the version number.
Yup, I’ve got it pretty easy.
I love this tweet by @BuildingTwenty:
MarsEdit - no iOS app
Glassboard - no Mac app
Vesper - iPhone only
NetNewsWire 4 - Mac only
Even a trace of @brentsimmons destroys sync.
It’s funny and true.
But it also illustrates an interesting change in what we mean when we talk about syncing.
Note that the tweet doesn’t really talk about syncing. It talks about multiple versions of an app, which is not the same thing.
Consider Glassboard. My then-co-workers at Sepia Labs did an excellent job with the backend, and syncing works wonderfully. But the non-existence of a Mac app is considered a sync bug, rather than a feature request for a Mac app.
Or consider MarsEdit, which downloads posts from your blog. That’s by far the most important part of sync for a blog editor (though I could understand wanting to sync your drafts).
But the lack of an iOS version of MarsEdit is considered a sync bug.
I’m fine with this. “Syncing” now means not just syncing itself but the creation of multiple versions of an app that sync.
(It can also mean that an app includes export formats and cloud backup. Cloud backups I get: that’s implicit. But export formats are yet a different thing.)
Vesper QA artist Nick Arnott writes:
The difference between a bad app and a good app is apparent to most. The difference between a good app and a great app is much more subtle. It’s the small details that 99% of users wouldn’t consciously notice were missing if they weren’t there.
For NetNewsWire nostalgists — I have three old sets on Flickr you might enjoy.
We haven’t seen the best days of feed readers, and if we aren’t careful, we might not. But if there is a saving grace, it’s that people who use feed readers use them heavily and don’t want to lose them.
My friends at Black Pixel have released an open beta for NetNewsWire 4 for Mac. It’s free during the beta period.
I downloaded it. I’m using it. I’m excited.
It’s weird to help test an app I used to work on — especially this app. But it’s fun.
Update: I bought it. It’s half-off, just $10, during the beta. No-brainer.
If you’ve checked out Vesper, you’ve noticed that the transition from timeline to detail (and back) isn’t a standard navigation controller transition. The detail doesn’t slide in from the right — instead, the detail view reveals itself as the other notes disappear.
(The same is true for detail-to-picture view and back.)
Though I’ve been writing iOS apps since before the App Store opened, I’d never done any animations like this. I had to figure it out.
Working on Vesper often makes me think of cartoons like Speed Racer that I loved when I was a kid.
(This is seemingly ironic. The Mach 5 is all about buttons and gimmicks, and Vesper is all about no buttons and no gimmicks. But it’s not really ironic because I want to capture the same feeling of cool that thrilled my 6-year-old self.)
When I started work on the full-screen animations, I started by lifting stuff up on the z axis and swapping in the next view controller’s view midway through the animation. This totally sucked. Completely. Terrible idea. Just the awfulest thing.
Then I remembered that one of the common escape plans in cartoons was the smokescreen. They’re firing sonic ray bazookas at us! Activate the smokescreen!
So I created
VSSmokescreenView. That’s the view where the animations take place. It gets placed at the highest point on the z axis, and the actual view controllers get swapped underneath.
I thought I’d invented something new — but I soon learned that everybody else has been doing it this way for years. Which is cool: it suggests that there’s a best practice and I wasn’t doing something weird.
Multiple Animation Blocks
A smokescreen view is easy enough to manage if you have one animation block. Add the view, run the animation, and remove the view on completion.
But Vesper’s transition animations have three blocks (in part because one block would have been too complex to manage).
For example, the timeline-to-detail animation has these blocks:
Animate the navbar changes.
Animate the table view away.
Animate the selected note + thumbnail to its detail-view version.
What’s more, these animation blocks could have different durations, and my designers could change those durations at any time without telling me, just by editing a plist. The shortest one could become longest, and so on.
So the problem was this: how does my code know when to remove the smokescreen view? In which of the three animation completion blocks should this happen?
I can think of a few ways to deal with this. None of them are lovely. Here’s the best one I came up with:
Reference Counted Smokescreen View
The smokescreen view has just two methods beyond its init method:
decrementUseCount. And there’s a read-only
Before each animation block, the view controller calls
incrementUseCount. In the completion handler for each animation block it calls
useCount returns to 0, then the smokescreen view is removed from the view hierarchy.
This is reasonably elegant, though I wouldn’t mind to learn of a better approach. (Let me know if you know of one.)
Too Much Information
If you’re used to using standard navigation controllers, you’re used to thinking of each view controller as a silo that exposes nothing about its internals.
Full-screen transition animations like this totally screw with that idea. Something has to do the animating, and that thing needs to know about both view controllers, which means those view controllers have to expose some information they wouldn’t normally expose.
The best thing I could think of was to expose what I needed as properties in the various view controllers, and use a comment to explain that they’re there for animation support only.
Sucky? Yeah, sucky. But way better than the alternative, which would have been to explain to my designers that I couldn’t do the animations because I’m too picky about what goes in my header files. (In plainer language: many Bothans died to bring you these animations.)
I’m a text guy. (See my earlier apps NetNewsWire, MarsEdit, and Glassboard.) Even simple addition and subtraction hurts my head. Rectangles vex me. (I don’t know logarithms from drumsticks.) (Which is something I intend to fix, by the way.)
But there’s no way out of dealing with geometry when doing these animations. Something at frame x needs to animate to frame y.
The first thing I learned was this: do not write redundant code to make the smokescreen view’s layout match. Instead, rely on
convertRect methods to convert from rects in a
UIView to rects in the smokescreen view.
Even this hurt my head sometimes. But it got better with practice.
One thing I kept repeating in the animations was taking a snapshot of the view-to-animate via
renderInContext. What I wanted in almost every case was a
UIImageView containing an image of the view.
This was an easy category method to write. Or two methods, actually: one to create a
UIImage snapshot of the view, and another to create a
UIImageView containing a snapshot image of the view.
There was one thing that made this just slightly more complex: sometimes the animation wanted a clear background and sometimes not. So there’s a
BOOL parameter on my category methods. (If
YES, it saves off the
opaque values, sets those to clear, calls
renderInContext, then restores those values.)
Once I got around to writing those category methods (which are simple) I was able to delete a bunch of foolishly-repeated code, which made the animation methods smaller and much easier to deal with.
It still bugs me how the animation code looks. It’s so awfully specific, and there’s too much of it.
Some of it is surely the nature of the problem. If you want to do something unique, you have to pay the price in code.
But it goes against the grain: I want it to be simpler and more general. I’ll keep at it.
Here’s a bug in Vesper. You can reproduce this easily.
Start dragging a note from right-to-left to archive it.
Before you let go, take another finger and tap the hamburgrabber button in the top left to open the sidebar.
Note that the sidebar opens and the note is still in a partially-dragged state. That shouldn’t be, but I didn’t think of it when I was writing the code.
You can figure out why the bug exists. When I’m writing a feature, I don’t necessarily think of all the interactions with all the other features. I try to, but it’s easy to get overly-focused.
It’s also easy to miss bugs that are hard to hit in the simulator. (I don’t know how to reproduce this bug in the simulator.)
Nick does excellent work.
Which means that when I’m busy and have a lot to do, I curse his name, the air he breathes, and everybody who’s ever been nice to him. I suspect his heart is black and terrible and full of hatred toward me personally.
Which is just to say, again: Nick does excellent work.
During my recent talk at AltWWDC, I was asked what makes a good QA person. I think I said, “Doggedness.” Which in my personal lexicon is high praise. (When I think about my own abilities, I know full well that they exist only because I keep chasing sticks and don’t ever stop, not out of any innate talent.)
Here’s the thing about Nick: I think he’s convinced that there’s another bug. And he’ll keep going till he finds it. And, once he finds it, he’s convinced that there’s another bug.
He uses multiple fingers (I like to imagine he has a severed hand he keeps warm just to use for this) and takes a phone call and notices every deranged pixel. Then he writes good bug reports with steps-to-reproduce, often with screen shots, sometimes even with video.
That’s what makes a good QA person. The best are macabre figures who delight in torturing developers, but then make up for it with the succinctness and precision of their bug reports.
I suspect there’s a reason that he chose to be @noir on Twitter.
The official line from Twitter is that RSS is “infrequently used today.” That’s the same justification that Google has given for shutting down Google Reader. It reminds of the joke about the shopkeeper responding to a request for something with “Oh, we don’t stock that — there’s no call for it. It’s funny though, you’re the fifth person to ask today.”
Nick Bradbury — my friend and former co-worker, now at Automattic — just released the last version of FeedDemon. It’s free.
Thanks, Nick, for writing such a cool app for so long.
Dave Wiskus wrote it up.
If you’re really good at what you do, it looks easy. But easy is tough to sell to clients, so we designers develop bad habits in order to make our work look impressive. Early on with Vesper, we realized that the existing design was okay, but felt cheap, like it was built using the same visual tricks everyone uses to make something look designed. As it happened, we were all heavily addicted to Letterpress, and we wondered aloud if that visual style might be where the puck was headed.
Vesper’s detail view is a UITextView. When the keyboard is down, URLs inside the UITextView are tappable.
I’d done just a little work with UITextView in the past. Though I’d seen UITextRange and UITextPosition in the headers, I had no idea how these things worked. So I figured it out.
Still to do: figure out how to highlight the link on tap.
Small Picture’s Fargo 0.8 connects outlines and blogging. An outline can be an entire website.
Small Picture is Dave Winer and Kyle Shank. Occasionally other iOS and Mac developers ask me if they should follow what Dave is working on. The answer is yes.
Dave has been a big part of some big things, some of which I’m sure you love: outlining, inter-application communication on Macs, blogging, RSS and OPML, and inter-application communication over the web.
And he’s always been a voice for freedom, for openness over lock-in, for a human and humane web.
I used to work at UserLand Software, which was Dave’s company in the ’90s and early 2000s. And I quite frequently had no idea where he was going with something. It took me a couple years to be interested in RSS! But I knew enough to pay attention and give the technology time to mature — and to give myself time to understand it.
If you’re like me, a Mac and iOS developer, right now you’re thinking about iOS 7 and OS X Mavericks. You’re figuring out how to make a living on the various App Stores. You’re watching the WWDC videos and wondering what cool new things you can do.
And you might look at Fargo and not know right off the bat how it’s going to change the world or even be relevant to what you’re doing. I don’t know either — yet. Which is totally fine. I’m going to pay attention and let it sink in, and you should too.
I’ll put it another way. I can take a good idea and make a nice app, but Dave can make a good idea.
While we don’t plan to switch, I do recommend checking it out if you’re looking for a bug tracker. (It has an API.)
Here are the slides for my talk at AltWWDC as a PDF.
The title: How I Made Vesper. Once there’s a link to the video for my talk, I’ll post that.
AltWWDC was such a cool thing. Many thanks to Judy and Mike and all the volunteers and speakers.
Check out objc.io. Looks great.
I’ve Instapaper-ed every article, so I have something to read while folks who have WWDC tickets are attending sessions.
If I had one feature request, it would be an RSS feed for the site.
Since I’m always interested in hearing what other teams use to work together and ship their software, I figure I should list what we use to work together on Vesper.
To swim with the current these days is to use git. But I like Mercurial better — and I think Mercurial is to Macintosh as git is to Windows. That’s probably not fair or rational, but it doesn’t really matter, since both git and Mercurial are excellent systems.
Along with Mercurial we use Bitbucket. I rarely had to log in to the site — which is as it should be. It just worked.
All of us use Mercurial on the command line.
Almost all of our company communication is via Glassboard. We’ve sent just a few emails and a few more text messages — but mostly it’s been Glassboard.
(This is the second app I’ve shipped with the aide of Glassboard. The first was Glassboard itself.)
In the past, before Glassboard, we would have used a discussion list because it’s valuable when testers are able to discuss things with us and each other. It becomes collaborative, and it makes for better software.
My first experience with this model goes back to my days at UserLand Software in the ’90s when we had a testers mailing list for Frontier. It was so productive, and so much fun, that I’ve used this same model for all of my subsequent apps.
Lighthouse bills itself as “beautifully simple issue tracking,” and to its credit I’m not sure what else there is to say. It’s a bug tracker. It looks nice. It’s easy to use. It works well.
We made heavy use of the milestones feature. We tend to tag tickets. We don’t order tickets by priority. (My internal algorithm defeats priorities. When there isn’t a clear choice, I pick based on how long it is till dinner, whether or not I’m tired, what I just completed, and what mood I’m in.)
In the last few weeks of the project, I measured progress by calculating how many tickets we’d have to close per day. If that number kept going up, then hitting our ship date was at risk. (We hit our date.) (After revising our early naive schedule.)
We use HockeyApp to distribute builds to testers. My favorite HockeyApp feature: symbolicated crash logs. My second-favorite feature: email notifications when there’s a crash.
In the past I’ve used TestFlight, which I also like very much. Both are an incredible improvement over the old days of passing around .ipa files and provisioning profiles.
Local hero Doug Russell worked on accessibility for Vesper — and wrote it up on his (aptly-named) Taking Notes blog.
I’m especially proud of the work my co-workers Dave Wiskus and John Gruber did. I had the privilege and fun of making their designs real.
I started working on it in early February. John and Dave had a head-start on the design. It’s been an intense several months of coding and iteration, and I’m really happy to be able to present it to you now.
Of all the software I’ve ever made, just two were lovable from the moment I started writing code. This is one of them.