OmniFocus for Mac 2.2.5

It just came out on the Omni site, and will be on the Mac App Store once approved. It fixes a couple crashes — including one that I called The Last of the Big Crashes.

When I started working on OmniFocus last year, there was a set of the most common crashes and a set of crashes that were hit pretty rarely. So we fixed a bunch of crashing bugs — the most-common crashes and others — until we’re down to the rare crashes.

(If you read the release notes going back to 2.1, you’ll see crash bug fixes in almost every release. Sometimes a bunch of them.)

I’ve often wondered if fixing crashing bugs leads to a more-successful app. It’s the right thing to do, regardless, so we do it. (In fact, I have to stop myself from being too obsessed with fixing crashes.)

But does that translate to more sales? Intuition tells me it does, since people using a trial version are less likely to hit a crash, and they’ll be more likely to buy the app. And people who have bought the app are less likely to hit a crash, and they’ll be happier with the app, and therefore more likely to tell friends, co-workers, and family about the app.

I would love to be able to tell developers unequivocally that fixing crashing bugs is good for the bottom line. But I can’t. I can only say it maybe helps — and then just appeal to our sense of professionalism. Fixing crashing bugs is the right thing to do. Period.

But, yeah, nobody tweets about how stable your app was today.

* * *

The specific Last of the Big Crashes in 2.2.5 was this: an NSOutlineView had unsafe references to deallocated objects, and then calling itemAtRow: crashed. The solution was to make sure those objects would get deallocated afterward, not before, calling itemAtRow:.

(That sounds simple, but going from the crash logs to understanding the problem to figuring out the best way to fix it was anything but simple. There was even a period of an hour or two of staring at assembly code.)

(Of course we couldn’t reproduce it — not until we got some anonymized databases that people were kind enough to send in. We get great help from OmniFocus users.)

Swift Book Club Book?

My co-worker Curt Clifton writes:

I’d like to start a “bike shedding” club. One problem a week, everybody implements a solution in Swift. Get together and compare approaches.

Anybody have a good source of sample problems? Project Euler is probably too mathy. Maybe a data structures book?

This would be for programmers at Omni, so think of the kinds of problems that people writing large Mac and iOS productivity apps need to solve.

(And reply to Curt on Twitter if you have a good idea. Thanks!)

Swift Diary #13: The Addiction

I’m at the point with Swift where I get on a roll sometimes. That’s when it gets fun.

* * *

I know the saying that programming isn’t typing — it’s thinking, and with autocompletion these days it really doesn’t matter how much typing a language requires.

Except that that’s not entirely true. Programming is also typing.

Or, put another way: a whole bunch of programming is housekeeping. And, for the most part, Objective-C requires a lot more housekeeping than Swift does. You end up with longer lines, twice the amount of files to maintain, imports to manage, types to type, and so on.

With Swift you get more logic per page with less effort.

* * *

I’m doing my best to understand exactly what sculptures come from this new type of rock. I design like an Objective-C programmer, but I’m learning how to design like a Swift programmer.

I do still wish for things — especially, 1) the ability to treat objects that conform to the same protocol as the same type, and 2) something like KVC.

* * *

But here’s what happens now. Sometimes I go to write some Objective-C code and I sigh at the effort — because I know the Swift version is half as long. I sigh at jumping to the top of the file and adding an import, and I sigh at switching to the .h file and adding a method.

Part of me still wishes that Swift had been something like a cross between Objective-C and Ruby. I wanted a concise, expressive, and dynamic scripting language where I could be massively productive. Instead I got a concise and expressive programming language that’s less dynamic than I’d like — but where I could still be substantially more productive (once I learn it) than in Objective-C.

And that’s where I am now — starting to feel that boost in productivity with Swift, and getting a little bit addicted to it.

On Scripting

Graham Lee writes of The death of scripting and The paradox of scripting.

