My Ideal Politician

My ideal politician would believe something like this:

Any time a bill crosses my desk, I ask myself two questions. Will this help a smaller business compete against a bigger one? Will this help a family recover from that competition? If the answer to both those questions is no — I won’t vote for it.

The reality is we have one party that routinely ignores the first question, and another party that gets it’s rocks off ignoring both.

|  12 Apr 2017




Working With Designs That Require Display Versus Text San Francisco Fonts

Some designs I receive from clients call for specific weight and family combinations for user interface fonts. Use a display font here, and a text font there. This is true of both custom fonts and system-provided fonts. Apple seems to encourage this level of finesse with system fonts in their online design resources. There are several distinct families in the downloadable San Francisco fonts available on the Apple developer site.

When requesting a system font in code, the UIFont returned will either be a display or a text font, depending on the API you use. For the systemFont(ofSize:weight:) API, the cutoff is in the neighborhood of 22 points, above which you’ll get a display font and below which a text font. Other APIs like preferredFont(forTextStyle:) might return a display or a text font regardless of point size. This is great for general purposes. An inexperienced designer can use whichever API is closest to their needs and receive a font whose family is a best-fit for that size, weight, and the characteristics of the current display.

However there are times when an experienced designer needs to specify not just a weight and a point size but also a family. In those situations, it is difficult for the developer to satisfy the design requirements. If you’re using a custom font bundled with your application, then you can create a font descriptor quite easily:

let descriptor = UIFontDescriptor(fontAttributes: [
    UIFontDescriptorNameAttribute: MY_FONT_NAME
    ])

If you need to do this with the San Francisco fonts, it is much more difficult. There are only two ways I know of to do this.

Yucky Hack

You can make some educated guesses about the behavior of the UIFont APIs and do something like this:

let textFont = UIFont.systemFont(ofSize: 6)
// .SFUIText 6pt, used for font name

let titleFont = UIFont.preferredFont(forTextStyle: .title1)
// .SFUIDisplay-Light 28pt, used for point size

let descriptor = UIFontDescriptor(fontAttributes: [
    UIFontDescriptorNameAttribute: textFont.fontName
    ])
let desiredFont = UIFont(
    descriptor: descriptor,
    size: titleFont.pointSize)
// .SFUIText 28pt, combo of desired traits

Very Yucky Hack

A more reliable but even yuckier solution: you can bundle the downloadable fonts from the developer site, and reference them by name in a font descriptor:

let descriptor = UIFontDescriptor(fontAttributes: [
    UIFontDescriptorFamilyAttribute: "SF UI Text",
    UIFontDescriptorFaceAttribute: "Semibold"
    ])

This bloats the size of your app bundle but at least you can guarantee that you’re always using a display or text font when you need one or the other.

Why Does This Matter?

To illustrate why this matters, please consider the following example. While the anecdote below is partially contrived, it’s representative of the kind of design problems I’ve had to solve on actual projects. I think it serves as a useful illustration of the shortcomings of the current UIFont APIs.

Consider a tvOS app with a horizontal collection view of cards. As each card takes the center spot, it receives focus and enlarges to about twice its unfocused size. Each card contains some body text.

Lets assume for the sake of this example that a variation of SF UI Display will be vended from whichever system font API is used to request a 44 point regular weight font.

Which font family would actually be preferable for the text on these cards? The answer is not straightforward. In the enlarged state, a display font might make sense. At a size of 44 points in the default expanded card state, a text font might look awkward in comparison. A 44 point size is probably large enough to accommodate the characteristics of a display font:

But on the other hand, for every one focused card there are always four unfocused cards (two on either side) visible at all times. If the unfocused card contents are scaled down via a scale transform, then whatever font is used at the focused size (with an identity transform) will be scaled down to a perceived “22 point” size. Note that the text is still laid out using a 44 point display font, but the unfocused card transform results in a perceived size that is much smaller. At this scaled down size, a display font would be harder to read, for example in words like “clipper” or “sail” where lowercase L’s are adjacent to lowercase I’s — especially so when staring across the room at a grainy television.

