Password Autofill and Shared Web Credentials

Update: See my next post for why the problem described here isn’t actually a problem.

In Apple’s WWDC 2017 session “Introducing Password Autofill for Apps”, the presenter describes this scenario: a user downloads an app, but is put off from using it when they’re required to log in with a username and password first.

I’ve worked at a number of companies built around a consumer service, and they all worry about this.

If a user who doesn’t use something like 1Password sets up a strong password, it’s likely they’ll forget it by the next time they need to log in. You can have them reset it, but…will they bother?

Apple’s solution assumes the user has logged into the service in Safari, either on that device or, if they have iCloud Keychain turned on, on another Apple device.

When they go to the username or password text fields in your app on iOS 11, in the QuickType bar above the on-screen keyboard, Password Autofill shows a little key icon to the right, and some text telling them that it now contains the username and password for that service. If they tap it, it will fill in the text fields with the saved credentials, and they’re on their way.

Password Autofill will attempt, via heuristics, to provide this information even if you’ve done nothing to support it in your app (besides connecting your app to your website, see below), though there are ways you can tweak your app to make the user interface connection more explicit.

If the user hasn’t logged into the service in Safari previously, or they did it on another device and they don’t have iCloud Keychain turned on, they’re screwed. Apple doesn’t have that information, and can’t offer it to them.

What if they’ve logged into the service before in that app, then deleted the app, then reinstalled it?

In the past, you could rely on the local app-specific Keychain entries surviving under such circumstances. So your app could still access the username and password from there, and automatically log the user in. But Apple took this away in iOS 10.3.

My understanding here is that you can restore that functionality by using something closely related to Password Autofill, but older: Shared Web Credentials (third-party tutorials here and here).

Both technologies require an Apple-recognized association between your website and your application; the WWDC session for Password Autofill and the documentation for Shared Web Credentials both spend a lot of time describing how to set up that relationship, which is also needed for Universal Links.

By using the Shared Web Credentials APIs, you can tap into that same reservoir of usernames and passwords that Password Autofill uses, but completely bypass the username and password fields of your application: you get the data yourself and can use it directly.

Why does anyone need Password Autofill, then? My hunch is that Shared Web Credentials didn’t take off the way Apple wanted — it does require more work, after all. So they made something even easier, something app writers might not need to do anything at all to support.

Now let’s think about it in the other direction: if Password Autofill is so easy, why worry about Shared Web Credentials at all?

Because Shared Web Credential let you go in the other direction.

If a user does log in via your app, you can use Shared Web Credential to push that information into Safari (and iCloud Keychain, if it’s on). Then, if they delete the app and restore it, you can still log them in automatically by getting that information back out of Safari. Note: doing so isn’t invisible: the user will be prompted with an Apple-provided confirmation alert in both cases.

So if you really want to make things as easy as possible for your users, it seems to me you’ll want to support Shared Web Credentials in both directions, before worrying about Password Autofill at all. It’s not as foolproof as the old local Keychain solution, since the user can reject sharing their credentials with Safari, but it’s better than nothing.

Am I missing anything about this?

Out of Context

Twitter’s been having a discussion about tech job interviews recently: you can see my contributions here, here, here, and here.

For the tl;dr crowd, my take is that interviews are extremely difficult, and so you (and I) should have some empathy.

A while ago, I did a bunch of interviews for a junior iOS developer. I gave them what is apparently a quite common exercise: in a simple iOS app, get some JSON data from a server and use it to populate a table, including, for each entry, a link to an image file to download separately.

I just made such a project, called Numbers, available here.

When you first run it, it shows a table filled with entries 1-20, where the brightly-colored number icons are each loaded separately.

A button to the right of the navigation bar is labeled “Wrong”, meaning you’re currently using the image loading implementation that’s incorrect.

If you scroll to the bottom of the table quickly, you’ll see that initially, the rows you uncover will be temporarily populated with incorrect icons:

Screenshot of "Numbers" application table view, scrolled to bottom, with rows 16 through 20 having incorrect icons 2 through 6.

That’s because, in the incorrect implementation, the async network calls insert the loaded images into the cells that originally requested them.

But, as Everyone Knows, cells in UITableView are reused when you scroll, which means by the time the network calls finish, the original cell might be in use for at a different row, and it shouldn’t display the original row’s contents.