But how can scripting be dead? There’s bash, and powershell, and ruby, and…even Perl is still popular among sysadmins. There’s never been a better time to be a programmer or other IT professional trying to automate a task.

True, but there’s never been a worse time for someone who doesn’t care about computers to use a computer to automate a task. Apps are in-your-face “experiences” to be “used”, and for the most part can’t be glued together.

There are counter-examples, of course — the apps I work on (Mac versions of OmniFocus and OmniOutliner) are highly scriptable. But the trend toward silos, sandboxing, and highly-controlled experiences is clear.

(First thing I did was look to see if Slack has a scripting dictionary. Of course not. Neither does HipChat. Apps these days.)

If you’re thinking about adding AppleScript support to your app, read these articles from last year:

Making Your Mac App’s Data Scriptable

Scripting from a Sandbox

In the first of these, I write:

When adding AppleScript support — which is also JavaScript support, as of OS X 10.10 — it’s best to start with your app’s data. Scripting isn’t a matter of automating button clicks; it’s about exposing the model layer to people who could use your app in their workflows.

While that’s usually a small minority of users, they’re power users — the kind of people who recommend apps to friends and family. They blog and tweet about apps, and people listen to them. They can be your app’s biggest evangelists.

Overall, the best reason to add scripting support is that it’s a matter of professionalism. But it doesn’t hurt that the effort is worth the reward.

OmniDev Blog

At Omni we started a new blog. (With an RSS feed.)

I wrote an article: Making Tab-Switching and Scrolling Faster in OmniFocus for Mac.

And Tim Ekl has written the first two parts of a series on building push-triggered sync:

Building Push-Triggered Sync, Part One: Choosing a Language

Building Push-Triggered Sync, Part Two: First Steps

Whistle-whetter: we’re using Go. Read all about it.

PS I’ve been on my yearly beach vacation. Back now.

Swift Diary #12: The P Word

Guy English writes a Swift Protocol Proposal. It’s worth reading the Twitter discussion.

Wooji Juice disagrees, and writes about the genius of Swift protocols.

Daniel Jalkut writes about The Seven Stages of Swift. I think I’m inhabiting several of them at once.

* * *

I’ll try to re-state my issue with protocols again in a simple way.

I’m writing a Finder replacement, let’s say. The UI has folders and files. There’s a Folder class and a File class. They’re quite different things, so there’s no class inheritance.

I want to represent the file system internally as a tree of Folders and Files — let’s say I want to use Sets. A Folder has a children property, which is a Set that contains both Folders and Files.

I want Folder and File both to have a writable name property so the UI can edit their names.

Something like this ought to come naturally and easily to a language, or else that language is not helping me write apps.

This isn’t some weird, made-up situation. It’s super-common. Look at Mail’s sidebar, for instance — there are a bunch of different things. (Or look at Xcode’s sidebar.)

Yes. There are ways to deal with this in Swift, including using @objc protocols and collections. Or proxy objects or base classes (ugh) or whatever.

But the most natural way is protocols.

If my point was just to get my work done and ship a great app as soon as possible, I wouldn’t be using Swift. I’d be using what I know: Objective-C.

But I’m also taking the opportunity to learn Swift, and the best way to really understand it is to use, as much as possible, pure Swift, rather than Swift-with-objc. And if, along the way, I run into questions or things that don’t help me write high-quality apps more quickly, then I’ll ask questions and even criticize when warranted.

My hope (and belief) is that the language designers take the feedback in the spirit intended. I want to help make Swift a great language for writing apps.

The designers may not give me what I want — it’s possible that I’m just asking for a faster horse, and they’re delivering a Model T, after all — but feedback from experienced app-writers ought to warrant attention. (Which I think it gets, which makes me glad.)

Swift Diary Page

I collected my recent articles on working with Swift on a single page. It’s linked-to at the bottom of every page on the site, so you can find it later.

People Were Quite Rightly Outraged at Me

In 1990 I was an editor of the weekly college newspaper at Seattle Central Community College. Each week we printed a comic strip drawn by a student.