So what alternatives are there?

One alternative would be to request two fonts: one to layout the text in the focused state, and another when laying out the unfocused state. The problem here is that if this results in a display font at the 44 point size and a text font at the 22 point size, the line fragments will most likely break at different words between the two states, creating confusion for the user during focus update animations:

The more desirable alternative for this design is to always prefer a text font, since this preserves the maximum amount of legibility at all focus states:

We would use a scale transform to downscale the 44-point identity-transformed text to a perceived 22-point size, preserving legibility in the both the focused/enlarged state and the unfocused/scaled-down state, and without disturbing the line breaks during the transition from one to the other.

Wishlist For Apple

If anyone from Apple is reading, I’d love if ya’ll can add programmatic access to family-based font selection of system fonts:

let bigTextFont = UIFont.systemFont(
    ofSize: 44,
    weight: UIFontWeightRegular,
    family: UIFontFamilyText
)

|  11 Apr 2017




Stormcrow

If you’ve ever wanted an easier way to write a properly-threaded tweetstorm, my new app Stormcrow can help. Type all your tweets into a single text view. Stormcrow will automatically separate your paragraphs into a thread of automatically-numbered tweets. Publish them all at once at the tap of a button. Spend less time futzing with reply buttons and counting tweets, and focus on what you’re trying to say.

Stormcrow is available now on the App Store for $2.99 USD.

|  27 Mar 2017




Swift Needs a Scope Keyword

Swift’s namespacing is great. It’s quite common now to see nested types like this:

class MyViewController: UIViewController {
  private enum State {
    case initialized
    case refreshing(previousModel: Model)
    case success(currentModel: Model)
    case error(Error)
  }
  private var state: State = .initialized {
    didSet { stateChanged(from: oldValue, to: state) }
  }
}

There’s no need for any class outside of MyViewController to access the State enum. Nesting it not only makes the intended usage obvious, it also lets you trim the type name down to a single word by obviating the need for a prefixed name like MyViewControllerState. Other classes are then free to nest their own State enums without worrying about name collisions.

Swift’s namespacing rules also allow you to group together related functions or constants that would otherwise be scoped at the module level:

struct Transformations {
  static func transform(_ foo: Foo) -> Bar {...}
  static func transform(_ bar: Bar) -> Foo {...}
}

struct Colors {
  static let background = UIColor.white
  static let bodyText = UIColor.black
}

Callers can then access a function like transform() without having to access a free function:

let b = Transformations.transform(f)

Please note this does not require the developer to initialize a Transformations instance. It’s hard to tell from my contrived example, but in practice it’s common to find types that would be nonsensical as instances but are nonetheless useful as scope providers.

But here’s the problem: how do you make it obvious to other developers that Transformations isn’t supposed to be initialized? One option: make the init method private:

struct Transformations {
  static func transform(_ foo: Foo) -> Bar {...}
  static func transform(_ bar: Bar) -> Foo {...}
  private init() {}
}

But that solution introduces more problems. First, it’s still not readily apparent that Transformations exists solely to provide a namespace. Second, this API pattern requires you to remember to make the init method private for every such type you ever create, which is a hassle. This is why the de rigueur solution right now is to use a caseless enum:

enum Transformations {
  static func transform(_ foo: Foo) -> Bar {...}
  static func transform(_ bar: Bar) -> Foo {...}
}

But this too is confusing because it’s not obvious that Transformations is meant to provide a namespace. It’s not really an enum. This is especially problematic in real-world examples where the functions and members of such a type are lengthy, making it impossible to tell at a glance whether there are any case declarations hidden somewhere in the file. It also does not prevent other developers from misunderstanding your intent and adding cases to the enum in the future.

I propose that Swift introduce a new scope keyword to address this common use case. My simple example might then look like this:

