inessential by Brent Simmons

February 2015

Ethics

Were software engineer a profession like doctor or lawyer, we’d have a strong and binding set of ethics.

I note that the ACM publishes a code of ethics. Here’s the first one:

  1. PUBLIC - Software engineers shall act consistently with the public interest.

Nowhere in the short list, or in the elaboration below, are the words “spy” or “monitor.” You could argue that you don’t need to call out those, because acting “consistently with the public interest” is enough.

But I think we’re at the point — between the NSA, draconian workplace monitoring systems, social network data collection, and malware — that calling out spying and monitoring specifically as unethical is warranted.

After all, you can argue that spying is necessary for national security, which is clearly in the public interest. And you can argue that workplace monitoring is either neutral (employers are within their rights to know what employees are doing with what resources) or a public good (more productivity is good for the economy).

But these are wrong.

Defining the lines gets interesting, though. Lots of apps collect crash logs and transmit them to the developers. Presumably there is some place where the user agreed to this collection. But is this monitoring? No. But defining things so that we can tell the difference, and so that the definition can handle scenarios not yet invented, could be tricky.

(Consent isn’t always enough. You may have to consent to workplace monitoring as a condition of employment. This isn’t, in many cases, a fair situation — not when you need a job to pay the bills.)

Another case: is it wrong to write code to spy on people who are actively planning to kill other people? Eeeesh. I would think not. But then how does the engineer assure that this is the only way that code would be used?

Assuming we could define things — a big assumption — then the value to society would be this: engineers would have the support of society when they refuse to do something that’s wrong. Right now they just lose their jobs.

But imagine if they could say, “No. I won’t. That violates the software engineering code of ethics,” and it would have the same weight as a doctor or lawyer refusing to act unethically.

And imagine if there were consequences when they didn’t refuse.

Reason Number 33,483 to Hate Programming

In one of the several apps I work on, I have a controller class that runs into a solution like this:

While the app is quitting, and things are being torn down, the controller class runs code it doesn’t need to run — because it watches for notifications of various types and does things. And code from elsewhere calls into the controller class for the same reason.

Well, that code shouldn’t run at app-quit time, since it’s extra work that doesn’t need to happen. And, worse, the object graph can be in a weird, partway-torn-down state, and any work done then could cause a crash.

The non-beautiful but acceptable and expedient solution was for the controller class to watch for the app-will-terminate notification and set an internal property (appIsTerminating) to YES when it gets it.

A few methods that I know for sure shouldn’t run at app-quit time (because they update the display) then return early when self.appIsTerminating.

This makes quitting faster, and some crashing bugs are avoided. And there are maybe 10 new lines of code.

(A better solution involves an audit of a bunch of code and a bunch of thinking and testing. Several days of work in this case. Possibly a week. Not worth it.)

But Here’s Where Things Get Ugly (or Uglier)

That controller class has a couple subclasses. Without those subclasses the parent class would have a bunch of nasty switch statements. Not good. Those subclasses are needed. (I like to avoid subclasses as much as possible, but there you go.)

But then I found that one of the subclasses also needs to know when the app is quitting — for the same reason of avoiding work at app-quit time. How should I do that?

It could register for the app-will-terminate notification also. With the same selector, and then have that method call super? I don’t think I’ve ever written a notification handler that called super. That means declaring it in the .h file for the superclass. Erg. (And never mind that the notification handler would be called twice, since superclass and subclass both register for that notification — which wouldn’t hurt anything, but smells bad.)

Or the subclass could not register for the notification, but know that the superclass does, and implement the notification handler (and still call super inside the notification handler). But then the subclass knows a weird secret about the superclass. (Sure. It already does know a few secrets. But I prefer to write my subclasses as if they don’t know anything about super’s implementation.)

Or I could have the superclass expose the appIsTerminating property in its header file, so that the subclass could see it. This also sucks, because a controller class has no business exposing its own copy of global application state.

In the end, though, that’s what I did. (Along with a comment that the property was there for subclasses.)

It reminds me that there are two competing values:

  1. Do everything the right way every time.

  2. Make responsible and professional decisions about time and expenses and benefits and drawbacks.

This is a super-small thing. The code I added is clear and obvious, and there’s very little of it.

But still it makes me itch. I did this work a few days ago and I went to bed last night thinking about it. (And out pops a blog post the next day.)

There are times when I think I’m way too fussy. There are times when I think I’m not nearly fussy enough. Often those are the same times. I don’t know which is correct.

Looping Through Objects in an Array

One way to loop through objects and stop when you’ve found the one you want is the following:

for (id oneObject in someArray) {
  if ([oneObject passesTest]) {
    return oneObject;
  }
}

The return could as well be a break statement. And the code in Swift would be something like this (typed without compiling; probably has errors, but you get the point):

for oneObject in someArray {
  if oneObject.passesTest() {
    return oneObject
  }
}

I’ve long been a fan of this. It’s easy to read and understand. It’s efficient because it stops as soon as the object is found.

It’s also pretty easy to make something re-usable: you could make a firstObjectPassingTest: category method that takes a block that performs the test. Easy.

In 10.6 Apple added - (void)enumerateObjects​UsingBlock:​(void (^)​(id obj, NSUInteger idx, BOOL *stop))block;

Mike Ash:

For simple enumeration, the block syntax doesn’t really offer any advantage over fast enumeration and the for/in syntax. The syntax is a bit clumsier, and iteration is a bit slower. The code has to call your block for every object. This overhead is less than that of a message send, as in the NSEnumerator case, but is more than the simple C for loop of NSFastEnumeration.

There are cases — dictionaries in particular — where the block-based enumeration can be the best choice. But most of the time the for-in enumeration is the straightforward and less clever approach. (“Less clever” is a good thing.) It’s faster too.

And yet… I’ve been afraid to say this out loud, as it seems to me that the entire world is on a we-love-blocks-and-hate-loops kick. (Back this up? I can’t. I love blocks too, but I have nothing against loops, and I’ll take the simple, clear, readable loop over a blocks-based method when it makes sense, which is almost every time, though not every time.)

