Facebook, Notifications, and Email Hacking

Recently the Facebook iPhone App added support for delivering push notifications. They are fantastic.

This is the perfect use case for push notifications, because there is a fundamental difference between a “notification” and a “message.” A message is something I usually have to act on. A notification is just an “oh, by the way…”

Here’s the problem with confusing the two:

OK Facebook, I get it. People are doing things on Facebook. Thanks!

Sending notifications through email is basically hacking the email system. I certainly want to know when Bob comments on my status, but I don’t want that information in what is basically a throwaway email. Email is designed for messages.

Now that I have push notifications, I can finally stop this constant emailing. Can’t I?

Sounds easy! Let’s just click that (awesomely obfuscated) link and I’m sure we’ll find a simple checkbox to turn off the oh my god

OK, deep breath. I can do this.

Do I want an email when someone “Sends me a message?” Well, yes, of course, that’s what email is for. Check.

Do I want an email when someone “Adds me as a friend?” OK, probably, this doesn’t happen very often anymore since everyone I ever knew growing up is accounted for. Check.

Do I want an email when someone “Posts on my Wall?” Hm. Well, now I have to think back to the sorts of things that people post on my wall. Sometimes it’s “Let’s get lunch today!” Other times it’s just fluff. I guess I should probably leave it on? Check.

No wait. I’m not actually making any progress here; I thought I came here to turn off email notifications? Everything just seems so important on this page…I mean, they wouldn’t give you so many options all at once if it wasn’t really necessary right?

What this page is, is basically a huge UI cop-out. They created it such that when you yell at them about spamming your inbox, they can direct you here and say “look, you have complete control over what we send you; this is your problem.”

I would much prefer that Facebook take a stand and make these decisions for me, for everyone, about what’s important and what’s not. What this page should look like is:

Notification Settings

Email me when friends send me messages
Email me about activity involving me
Show detailed options

And, of course, there will be cases where you’ll want to block very specific things, but Facebook already does a superb job of exposing that elsewhere, for instance on your newsfeed. You can silence particular apps (cough mafia wars), block people, whatever. And the UI for that appears right when you need it.

Just kidding Drew, you’re my boy, dawg.

There, I fixed Xcode—You’re Welcome.

Download xcode-auto-assistant now

In my last installment, I discussed Xcode’s frustrating implementation of code completion.

I’ve now taken matters into my own hands.

It turns out Xcode has an (undocumented) plugin system. And it also turns out that this guy created a really fantastic plugin for Xcode that automatically inserts a matching opening bracket ‘[’ when typing the closing bracket ‘]’.

Now, it turns out Apple added this bracket-insertion feature on their own, possibly being inspired by this, so the plugin is now just reference material.

Really useful reference material for doing what I want to do.

I’ll save the nitty-gritty details of how the plugin works for a later post (or just browse the source). Let’s just say that we have access to keystrokes as you type them in Xcode. How would we use that to achieve automatic completion list display?

Take 1: Popup all the time!

The most useful behavior, it seems, is for the popup list to appear as soon as you type a reasonable character that can be completed, such as an alphabetical character. Here we’ll type ‘u’ because we want UIViewController.

So that’s the first thing I implemented. Listen for alphabetical character, popup the list.

The problem turns out to be that the list takes “a while” to appear, because we’re in Objective-C which is still C and the number of legal symbols you can type in a particular location is immense. I mean look at that tiny scrollbar! There’s all manner of detritus in there like u_quad_t and UIKIT_STATIC_INLINE.

You might think, no problem, I’ll just ignore the popup and keep typing because the list will narrow itself down as I go. But, in practice, it turns out to be extremely annoying because you can’t type small words like “if” and “for” without the popup list slowing you down.

Examine our options

I imagine that Apple encountered this same problem, and it seems the way they addressed it was by analyzing the number of items that would match and only giving you a suggested completion if the number of possible matches is small.

This is why, with Apple’s completion, you must type “nss” before it will automatically suggest something like “NSString”. If you just type “ns” you can sit there forever and it’ll never suggest anything. But if you type “cl” it might suggest “CLLocation” because there aren’t a lot of other things starting with “cl”.

My beef with this approach is that it’s unpredictable. How do I know how many letters I’m supposed to type before I can press enter and move on?

Take 2: Smart delay

The solution turned out to be surprisingly simple. Display the list after typing any alphanumeric character, but with a delay proportional to the number of characters in the word entered thus far. On the 4th character and beyond, the list always appears immediately.

This way you can type “uivi[enter]as fast as possible and you get UIViewController (depending on your typing history, but this is intuitive).

By the time you get to the 4th character, the list is almost always reasonably small and therefore much more helpful.

If you just type “u” and forget what you were doing, we’ll wait about 0.4 seconds before presenting the list to help you.