scope Transformations {
  static func transform(_ foo: Foo) -> Bar {...}
  static func transform(_ bar: Bar) -> Foo {...}
}

A scope can be declared the same way as structs, enums, and classes:

scope TYPENAME {
  // body
}

A scope can be declared either at a module level or nested within any type that supports nested types, including another scope:

scope OuterTurtle {
  scope MiddleTurtle {
    scope InnerTurtle {
    }
  }
}

A scope cannot be initialized, therefore a scope cannot have instance-level properties or methods. All methods and properties of a scope must be static. However, as a convenience the static keyword can be omitted since this is always implied:

scope Endpoints {
  scope Users {
    func getUser(withId id: String) -> Endpoint {...}
    func followUser(withId id: String) -> Endpoint {...}
  }
}

Scopes support the same access levels as other Swift types:

public scope Foo {
  public let qux = Bar.baz
  private scope Bar {
    let baz = "Baz"
  }
}

If you think this would be useful, please get in touch with me on Twitter.

|  17 Mar 2017




How To Write The Software

From an interview with a career SR-71 pilot:

Q: So if I’m understanding the whole startup process is kind of like this space age Model T, where you cranked it just to get the engine up to speed?

A: Yeah. It’s just amazing, and points out a hallmark of the Skunk Works. Don’t waste energy on something you have a solution for. You’ve got a lot of things to worry about already: how to keep the glass from melting at speed, how to keep the engines running at high speeds for long periods, how do you keep the fuel from exploding. If someone had a simple solution to something, then that’s what they did. A very unique, very pragmatic approach. It was also part of the mystique of the thing, this fifty foot green flame shooting out from each engine on startup.

Source: SBNation

|  1 Dec 2016




Tangential Thinking

I don’t know if this term is one somebody else coined, or if it has other meanings elsewhere, but what it means to me is clear. Life is a series of points on a curve of no discernible shape. No orderly function produced it. There are as many bends and folds as there are numbingly straight passages. The only guarantee is that, as it has bent before, it will bend again. The chief mistake of the student of this line is to project its future course as a tangent from the present. Someday it will bend away from that projection, and the tangent that seems so sure now will vanish. This mistake is easy to make. There are many straight passages, some so long as to suggest a guiding hand. If there is a guiding hand, it seems bent on tempting the complacent into despair and the despairing into complacency. Guard your mind against both temptations.

|  27 Nov 2016




How I Organize a Swift File

As a professional developer, it’s my job to work with the code that I’m given, even if it’s not ideal or aligned with my own coding style. That doesn’t mean I can’t have my preferences and peeves. Sometimes I inherit Swift code that looks like this:

The main thing this code has going for it is that it’s terse, which can be a good thing for some Swift code. But there are problems:

When I encounter code like that, I try to clean it up:

What’s different:

Here’s how it looks with some of the details above removed, in order to capture all code sections in one screenshot:

I don’t expect everyone to agree with my preferences. This is just what I like. But I think I can make pretty good objective arguments for the principles I’m trying to put into practice:

|  2 Nov 2016




Self-Driving Car Fleet Commercial: 2021

INT. BEDROOM - DAY

A teenage GIRL is sitting on her bed working on homework. Her head is bobbing to music bumping in her headphones.

A smartphone beeps from the bedside table. The girl picks it up. Chat bubbles appear in the air around her as she uses her phone.

        MESSAGE FROM FRIEND
        beach trip tonite?

        GIRL (MESSAGING)
        lets do it

CLOSEUP: PHONE SCREEN

The girl launches a brightly colored app on her phone. She presses a button that says “Day Trip”.

INT. BEDROOM - DAY

The girl swipes through her options on her phone. As she swipes, her dorm room dramatically swipes away, replaced by each destination, surrounding the girl like she’s being magically transported: downtown, nature hike, theme park. Each destination appears with a badge in the corner that reads “Travel time: N hrs”. She chooses a beach that’s two hours away. It looks like sunset at the beach.