And then today there was this response from Chris Lattner (message #11). I can’t quote it because it’s on the confidential Apple forums. But I bet anybody who’s read this far also has access to the forums and knows who Chris Lattner is.

And now I feel better about for-in loops.

OmniFocus 2.1 for Mac Ships

Since starting at Omni late last September I’ve been working on OmniFocus 2.1 for Mac — and today it shipped. (It’s the first thing I’ve worked on at Omni to ship.)

The big changes are Yosemite-related: sharing menu, sharing and Today extensions, vibrant UI, new-style toolbar buttons, improved find-and-replace, and the tear-off view options popover. (Plus — my favorite — performance and stability fixes.)

OmniFocus, like every Omni app, is a team effort. It’s the work of engineers, designers, testers, project managers, writers, video-makers, and support humans — the whole company contributes, directly or indirectly, to every shipment.

While I’m proud of my work, I’m way more proud of the team’s work — because my work is just bits and pieces, and the team’s work is the entire app. And the app is good, and I feel good.

Three Xcode Tips

In case you don’t know these…

Really Clean

Instead of manually deleting the DerivedData folder, get Xcode to do it.

Hold down the option key, pull down the Product menu, and choose Clean Build Folder…

Normally that menu item is Clean…, but with the option key it’s really clean.

Keyboard shortcut: option-shift-cmd-K.

Callers

In that bar right above the source code, at top left, is a little icon made up of four rectangles. Click it to pull down a menu that includes a Callers submenu.

Put the cursor on any method name. Pull down the menu and see where it gets called.

(Note, however, that it won’t detect performWithSelector-style calls. So the Callers submenu could miss instances.)

The Find pasteboard

To search for some text, select it and hit cmd-E. The text will then appear in the find and search text fields.

No need to select the text, copy it, and then paste it into a text field.

Vaccines Again

Whenever the subject of vaccines come up, I remember my post from a few years ago about chicken pox. I wish the chicken pox vaccine had been available then. My eyes wouldn’t be so ruined.

What I didn’t tell in that original post — because I was so sick and barely aware of what was going on at the time, because my Mom told me about it after I wrote that post — was that I nearly didn’t survive. I was seriously dehydrated, since I couldn’t even sip water without throwing up, and I needed to go the hospital.

But there had been a blizzard. We lived at the bottom of a big, steep hill, and the car was parked at the top of the hill. My parents would have had to bundle me up and drag me on a sled up the hill to the car — and Mom tells me they weren’t sure I’d survive the trip.

Luckily I was finally able to drink a little water — well after going to the hospital was a good idea, but just before it was a desperate move in the cold and piled-up snow.

This is what these diseases are like sometimes. I’m reminded every single day when I take out my contact lenses and my vision becomes a solid blur.

Since I made it, since I survived, I can tell you about it. If I hadn’t, there’d just be silence where I would have been.

Update 1:15 pm: Mom reminds me it wasn’t water but cherry jello.

Swift 1.2 Beta

I didn’t expect to see this much improvement before WWDC. I’m very pleased.

Having accepted that Swift is Felix Unger to Objective-C’s Oscar Madison, I welcome changes that make Swift’s persnicketiness easier to satisfy.

My favorite change may be the improvements to if let. In the past, you’d write something like this:

if let a = foo() {
  if let b = bar() {
    doSomething(a, b)
  }
}

Now you can write:

if let a = foo(), b = bar() {
  doSomething(a, b)
}

(And more: you can include conditions with a where clause.)

So simple, so welcome.

I’m not sure what I think about the new annotations for Objective-C: nonnull, nullable, null_unspecified, and null_resettable.

On one hand it’s a leakage from Swift into Objective-C — as if Felix is wearing down Oscar until he gives in and picks his clothes off the floor and washes his hands 50 times a day. And it’s not like this has ever been a problem for me in Objective-C. (Objective-C’s nil-handling behavior was a delight when I switched from C, and I still like it.)

On the other hand, maybe I’m worn down a little bit too, and I don’t mind if the tools help ensure that my code matches my intentions. Most likely, though, I’ll use these only with Objective-C code that Swift needs to know about, because it will make things easier when writing Swift.

There are a bunch of other solid changes: read the release notes if you haven’t already. The day when I’m writing most code in Swift has just gotten closer.

With all the great things, we’re still not at Swift nirvana. I checked one of my favorite examples: impathic’s one-liner that takes 40 seconds to compile. It still takes about 40 seconds. But, well, that’s software development for ya.

PS Swift has a Set type now! I love sets. Use ’em all the time.

UXKit Again

Garrett Murray, one of the great iOS developers, tweets:

I do sort of dream of this world though where building UI for iOS/Mac/Watch all uses very similar code.

You could say that it already is very similar code. Everything under the hood is the same — Foundation is the the same, Core Data is the same, networking is the same, and so on.

The code that needs to be different is UI code. But, even there, you have so many things that are again the same (auto layout and storyboards) and things that are very similar, that use the same concepts with slightly different names (colors and fonts, gesture recognizers, view controllers, table views, text views, image views, popovers, and so on).

The big differences — and there are some — can’t be attributed to the frameworks: they’re differences of the platform.

An example: iOS uses navigation controllers for hierarchical data, while Macs use multiple panes. (I’m aware that iOS has split views, but, in general, iOS uses time where Macs use space. I’ve never seen a three-paned iOS app, and I hope I never do.)

Macs have menus and multiple resizable (closable, minimizable) windows. Macs have configurable toolbars; Macs have mice. Macs let you drag-and-drop between apps. Mac apps are scriptable.

By the time you’ve unified all this into one framework, you’ve either done a disservice to one or both platforms (by removing or changing things that people expect from the platform), or you haven’t really gained anything, as the differences between the platforms still need to be expressed in the framework, and learning how to write Mac apps would still be roughly the same-sized job it is right now.

Programmers like it when differences can be collapsed, when we can use one thing to make two things happen. But we also have to remember that different things really should be different — and not just different, but obviously different.

I have no illusions that I can talk any iOS developers into Mac development. I will say that it’s fun, though, for a bunch of reasons. Your apps run on the same machine as your development environment. You have the freedom to distribute outside the app store. You have a chance to write something that all your peers — many of whom are also programmers — will run all day long on their Macs. (And you have a decent chance of making better money. Mac users tend to be loyal and supportive and awesome.)

The thing to do isn’t to treat the Mac as a weird version of iOS, though. The Mac UI is great (though, like iOS, not without warts) and the platform is worthy of your understanding and respect. The thing to do isn’t to wish there were navigation controllers and similar on Macs — instead, it’s to figure out what’s the best Mac version of your UI. Different APIs are the last thing to be concerned with: you’ll learn those. The harder part — and the interesting and challenging part — is designing a great Mac app.

Update 4:40 pm: Garrett Murray follows up on his blog with some great points:

If I want to create a label, I’d love to create a UILabel (or, say, UXLabel) and know that by default it would perform in a logical way on all platforms. TableViews, animations, all of these core components would share a logical API you could use with little concern for how they behave and perform at the default level. Obviously, things like NSMenu would be on OS X only. That isn’t a deal-breaker for this. And sure, UXLabel might have some attributes available only on Watch. I think that’s all logical.

UXKit Skepticism

Some developers are excited to note that the new Photos app contains a private UXKit framework that, according to Jason Snell, “sits above the Mac’s familiar AppKit frameworks and strongly resembles UIKit on iOS.”

I doubt this will ever be available outside Apple as a framework that’s meant to replace AppKit.

Partly it’s a matter of resources. AppKit exists, and people make great apps with it. It’s hard to imagine Apple wanting to support another UI framework for developers outside Apple.

And it’s hard to imagine Apple adding this complication. Choice of language is one thing — but add the choice of UI framework and it looks like the company is flailing around.

It’s not like AppKit has stood still. With every release of OS X it’s more UIKit-like. It’s not a different country: it has auto layout, storyboards, view-based table views, gesture recognizers, and so on.

But AppKit also has things that don’t make sense on iOS: menus, resizable windows, resizable split views, AppleScript support, drag-and-drop between apps, mouse support, and so on. It has some time-saving (but optional) features such as Cocoa bindings that haven’t made it to iOS.

And UIKit has things that don’t make sense on Macs — navigation controllers and size classes, for instance. And where there are things that are the same on both platforms — toolbars, for instance — you’ll find that they’re not really the same.

AppKit and UIKit aren’t that different, and anybody working with one can switch to the other — with a learning curve, sure, but people who stick with one or the other are (hopefully) still always learning anyway.

But where they are different, the differences are critical.

With AppKit, Apple does what it does best: steady, incremental improvement. The AppKit of 10.10 is a very nice improvement over that of 10.9, as 10.9 was over 10.8, and so on. I expect that to continue.

Minimal UXKit

I could imagine a minimal UXKit that isn’t meant to replace AppKit but that can be used with both AppKit and UIKit. It might have UXColor, which would wrap UIColor and NSColor. Same with UXFont and UXImage. UXTableView could present a simplified superset of UITableView and NSTableView/NSOutlineView. Etc.

The point would be to make cross-platform development a little quicker — but it wouldn’t get you out of using UIKit and AppKit.

And, frankly, a bunch of this is super-easy stuff. You could make your own UXColor class by just defining it to UIColor or NSColor depending on target and adding category methods so that their interfaces match. (I’ve done this. I bet a bunch of people reading this have done it too.)

So I’m not sure there’s that much value in releasing a minimal UXKit — knowing that it would just be a source of feature requests and frustration, because it’s unlikely ever to do enough to make people happy who want to bring their iOS apps to the Mac.

What seems more likely is true convergence: imagine if, in the next OS releases, UIColor and NSColor, UIImage and NSImage, UIFont and NSFont, and so on were actually the same exact things.

My own experience

Would UXKit help OmniFocus or Vesper? No.

A Performance Enhancement for Variable-Height NSTableViews

Yesterday in one of the several Mac apps I work on I made a performance fix that could be useful to other people.

I have an NSTableView with variable-height rows. The height of the row is determined in large part by the height of the text in an NSTextField.

Unfortunately, text measurement is expensive, and measuring a ton of text as you resize a window causes terrible performance.

One common way to mitigate this is to use a cache so that you never measure the same text twice for a given width. And, in fact, there already was such a cache, so the performance wasn’t as bad as it would have been without it.

I did some testing in Instruments, and it told me that about 20% of the time spent during window resizing was calling the method that calculates row heights.

Then I noticed something about this particular case: quite often the text was just a single line. (Not always, but often. And it wouldn’t necessarily be true for all users. But true enough for enough users.)

So if the height was single-line-height at width n, the height would still be single-line-height at width n + x.

I wrote some code that takes that into account — and now Instruments reports that only 0.5% of the time during window resizing is spent in the calculate-row-height method. That’s a nice difference.

How It Works

There’s a property, calculated once, called heightForEmptyTitle. It stores the height of an empty string — @””.

There’s also a second cache (an NSCache), called singleLineWidthCache.

The method takes a title (the string to measure) and width.

The first thing to do is to ceil(width) — the title/width/height cache will be nearly worthless unless you round to integers.

Then it checks to see if heightForEmptyTitle has been calculated. If not, it does so.

Then it checks to see if title is nil or @”” — if so, then it just returns heightForEmptyTitle.

Then it looks for a cached height in singleLineWidthCache:

NSNumber *minWidthForSingleLine = [self.​singleLineWidthCache objectForKey:​title];
  if (minWidthForSingleLine) {
    if (width >= minWidthForSingleLine.​floatValue) {
      return self.​heightForEmptyTitle;
  }
}

If it finds it, and the passed-in width is greater than the cached width, then we know the height has to be the height of a single line, and we can just return that. (heightForEmptyTitle could also be called heightForSingleLine.)

If it doesn’t find it in the cache, or the width isn’t greater, then it moves on. It looks to see if that title/width combination is in the other cache (the cache that already existed in this method before I got to it). If so, it returns that cached height.

If it wasn’t cached there either, then it does string measurement. (By setting preferredMaxLayoutWidth on the NSTextField and then calling fittingSize.)

If it finds that the calculated height equals heightForEmptyTitle, then it may cache that information in the singleLineWidthCache.

if (titleHeight == self.​heightForEmptyTitle) {
  if (!minWidthForSingleLine || width < minWidthForSingleLine.​floatValue) {
    [self.​singleLineWidthCache setObject:​@(width) forKey:​title];
    return self.​heightForEmptyTitle;
  }
}

If it hadn’t found a previously cached value, or if the calculated value is less than the previously cached value, then it caches the new value.

Notes

The code assumes that the height of an empty title is the same as the height of a single line. This isn’t necessarily true (though it was true in my testing). The code is written so that when that assumption is incorrect, the only consequence is that you don’t get this caching. (You don’t get incorrect results.)

It also doesn’t do anything when multi-line text fields are more common. I have an idea for this, though. First look at all the cached height/width pairs for the title. If the passed-in width is between two cached widths that have the same height, then return that height. (In other words, if it has cached width/height 300/26 and 400/26, then a passed-in width of 350 should return a height of 26.) That’s something I still might try.

Also: I mentioned that this is for NSTableViews — but it works as well for NSOutlineView, and it ought to work on iOS as well (though it may be less needed there, since widths are less dynamic).

And it should go without saying that if something that affects text measurement changes — such as the font for the text field — then the caches should be tossed.

Random Swift Things

Last night I discussed Swift with some local developers. Some of it stuck in my head today. At random:

Question

It’s two years from now. Your company is hiring, and the best candidate has one drawback: all her experience is with Swift, and she’s barely acquainted with Objective-C. But she knows the frameworks well and has proven experience shipping quality software.

All of your existing code — and there’s a ton of it — is in Objective-C. Maybe there’s a little bit in Swift, maybe not, and maybe you’re open to doing more in Swift, and maybe not.

Do you hire this person?

Swift Is Hard

Objective-C looks hard because of the [ and ] syntax and all those words. It looks kind of mean, actually, like an angry grandpa with bushy eyebrows who makes you spell out “I am laughing out loud” instead of writing LOL.

But Objective-C is easy compared to Swift. Swift looks easier at first blush — every JavaScript developer sees it as familiar, and many think that this might be their way in to writing native apps.

More-familiar syntax will help more people get started, I think. But then you run into concepts that Objective-C doesn’t have to deal with (optionals, generics, and tuples, for instance) and concepts that Objective-C doesn’t have to deal with much (value versus reference semantics, functional design patterns, strict type safety). And you inevitably run into the issue of interoperation with Objective-C — which, obviously, isn’t a problem in Objective-C.

Angle-bracket-T Blindness

I’ll exaggerate a little — okay, a lot — to make a point. A popular form of blog post about Swift seems to be like this:

Here’s how you’d do things the crufty old-fashioned way:

for (id oneObject in someCollection) {
  [self doSomethingWithObject:oneObject];
  }

Well, you can tell by looking just how awful this is. Nasty loopses and untyped types. Let’s do it the modern way…

[snip]

[snip 200 lines of code]

func x<T> -> x<U> <TT> (in U -> <T>){$1 $2}.map(func y(T)<T><T> -> <U> infix $3 {

Clearly this is hyperbole and ridiculousness and line noise. I’m not being fair. But I think that anybody who reads a bunch of articles about Swift (as I do: I read everything I can find) recognizes what I’m talking about.

(There are many people who write wonderfully about Swift. Two of my favorites are NSHipster and David Owens II. But I still get angle-bracket-T blindness sometimes, even with them.)

Objective-C Hasn’t Finished Evolving

This is a prediction. It’s surely true that Apple has more existing Objective-C code than anyone else in the world. Improving Objective-C — especially if it means making their developers more productive and making their apps better — is in Apple’s best interest.

It’s possible we’ll even see some convergences — changes to Objective-C that make it easier for Objective-C and Swift to work together in the same code base.

I keep thinking it’s easier for Apple to upgrade Objective-C than to redo everything in Swift.

But Swift Is the Future

Swift’s adoption, and the enthusiasm around it, have surpassed my expectations — despite its very-much-still-early position. (If you have a developer account, read Apple’s Swift forum.)

Here’s the thing: if you go searching the web for solutions to some problem involving recent APIs, you’re extremely likely to run into Swift code. It’s happened to me plenty of times already — I’m translating from Swift to Objective-C as I read, which is not something I expected so soon.

Swift is happening.

P.S.

Yes, I’d hire the person with Swift experience but no Objective-C experience.