Instead, the network call for an image should update the cell that currently represents the row.

If you tap the “Wrong” button, it will change to the text “Right”, and that’s how the application will behave when it reloads the table. Scrolling quickly to the bottom of the table won’t result in erroneously populated images anymore.

When I was interviewing, if the interviewee said they knew table views, I would give them this exercise, and would consider them not worth hiring if they made that rookie mistake.

Nowadays, it’s clear to me that this is a Gotcha! question like any other.

Instead of it being a question about how they think, how they solve problems, it requires a very specific piece of information you either have it your head at that moment, or you don’t.

In a recent interview where I was debugging a problematic table view implementation, I failed to recognize a similar incorrect image loading mechanism — until nudged to do so by the interviewer. I just didn’t see it. If that interviewer had been as quick to judge as I had been in the past, I wouldn’t have gotten the job.

As a final note of curiosity, you might notice that, in the Numbers project, I reset the NSURLSession each time before reloading the table view’s contents. That’s because NSURLSession has its own cache of network call results, and if I didn’t reset it, you would only be able to reproduce the “wrong” behavior the very first time you tried it. Every subsequent time (including across app relaunches), the images would “load” instantaneously from the cache.

While I would never recommend shipping the wrong implementation, even if you did, these days, Apple’s frameworks would mitigate its impact.

Diverse Rolling

Two years ago, I took the OPML file from Brent Simmons’ inessential post “Blogs by Women”, threw it into my RSS reader, and magically had 30+ new blogs to read.

Here are the favorites of mine that are still around and active.

Erica Sadun (Twitter)
I’ve known about Erica’s work since the 2013 Edge Cases episode “Rectangles on a String”. (I even know how to pronounce her last name, even if she does pronounce tuple wrong.) Her blog updates several times a week, often about some detail of Swift development. She’s written a bunch of books, mostly focused on developers, and one book on Swift.

Accidentally in Code, by Cate Huston (Twitter)
Most delightful find for me personally. She talks about a variety of issues in the tech industry, including managing, as I’ve previously mentioned.

Becky Hansmeyer (Twitter)
From her own description, her blog is “my own little place to comment on Apple & general technology news, as well as what it’s like to be a novice developer with no prior programming experience.” Her tag line is “100% grass-fed Swift”.

Natasha the Robot (Twitter)
Helpful posts on iOS/watchOS and Swift topics. Natasha is the organizer of the try! Swift conference, and frequent speaker.

Julia Evans (Twitter)
Detailed, explanatory posts on a variety of tech topics. Very motivational! Not iOS-related, however.

And finally, a great blogger who’s been very active recently who’s not on the list:

Stephanie Hurlburt (Twitter)
Graphics developer and entrepreneur, who posts about a variety of aspects of the tech industry, some of them quite personal.

Enjoy!

Point of No Return

I found an interesting (to me) aspect of Swift/Objective-C interactions this week.

Take this Objective-C method:

+ (nullable NSData *)dataWithString:(nullable NSString *)string error:(NSError **)error

It uses the standard Apple pattern of having both a return value and an error. (I left out the error’s nullability annotations for brevity, as Apple always assumes them.)

In theory — and, if I’m remembering correctly, according to Apple guidelines — first, you’re supposed to check if the return value is invalid. Only once you’ve verified that it’s invalid should you check to see if there’s an error.

And as far as I’m been aware, there’s never been any assumption that you’ll get an error. That’s why, throughout your Objective-C code, you always have to check the return value and treat that as gospel.

If you use this method in Swift, the auto-generated Swift signature is:

func data(with string: String?) throws -> Data

Notice something?

I mean, besides the fact that Apple’s compiler/runtime magic smoothly converts between the Objective-C’s last-parameter-is-an-error-pointer pattern and Swift’s “throws” pattern.

The return type doesn’t allow for nil anymore.

You can’t check for an invalid value, if “invalid” means nil.

Instead, you can only assume that the original Objective-C implementation will “throw” an error if there is a problem.

Now, go back to your original Objective-C method. What if you return nil but don’t set the error? What does Swift do?

It does something clever.

In my testing, even when you haven’t set an error, the Swift translation layer throws an error anyway.