More importantly, you can type “for (int i = 0…” at normal typing speed without the popup appearing at all, and once you get stuck on something you’ll pause naturally and only then will the list appear.

Extras

Of course, you don’t want the list appearing on just any alphanumeric character: If you’re writing a string or a comment, the list isn’t going to help you. So the plugin does some extra work to detect those situations. It’s not a full-on lexer but it seems to work 99% of the time.

Additionally, if you type a period ‘.’ to access a struct member or ObjC property, the list always appears immediately.

One last neat feature: When you type a semicolon, it will be automatically moved to the end of the line as necessary. I don’t know about you, but I often find myself in this kind of situation:

…having just typed a method name and needing to cap off the line with a semicolon. Normally I’d have to go find the right arrow key first, but with the plugin you just type ‘;’ and it puts it in the right place.

Pretty cool!

Try the plugin here.

Code Completion and XCode

Update: I wrote a plugin to address these issues.

The newish mac app Espresso contains a great (and uncommonly beautiful) implementation of code completion.

It goes like this. Say you’re editing a CSS file:

That’s a nice blue background, but you also want a border. You start by typing the letter “b”:

Since Espresso knows that there are many possible options that start with “b”, it presents them to you in this lovely but minimal popup. You can use the arrows and press enter to select something from the list. Or, you can pretend the list never appeared and keep typing. Once you type enough to eliminate all other options, the list disappears and you’re left with a more standard OS X “completion” highlight. You can still press enter to accept this last suggestion.

The two things I want to emphasize about this workflow are:

  • It’s predictable. I trust Espresso to always give me all possible relevant options after each keypress. And I know that I just press enter to accept and move on.
  • It’s useful. Whenever there are multiple options, they are presented to me in the list, and the list appears automatically when needed.

Predictable

XCode goes like this. Say you’re writing some Objective-C:

We need to make a new instance of UIViewController, so we begin our journey of typing the class name.

XCode does nothing so far. We know it has a set of suggestions to help us—if you press ESC now, you’ll see a nice list of all the classes starting with “UI”. But for some reason it’s decided not to jump in yet. (Note: My Code Sense delay is set to Immediate). We press on, typing “v”:

Ah ha, there it is! Clever XCode! That’s what we want—so we’ll press enter:

Curious. It has only partially completed the word. See how before, only the ‘i’ was highlighted? This is a (newish?) feature of XCode. It turns out there are a few other classes starting with the prefix “UIVi” and it doesn’t want to assume that I want something starting with UIView and not, say, UIVideoEditorController which I never knew existed until just now.

At this point if I press enter again, it will go ahead and fill in the rest of the word.

So it eventually gave me what I wanted. But here’s a wrinkle: if I would have typed “uivi” myself first, it would have suggested UIViewController just the same, but in that case it would have completed the entire word when I pressed enter.

The problem here is that XCode is not predictable. When I’m typing code, my brain is moving faster than my fingers. I can decide to type [[[UIViewController alloc] init] autorelease] a hell of a lot faster than I can actually write it. And my brain can’t move on to a more interesting problem until it can give my fingers a known sequence of keys to press. XCode’s completion is a different back-and-forth conversation with the editor every time. How do I get it to finish UIViewContoller? Do I press enter once, twice, three times? It depends how many characters I typed first, which also depends on factors like XCode tailoring its suggestions based on my code history.

Useful

Here’s another example. Let’s set the frame of our new controller’s view, by first declaring a new CGRect:

Now here I’ve typed the letters cgrect just like that, and XCode hasn’t suggested anything at all. Maybe I have to type more than 6 characters before XCode jumps in? (Nope, that’s not it.)

OK well, I’m done typing now, so I have to fixup this cgrect by turning it into a real CGRect with proper caps. Maybe XCode can help with this? I’ll press ESC.

OK, so I got lucky, it happens to be the 2nd item in the list. (If this list was sorted alphabetically, as it is by default, CGRect by itself wouldn’t even be on it). But still, I’ve written an exact match, shouldn’t that be what’s selected by default instead of CGRectInset? Now I have to fiddle with arrow keys and scrolling and by this point I could have just typed out CGRect myself with proper carpal-tunnel-inducing capitalization and skipped all this business.

It gets worse

These are just two examples out of many. In fact, XCode’s completion is so unhelpful that I can only assume the engineers at Apple never have it turned on, and maybe just code everything in Vim anyway. To me, it feels like the sort of feature that was built to “satisfy” demand from non-Apple developers. Look, fine, we’ll give you your ‘completion’, you Microsoft-coddled sissies, now please go away and let us work on OS X 10.7 already!

It’s just a bit sad for me, because I have tasted the sweet nectar of real, predictable, useful code completion, and it is wonderful and productive. This isn’t an intractable problem! It just needs some more TLC.

If you agree with my findings, I encourage, nay, command you to go fill out a bug report with Apple (they really do read these).

I have also reposted the issue on Open Radar.

Transport!

I finally sat down and published Transport, a little app I’ve been using for quite a while to send files and screenshots and such. Mostly screenshots, because it turns out this is incredibly useful when it only takes one keystroke. Communicating via images is sometimes a zillion times easier than typing 1000 words and all.

You might wonder why Transport’s public server is located at “ctu.appspot.com” — i.e. what the heck is CTU? The answer is surprisingly long and mildly interesting, so I’ll be posting a bit more later to explain.