CLOSEUP: PHONE SCREEN

A carousel appears with silhouettes of vehicles. The girl flicks through the available vehicle types. Each one has a badge in the corner that reads: “Up to N passengers” until she stops on an eight-passenger, fun-looking, rounded box on wheels. She selects it.

INT. BEDROOM – DAY

The bedroom has returned to normal. All these simulated smartphone actions are happening very quickly. You’re not meant to study them, only to perceive the gist of them as they whizz past.

A title hovers in the air, as if projected from her phone: “Invite Friends”. The girl taps her phone several times. Each time she taps, an avatar bubble appears in the air next to her. It’s all the friends she’s inviting on the beach trip.

The girl taps a big “Book It” button.

EXT. DORMITORY - AFTERNOON

A boxy-looking van pulls up outside the girl’s dorm. The cool-looking sidedoor juts open as the van rolls to a stop, electric motor idling. The girl’s FRIENDS are already inside, laughing, waving her in, bracelets jangling in the summer sun.

INT. VAN - AFTERNOON

Everyone inside the van is partying. A TV is playing a movie, or maybe a video game, or karaoke. All the seats face inward. There is no steering wheel, no bucket seats. The girl finds a spot on the wraparound bench seating and fastens her seatbelt like it’s a muscle memory.

EXT. BEACH - SUNSET

The van pulls up in the immediate foreground, perfectly-centered in our field of view. The sun is setting in the distance, so the van is heavily silhouetted. It’s shaped just like the silhouette we saw earlier in the smart phone app. The crazy door opens and silhouettes of the kids pour out of the van and onto the sand. As they run down to the water, the title appears in a bright, thin, white font:



U B E R


|  31 Oct 2016




Future Imperfect

In an episode of the third season of Black Mirror, a woman pulls up to an electric gas station of the near future. It’s the wee hours of the night. Her electric car, a rental, has a low battery. It’s about to putter out. She goes to the — I’m not sure what to call it — pump and tries to plug in the charging cable. It won’t fit. She rummages through the trunk and can’t find a conversion cable. She begs the attendant, and then everyone else at the station, but no one has the cable. She’s stranded. She has no choice but to trek down the interstate on foot, hoping to hitch a hike.

That scene strikes me as precisely the bold future that we’re rocketing towards.

Examples abound.

Only one percent of Android users have access to the latest version of Android because carriers and manufacturers aren’t motivated to release them.

The next lightbulb you buy might be conscripted into an army of lightbulbs bent on bringing down the power grid on the eastern seaboard if its manufacturer isn’t obligated to use strong enough security measures. The few manufacturers that are using those standards might be too expensive for you or just won’t work with your other Things of the Internet.

Facebook for iOS still doesn’t use the native share sheet, which was released four years ago.

The new “TV” app for tvOS/iOS doesn’t include Netflix, arguably the most important streaming service, presumably because Netflix refused whatever terms Apple required.

There is no Amazon Prime Video app at all on tvOS, let alone in the new TV app. Comixology, another Amazon product, doesn’t sell comics in-app because the 30% markup on in-app purchases makes the idea a non-starter for Amazon. They can’t even link to the online store. You just have to know that there’s an online store where you can purchase the items, and that those items will magically appear in the app.

Google Maps, demonstrably the best mapping service in the world, can’t be configured as the default mapping app on your iPhone or iPad. Because of the ongoing competition between Apple and Google, it’s not even installed by default anymore1. Many iPhone owners will never discover just how much better Google Maps is.

Google’s speech-to-text recognition is fantastically good. Try it out in the Google iOS app sometime, and compare the same prompts with what you get from Siri. I’m talking about the difference between a barber jacket and a Barbour jacket. Google understands when you mean the latter. The default iOS keyboard has a voice recognition feature that isn’t nearly as good, but you can’t use Google’s speech recognition in Gboard, Google’s iOS keyboard, because Apple won’t allow them to access the microphone.