If you log it, it’s called nilError.

It’s got a domain of Foundation._GenericObjCError and a code of 0.

Feels a bit like a hack, doesn’t it?

But it does prevent the problem of old Objective-C code not indicating the desired result under Swift.

Translating Objective-C to Swift in Xcode 9.0 Beta 2

I’m putting together a post comparing Mac drag and drop APIs and iOS drag and drop APIs.

To prepare, I took the Xcode CocoaDragAndDrop sample project (here, last modified in 2011 with note “Updated for Xcode 4”) and converted it to Swift (here) using the second beta of Xcode 9.0.1

Since I haven’t internalized the pattern between Objective-C and Swift method conversions, I was often frustrated by how to translate Objective-C method calls to Swift method calls.

While I was working on the project, it seemed that 4 times out of 5, when I tried to go to a class or protocol’s declaration in Apple’s headers and see its Swift-ified methods, Xcode would take me to the Objective-C header instead, even though I was starting off in a Swift file.

Of course, now that I’m trying to reproduce it to file a Radar, it doesn’t happen. I wonder if that’s because the final project has no Objective-C files in it at all.

It doesn’t help that the translations changed between Swift 3 and Swift 4.

For example, NSPasteboardTypeTIFF in Swift 3 is now NSPasteboard.PasteboardType.tiff in Swift 4, with a similar pattern for all its friends.

register(forDraggedTypes newTypes: [String]) is now registerForDraggedTypes(_ newTypes: [NSPasteboard.PasteboardType]).

Etc.

It’ll be nice to be working exclusively in Swift for the rest of this effort.


1. Feedback welcome! ↩︎

Refactoring a Massive View Controller

Now that Apple has announced a long-delayed revamp of refactoring in Xcode 9, it’s a good time to talk about my proudest refactoring moment over the last year:

I successfully broke apart a massive view controller in shipping code.

How? When you refactor a massive view controller, you know what you want your code to look like when you’re done. The places you’ll put all the diverse logic that’s currently twisted and squashed into one place.

Where you stumble over is how to get it there while you keep it all working.

When I looked at my massive view controller, I saw about four different areas of responsibility, four different related sets of methods and instance variables. But they weren’t cleanly divided: if I tried to take out any one of those areas, I’d be dragging in bits of the other areas along with it.

So I did.

I made a new class, let’s say for Login functionality, and pulled out all the methods and related ivars.

But since the existing spaghetti code that was left in the view controller wanted access to some of those methods and ivars, I couldn’t make a well-designed Login class at this stage. Instead, I left plenty of methods public that should be private, so they could be called by the old view controller. I left plenty of read/write properties public, so they could be called by the old view controller. I think I wound up exposing 12 of properties in all.

It was a total mess.

But it still worked exactly like it used to, no regressions, because it was exactly the same code — just moved.

Then, instead of trying to fix up the Login class, I moved on to the next. Maybe the next one was Network Connectivity. Maybe the one after that was Model Loading. Whatever they were, I pulled everything related to them out into their own classes, doing nothing except cutting and pasting the code from one place to another.

And as I went about it, a funny thing happened.

Even though I wasn’t trying to finalize the design or the APIs yet, for each new area I pulled out, I found I could refine the previously-extracted areas. Exposed properties that before were accessed seemingly at random, I could now see were only used by one of the specific areas I’d pulled out, and only at specific times. I could start to move properties around between the extracted classes, cut and paste them where they should go. I could move closer to the encapsulation I wanted.

All without breaking anything, because I was taking such tiny, straightforward, safe steps.

That meant, by the time everything was extracted, I was actually much closer to a final design than I had any right to be, given initial conditions.

At that point, I could finish the redesign through more conventional means.

Boilerplate in C++ and Swift

Moving from C++ to Objective-C was a revelation to me.

In C++, dynamic lookup was a chore. Because the language was relatively static, if you wanted to go from an arbitrary key to code, you had to write your own custom lookup table.

I remember writing a lot of registration code, a lot of boilerplate. For each class or method I wanted to look up, I would put an entry in the lookup table. Maybe it was part of an explicit factory method, maybe it was a C macro, maybe it was some sort of template metaprogramming magic. But there had to be something, and you had to write it every time.