The strip — “Red Ruffensor,” as in red, rough, ‘n’ sore — was a liberal satire of action hero comics. It was community college student work, but pretty good for that.

We were criticized, though, for not including anyone but white men and women in the strip. The position of the cartoonist was that this was a satire of a genre that doesn’t include anyone but white men and women (mostly men), and that to include anyone else would actually be mean. (Every character in the strip was a jerk.) So he didn’t.

Until, under continuing pressure, he changed his mind.

One day, the last panel of one of the strips included a character with stereotypical and exaggerated Asian features, and a speech bubble: “Me finally get a line!”

Awful, right? It fit, though, because the whole point of the strip was that action hero comics are homophobic and racist and sexist (and yet homoerotic), and this was a liberal college that, we thought, got it.

I was 21 years old. I okayed it. It ran.

This became a huge (but localized) controversy. Seattle newspapers wrote it up, and some people (though not me) discussed it on 1090 talk radio. There were numerous discussions at school, and afterward the newspaper staff attended sensitivity training.

What my 21-year-old self didn’t get was that that last panel was mean-spirited, even if, to our young minds, it made sense. The integrity of the comic as satirical speech would not have been harmed by leaving it out — and, even if it would have been, would that have been so important? (No. Consider the context.)

I don’t remember if I apologized then or stuck to my guns. At any rate, now I say: I apologize. I’m sorry for running that. I should not have. It was wrong.

* * *

If I had the ability to send myself a message back in time, I would send myself a message to before the cartoonist wrote that panel. I would tell myself how to deal with the pressure to make the strip more inclusive.

Here’s what I’d write:

Dear Brent,

Hi. I’m 47 years old now. Life is good. You’re still sitting in front of a Mac.

I hear — actually, I remember — that you’re under a whole lot of pressure to make Red Ruffensor inclusive.

Well, thing one: you, young man, have no idea what real pressure is yet. But I remember how this felt, and you need some advice. Luckily, this isn’t that hard.

The solution is, in part, the same solution you’ve always used and always will use: start writing.

Step one:

Write an editorial explaining the comic — it won’t be hurt by explaining that it’s satirical, and that everyone in the strip is awful, and it’s all about pointing out the homophobia (and latent homosexuality) of action hero comics. Let people know that Red Ruffensor actually means “red, rough, ‘n’ sore” — because I guarantee you that they don’t know.

Let people know that, in this particular comic, inclusiveness is a bad idea. Explain that the cartoonist is throwing punches — haymakers — at everybody in the strip.

Also write that the paper is committed to inclusiveness, and so you’re looking for more student cartoonists. And if anyone reading this might be that cartoonist, please get in touch!

And make a pledge: no Red Ruffensor in a given week unless there’s at least one other strip to run.

Step two:

Actually find another cartoonist. Or more than one. And run their work, and write an editorial that first week introducing the new strip (or strips), and thank the people who asked that the paper be inclusive, since it’s now better for it.

That’s it. Pretty easy. Be good!

Regards, your pal,

Swift Diary #11: Objective-Swift

My main problems with Swift are:

  • Collections of protocol-conforming objects don’t work as I need them to.

  • No KVC.

  • No equivalent of NSClassFromString.

Now, these aren’t really problems with Swift — they’re problems with pure Swift.

But there’s no such thing as a pure Swift app. The frameworks are Objective-C frameworks. You can’t load nibs without Objective-C.

Given that, I made the pragmatic decision to start using @objc protocols, classes, and collection types where those things make sense, where Swift fought against my design.

And suddenly the language is a joy to use. It’s like Objective-C but with type inference, no .h files, fewer imports, shorter syntax — and I get the things I was missing.

I’m still not sure I like optionals, and there’s more casting than I’d like, but overall it feels like Objective-C with less housekeeping. In this language — I’ll call it Objective-Swift — I can go fast.

* * *

More about optionals…