Five years and five operating systems later, Apple finally extended a public API for Siri, but it only works with six limited domains. You still can’t use Siri to put an item in the todo list app of your choice.

If you prefer Chrome over Safari on iOS, or the Gmail iOS app over Mail, you have to plod through the tedious procedure of launching those apps manually since system-wide features can only use the native apps.

Hilariously, you can spend $4299 dollars on a spanking new MacBook Pro and $969 dollars on an iPhone 7 Plus — both from the same manufacturer — but you cannot connect them together without a $25 conversion cable.

It is no wonder, then, that Google is staking their future on original hardware. There’s no way they can embed all of their fantastic services into a competitor’s device at a level that’s integrated deeply enough to be useful. The only way they can bring their AI assistant plans into concrete reality is to make their own phone. From a historical perspective, this is a pathetic waste of resources. Apple already makes the best hardware and software. The ideal smartphone would marry Apple’s hardware and software with Google’s services. But because of the intractable realities of competition and viable business models, Google has to reinvent Apple’s wheels in order to keep selling their own.

This is not a rant about the lack of open standards. Open standards don’t lead to a perfect user experience, either. The podcasting industry is, by tech standards, the wild west. But if you try sharing an episode with someone, they’ll be unable to hear it unless you share it using a podcast client that offers a proprietary browser player. New features in HTML and CSS are dependent upon mass market browser developers like Apple, Google, and Microsoft agreeing to implement spec changes. Their willingness to do so is a business decision, and could change in the future — <cough>AMP</cough>.

Please understand I am not suggesting that things could be any different. At least not practically. There are fixed points in business, law, and history that are determining our status quo. What I am saying is that our technological future is being shaped more by business constraints than engineering constraints. What is technically possible is outstripping what is feasible in the market.

The future is looking less and less like Star Trek and more like that woman in Black Mirror, thumb in the wind, begging for a ride.


  1. By this I mean the original iOS Maps application used Google maps for it’s data, thus in a sense being installed by default. 

|  28 Oct 2016




AsyncOperations

Today I’m open sourcing some utility classes I’ve been working on for the past several months. From the GitHub description: “A toolbox of NSOperation subclasses for a variety of asynchronous programming needs.”

Just Show Me The Source

Asynchronous NSOperations

Generally speaking, NSOperation makes it easy to chain together dependencies among multiple operations. Consider a sequence of NSBlockOperations:

let one = BlockOperation {
    print("One")
}

let two = BlockOperation {
    print("Two")
}

two.addDependency(one)

// Prints:
//    One
//    Two

But what happens if you have a block that must be executed asynchronously?

let one = BlockOperation {
  doSomethingSlowly(completion:{
    print("One")
  })
}

let two = BlockOperation {
  print("Two")
}

two.addDependency(one)

// Prints:
//  Two
//  One

There are at least two problems here. Of course our output is now printing in the wrong order, but notice also that there’s no way to cancel one after it has called doSomethingSlowly(). As far as NSOperationQueue is concerned, that operation has already finished, despite the fact that we haven’t yet received our result.

To solve both of these problems, we would need to change the behavior of NSBlockOperation so that it isn’t marked finished until we say so. Since we can’t change the behavior of that class, we’d have to write our own NSOperation subclass with that capability:

let one = MyAsynchrousOperation { finish in
  doSomethingSlowly(completion:{
    print(“One”)
    finish()
  }
}

let two = BlockOperation {
  print("Two")
}

two.addDependency(one)

// Prints:
//  One
//  Two

Writing NSOperation subclasses is something every Swift developer should know how to do, but it’s still a pain in the a**. It would be preferable to have an abstract base class that subclasses NSOperation, adding built-in support for asynchronous execution in a way that can be extended for any arbitrary purpose. That’s what AsyncOperations aims to provide.

AsyncOperations

There are four classes in AsyncOperations:

Examples

|  19 Oct 2016