Boilerplate, boilerplate, boilerplate. Over and over again.

In Objective-C, the dynamic lookup mechanism was built into the language: dynamic dispatch. Look up any class, any method, with just a string.

I remember reading somewhere — I wish I remember where — a post where someone pointed this out, that the C++ technique and the Objective-C technique both required lookup tables, but in the latter case, it was maintained for you by the Objective-C runtime. Objective-C didn’t reduce the inherent complexity, it just hid it, made it uniform.

The LLVM team, on the other hand, has been trying to kill dynamic dispatch for a long time.

Since ARC, calling arbitrary methods by string, the core of dynamic dispatch, by default triggers a warning.

And of course, in pure Swift, dynamic dispatch is completely absent. Everything must be known ahead of time by the compiler.

I understand why. They want to make it more safe.

Does that mean we’re seeing the reinvention of the custom lookup table in Swift?

Swift enumerations, for example, make this relatively easy, since you can pair methods, i.e. arbitrary code, with each enumeration case.

If I have to write a new enum case for every new class, though, then I consider that unnecessary boilerplate, a throwback to C++ techniques. Boilerplate.

And I wish we didn’t have to go back down that road.

WWDC Sessions by Women and Minorities

My one WWDC 2017 prediction:

People will be talking, afterward, about the number of women and minorities up on stage during the Keynote.

This is highlighted by the (unconfirmed?) report that the breakout woman of color from last year’s WWDC Keynote, Bozoma Saint John, is leaving Apple soon.

From what I have read and experienced, Apple, like many tech companies, is struggling to increase its diversity in any substantial way. Rows and rows of white dudes (such as myself, when I was there) working on Apple’s hardware and software.

The executive team you see at the Keynote is important, but I don’t see it changing anytime soon. So I’m looking at the rest of the sessions.

The people who give the regular talks at WWDC are the people who work on the thing, or their immediate managers, who usually contribute technically was well.

So when I’ve seen more women up on stage for those talks in the last couple years, I’ve been pretty happy with it. They aren’t tokens. Apple really is employing more women to work on their stuff.

So that’s what I’ll be looking for as I watch the sessions (remotely) this year: more women and minorities throughout.

Thoughts on Learning a Little Scala

In some ways, Scala is the functional improvement over Java that Swift is to Objective-C.

  • Based on functional concepts, when the previous language was primarily OO.
  • Updated, modern, compact syntax.
  • Strongly typed, but with type inference, so complex type declarations can be omitted.
  • Compiler much slower, since it is doing more.
  • Strong interop with legacy code.

In other ways, though, Java to Scala is more like the transition from C to Objective-C:

  • Standard types taken from previous language.
  • Runtime taken from previous language.
  • Compromises made in language design to accommodate previous language’s content.

Both Objective-C and Scala were languages invented outside the nurturing environment of a flagship corporation. They couldn’t reinvent the wheel. They didn’t have the resources. (Same could be said for C++.) So they had to find a “host”.

Java and Swift, on the other hand, had serious money behind them, and could do everything from scratch if they wanted. They could think big.

I believe you need both to make progress.

Apple is taking dramatic steps now. But they will eventually finish all the large-scale, cutting-edge elements they’re willing to sponsor for their business, and the pace of change will slow.

And then, once again, we’ll have to look outside of Apple for language innovation.

New Codebase, Who Dis?

I’ve found that just reading through a new codebase isn’t enough to get me comfortable with it.

I’ve even found that having it explained by the previous developers doesn’t do the trick.

What does “comfortable” mean? It means that I have an accurate mental model of it. I’ve internalized it. I don’t have to check the code or the documentation to know the following:

  • what the big features are
  • what it does well
  • what needs to be fixed about it
  • what looks bad but doesn’t need to be fixed right away
  • what the low-hanging fruits for code cleanup are
  • what OS features it doesn’t support, but should
  • what OS features it doesn’t support, and never will
  • what its predominate style is (or if it has one)
  • where the best place to put a helper method is

That list is just off the top of my head. I’m sure there’s more.

So, if just reading the code doesn’t work for me, what does?

Actually working on it.

Fixing bugs. Adding new features to existing code. Going through one full major release cycle, if possible.

Then I can start thinking concretely about making major improvements to it.