For those who don’t know Objective-C: it’s based on message passing, and sending a message to a nil receiver is fine. It just doesn’t do anything. If it has a return type, it returns nil. (Roughly speaking.)

In other words: say foo is nil. The following in Objective-C is a-okay — nothing happens when foo is nil:

[foo doSomething:someArgument];

The Objective-C syntax is weird to everyone who isn’t used to it, I’ll grant. The above could be expressed in another language as foo.doSomething(someArgument)

What’s cool about this is that you can do nil-checking less often. Say you call a method that returns an object or returns nil. If it returns an object, you want to tell that object to do something, or you want to get one of its properties — or you want nothing to happen if the object is nil.

You can just skip the nil check and write your code as if the object isn’t nil.

I’ve relied on that behavior thousands of times. As an Objective-C developer it’s second nature.

There are obvious problems with that, though. One is that it’s not clear at all in the code that the object may be nil and nothing’s happening and it’s okay (it’s by design). Someone reading it — including future me — may not realize it, and it may be important.

The second, and related, problem is that nil as an argument rather than as a receiver is a completely different story. Plenty of methods will crash if you pass nil as an argument. So it’s not true that Objective-C code is free of nil-checking.

Along comes optionals in Swift, which make it clear when a thing may or may not be nil. When a variable is defined as optional, and you want to do something with it, you have to handle the nil case, and that’s enforced by the compiler.

That’s good — very good, in fact — except for all those times when I’m bugged because I have to satisfy the compiler when I feel like I shouldn’t have to, when years of experience tell me it’s quite okay to ignore the possibility of nil.

So I’m of two minds on optionals. Like many other things with Swift, I don’t really care about it for code that’s entirely mine — because I know my own style so well, because I know what mistakes I make and don’t make — but I do care about it for code that will have many authors.

Swift Diary #10: Changes to Properties

Both of the apps I’m working on have a custom persistence engine (built on top of FMDB and SQLite). Core Data isn’t a great fit for these apps. (This isn’t me being contrary. I’m doing very database-y stuff, and Core Data is an object persistence system, not a database. Seriously: you should use Core Data.)

The model objects are pure Swift objects. And I’d like to borrow one of Core Data’s awesome features: when a property is set on an object, the persistence system should get notified. It will record the change, then coalesce and queue updates to the database.

* * *

Let’s say I’m writing a Twitter client. (This an example used for historical reasons — because, if you look at history, you’ll find that people used to write Twitter clients — and should not be taken as indicative.)

Let’s pretend it has a Tweet class, a pure Swift class, with about 20 properties (some from the server, some local) — and setting any one of those should trigger the persistence system to do its thing.

I can do what I want if I add a didSet code block to each property. One of the cool things is that didSet is ignored during init, which means I can initialize an object with data without didSet getting called and triggering an unnecessary database update.

Each didSet block looks like a variation on this:

recordPropertyChange(self, key: "somePropertyName", newValue: somePropertyName)

It’s a pain to do this for every single property in every single class that’s database-backed.

* * *

Were this Objective-C, the situation would be fairly easily dealt with via dynamic method resolution. Each property would be marked as @dynamic, and methods that do the right thing (update in-memory storage and notify the persistence system) would be provided at runtime.

That’s not available to pure Swift classes, though.

I could ask for that feature — but it had me thinking that there might be a better feature request to make. Classes could optionally (perhaps when conforming to a PropertyObserver protocol) implement a class method that gets notified when any property changes in the same circumstances where it would call didSet. (It should still call didSet, when it’s there.)

Something like:

class func didSetProperty<T, U>(object: T, key: String, newValue: U) {
  recordPropertyChange​(object, key: key, newValue: newValue)

(I’m totally unsure that the above is the right way to express this. Maybe object should be Self? I’m still learning my way around generics and protocols.)

If there already is a way to solve this, and I don’t need to make this feature request, then I’m keen to hear the solution. It would be useful.


Ads via The Deck