inessential by Brent Simmons

April 2016

In Praise of Swift

In Performance These Days I argued that developer productivity is more important than the speed of a given language.

And while I wish for an Objective-C without the C and with the cool parts from Swift, I also realize that it’s not going to happen, and I’m fine with that.

* * *

I’m at the point where I get bugged if I have to write Objective-C code.

I don’t think I’m actually more productive in Swift yet, but that’s not the fault of Swift — that’s just how it goes when you switch languages and the previous language was your primary language for more than a decade.

Writing Swift code feels like driving a hot rod. Sometimes it feels like driving a hot rod into a brick wall. But still: it’s a goddamn hot rod.

If I had just two feature requests, they’d be:

  1. Allow Set<SomeProtocol>. This is a major part of protocol-oriented programming for me. Comes up all the time.

  2. Support KVC. (Note that I specify KVC and not KVO, which I don’t care for.) I use KVC only rarely, but when I use it it saves a ton of tedious, error-prone code.

Both of these issues keep me tied to some degree to Objective-C — or at least to NSObject and the Objective-C runtime — for now.

* * *

Okay, I have a third feature request. And it’s a big one. It’s kind-of for the Swift team, but it’s really for everyone who works on developer tools at Apple.

I’d like to see those teams look at a whole bunch of actual Xcode projects and source for shipping apps and do some analysis. Where do developers struggle? What takes too much work?

The goal is to use these projects to keep answering the question: how can writing high-quality apps be made easier?

It’s not enough to look at apps written inside Apple — these apps should come from outside. I’d bet that many developers would be happy to (confidentially, of course) submit their projects for this effort. I certainly would.

And it’s not enough just to hear what developers say. (Though that’s important too.) There’s no replacement for seeing what they actually do.

It’s kind of like when you work on performance issues. You may think you know what’s slow, but there’s no replacement for actually running the profiler and seeing what’s slow. Same with this: there’s nothing like actually seeing what problems need solutions.

Maybe this is already being done and I just don’t know about it. If so, then cool.

* * *

Did I mention that Swift is a hot rod? And I need to go work on some Objective-C code, and I’m procrastinating because it’s Objective-C and I want to go drive my fast car instead.

PS Daniel Jalkut suggests writing unit tests in Swift. Me, I’m writing all new code in Swift. But if you haven’t started writing with Swift yet, then you should listen to Daniel.

Performance These Days

Mike Ash reports that objc_msgSend takes 2.6 nanoseconds on his Mac and 2.7 nanoseconds on his iPhone. This shouldn’t come as much surprise — we’ve known since Mike’s first report in 2007 that objc_msgSend is fast. (Though this function isn’t the only measure of Objective-C’s speed relative to other languages, it’s indicative.)

So Objective-C is fast — but it hardly matters, because almost all of your code might as well be written in Ruby. (Or in any relatively slow scripting language.)

Pushing a view controller onto a navigation controller takes the time it takes. Your text fields won’t draw their strings any faster just because you’re using Swift instead of Python. Hitting the disk is still hitting the disk.

There may be some things your app does that need to be super-fast. Parsing email messages or RSS feeds, for instance. Processing audio. You wouldn’t want to use a scripting language for those — you’d want something like Objective-C or Swift, or even C or C++ — to make those parts fast. (And you probably want to move those things off the main thread.)

But that’s the minority of your app, by far. Imagine a typical RSS reader — what percentage of the code makes up the feed and OPML parsers? Well under 1%, I’d bet. The rest might as well be in Lua or JavaScript, and users would never feel the difference, because there would hardly be a difference.

Maybe Swift is faster than Objective-C, or will be. But that also hardly matters.

Performance does matter

That’s not to say performance doesn’t matter. It totally matters. If an RSS reader blocks the main thread while parsing feeds — and is slow at parsing feeds — it’s going to suck.

But making things fast has to do with choosing fast data structures and algorithms, moving things off the main thread when needed, and figuring out which of the other things Mike Ash lists as slow (such as object creation and disk access) you can avoid. Switching to Swift — or whatever — isn’t going to make a slow algorithm appreciably faster.

Another kind of performance

Instead of language performance the focus should be on developer productivity. Developer performance. That’s the thing that counts these days.

Swift makes a bunch of leaps forward here and some leaps back. Awesome things: type inference (I could stop right there and be done); not having separate header files; easier syntax for blocks; let for immutable variables; map and filter (though easily done in Objective-C); protocol extensions; etc.

And yet it’s stuffier than Objective-C, and in some respects feels like a lower-level language. We’ve given up dynamic dispatch (largely) and gained optionals and a stricter type system. We’ve also given up simplicity (assuming you know C, and you should, the “Objective” part is pretty small) for a much more complex language.

Objective-C has way too much housekeeping, yes. Totally. And yet, in Swift, I sometimes feel like I’m filling out a form in triplicate before I can use a variable, or faxing various department heads before I can call a method.

Where Swift is awesome and not-awesome

As a system programming language, Swift is, I strongly suspect, utterly brilliant. I want that kind of programming to be buttoned-down. Absolutely.

Swift seems like the answer to the question: “What would a language for system programming look like that’s both safer and better for productivity than C and C++?”

The problem is, the answer to that particular question is not necessarily the same as the answer to the question, “What would a language for app programming look like that’s both safer and better for productivity than Objective-C?”

The safer part is easy: remove the C. Huge win right there.

But I think Swift otherwise gives and takes away — we get type inference and all the lovely things I mentioned before, but we end up fighting the type system, standing on our heads to deal with optionals, and working with a language that’s much larger (demonstrably) than is needed for writing great apps. It solves a whole bunch of problems that didn’t need solving (for app-writing).

I’d rather we focused harder on making writing high-quality apps easier. A scripting language, or something spiritually close, that took the best parts of Swift, but was much smaller and simpler, more supple, that ran on the Objective-C runtime — dynamic dispatch and all — would have been ideal. I could fly in that language.

Yes, I realize that would have meant pushing some errors from compile time to run time, in exactly the same way Objective-C does right now.

But I don’t care — I’d take that trade-off every single day of the week.

Quantify.app

The folks making “App: the Human Story” have just released their own app: Quantify.

The idea is that while you’re shooting video — an interview or whatever — you can rate the action as it goes along, and then you have that when you go to edit. Saves a ton of time.

If I made videos, I’d get this app.

PS The latest update on the documentary:

We’re pushing hard and plan on showing you the film the first part of June, right before WWDC.

Good timing.

High-Level Events

I wrote, in The Objective-C Version, that one of the major advances of Cocoa over the Macintosh Toolbox was event routing. Both frameworks were event-driven, but with Toolbox code you had to dispatch events manually to their proper places, while in Cocoa you hooked-up events and methods more directly. Which was genius.

But now we’ve been doing it the Cocoa way for years (and decades, for some people), and we take it for granted. We take it for granted so much that we’re now able to realize what a pain it can be. The thing Cocoa is missing — and what the reactive-programming folks get — is the notion of high-level events.

If events such as IBActions, NSNotifications, KVO-fires, timer-fires, delegate callbacks, and so on are primitive events, then a high-level event should be a composition of primitive events and conditions that don’t have to happen at the same instant.

Example

Consider again that live-search textfield from Comparing Reactive and Traditional.

There are two high-level events that could be described like this:

Textfield search event:

Primitive event: textField.stringValue changed
Condition: textField.stringValue.count >= 3
Condition: textField.stringValue unchanged for 0.3 seconds
Action: runFetch(textField.stringValue)

Refresh button search event:

Primitive event: refresh button action method called
Condition: textField.stringValue.count >= 3
Action: runFetch(textField.stringValue)

I’m not saying we want to describe them using the syntax above — but it’s clear (from the above, and from RxSwift) that it is possible to specify high-level events.

It’s also clear (self-evident, I hope) that declaring high-level events means less code that synthesizes high-level events by querying and maintaining state (which is where your bugs come from).

(It’s also clear, I hope, that this is not all that RxSwift does. But it’s the part I’m interested in.)

How Apple might do it

It’s tempting to say that our synthesizing high-level events by breaking them down into small, logical pieces is why they pay us the big bucks. It’s what we’re trained to do, after all.

But that argument could be used against every single advance in app-writing, so let’s forget it.

Instead, let’s imagine how Apple might solve the problem.

Since high-level events are a UX thing, there would be some way in Interface Builder for your designers to specify high-level events. A drag-and-drop, point-and-click thing.

You’d wire up some triggering event (the primitive event), then create a predicate (the conditions), set some attributes (coalesced or not, coalesce interval), and then link it to an action method.

Because magic is disallowed, there would also be a way to do it in code. You could instead instantiate an NSHighLevelEvent object and set the trigger, conditions, and action.

You could write NSHighLevelEvent yourself — or HighLevelEvent, since it’s not Apple’s if you write it yourself — minus the editing interface in IB. To get an idea of its API, imagine something like this (quickly-typed thing) in your view controller:

let textField​RunSearchEvent = HighLevelEvent​(observationTarget: self, key: "currentText")
textField​RunSearchEvent.​coalesced = true
textField​RunSearchEvent.​coalesceInterval = 0.3
textField​RunSearchEvent.​condition = NSPredicate​(…)
textField​RunSearchEvent.​target = self
textField​RunSearchEvent.​action = #selector​(runSearch(_:))

What it means: when viewController.currentText changes (let’s assume HighLevelEvent always considers distinct changes), it coalesces changes for 0.3 seconds. Then it evaluates the predicate — and, if true, it then calls target.action(sender).

Obviously this is an object-oriented approach and is unlike reactive code. It has the benefit of fitting in better with the existing Apple frameworks (and the style of code most iOS and Mac developers have been using since OS X came out).

I do not suggest that this solves all the same problems RxSwift solves — but I do suggest that this approach would make app-writing a bit easier. You let the HighLevelEvent handle state (including setting up and tearing down a timer when needed).

Aside from setting up the HighLevelEvent, you’d have code that looks something like this in your view controller. Standard stuff:

func textDidChange(textField: NSTextField) {
  currentText = textField.stringValue
}

@IBAction func runSearch(sender: AnyObject) {
  …
}

In other words, this would fit in nicely with the way people write apps now, and would be something I’d use.

The Objective-C Version

In Comparing Reactive and Traditional I linked to two solutions to a specific problem: one in RxSwift and one traditional (but also Swift).

To round things out, a friend of mine wrote an Objective-C version. You can see the main view controller as a gist and you can download the entire sample project. (Because it’s not all in the gist.)

My friend writes:

The rules outlined in Comparing Reactive and Traditional represent the business logic for contacting the server: coalesce requests over a timeout period, coalesce non-unique consecutive requests, and ignore requests shorter than a specified length. If I’ve learnt anything in nearly 30 years of writing software, it’s you don’t want to put business logic in the UI. Working with UI is complicated enough without embedding your business logic there. That’s why the business logic is embedded in the Fetcher object – mostly in the -fetchQuery:error: method.

Because we’re coalescing calls, having a method with a completion handler isn’t appropriate. One unifying theme in Apple’s use of completion handlers is they are ALWAYS called – either with a result or an error – the block is never just ignored. Because we plan to ignore many calls to our query method based on the business logic, either a property with a handler block or a delegate is appropriate. I chose a delegate, because they still have slightly more historical precedence.

I inferred from Brent’s implementation the rule that new queries should cancel incomplete queries. I’m not certain whether that’s correct, but it seemed appropriate to prevent responses coming out of order.

* * *

Also: Jorge Bernal’s post From traditional to reactive is worth reading — he takes the traditional version to the next level (closer to something you’d actually write), by creating a Throttle object.

He writes:

There’s no silver bullet, and that’s also true for RxSwift, but I believe it can help. I can’t imagine reasoning about all the possible states in a more traditional design.

And:

I also would argue (although someone might disagree) that any time you use NSNotificationCenter, NSFetchedResultsController, or KVO, you are already doing some sort of reactive programming, just not in a declarative way.

In the Macintosh Toolbox days we wrote code that polled the event loop via GetNextEvent. Our code examined the event and handled dispatching it to the right place in the app. This was a huge pain, and you can be glad if you’ve never had to write code like that.

I first experienced the joy of AppKit when I created a menu item in Interface Builder, wired it up to an action method, and then wrote the code in that action method to handle that specific command.

Responding to events in this way is far better than the old-fashioned method. I don’t know if I’d call it reactive, though — I’d just go with event-driven.

(Even the Toolbox version was event-driven — it’s just that it didn’t help with event routing, which is a thing we now take for granted.)

Reactive Followup

Junior B. posted a good follow-up to his post that I had replied to previously. See To React, Or Not To React.

Other followup…

On using other people’s code

Brian Gerstle asks:

@brentsimmons is it fair to say your only criticism of Reactive is that—in this case—its 3rd party code? If it was Apple, you’d use it?

I’m cautious with third-party code. I do use some: FMDB, for example, appears in every app I’ve started from scratch in the last decade or so.

I like FMDB because the code is available (which is an obvious must-have); it’s relatively small; it does one job — providing an Objective-C wrapper for SQLite — and does it well; and it’s used in just one small section of my apps and has no impact otherwise.

Another example: recently I looked at at Fletcher Penney’s MultiMarkdown parser, which I might use in an app I’m working on — and I like it for the same reasons I like FMDB.

I don’t have hard-and-fast rules about when to use other people’s code and when not to. But I’m most likely to say yes when the code is essentially a library that performs one conceptual function (database access, Markdown parsing, etc.).

I ask myself: what if something goes wrong and I can’t use Framework X anymore? Can I replace it somehow? Some amount of effort is fine, but rewriting and re-testing vast portions of the app is not acceptable.

I could write my own SQLite wrapper if I had to, and I could write my own Markdown parser. (Or find replacements written by other people.)

What if Apple made RxSwift?

Were Apple to provide reactive UIKit and AppKit and say, “Here’s how you make apps in the future,” I would expect that the tools would support this new style, and I’d expect it to play well with accessibility and AppleScript support and everything else. It would be well-integrated.

I’ve spent decades following Apple’s lead. People who don’t follow along end up in tight places — wishing for 64-bit Carbon, for instance.

That’s not say it always works out. Garbage collection, for example, was a dead-end (but with ARC it had a great replacement).

But, yes, I’d follow Apple’s lead into the reactive future in that case.

Not my only criticism

I wouldn’t be that happy about following Apple’s lead into the reactive future — if, that is, their implementation looked much like current versions.

So, no, not-being-Apple-code is not my only criticism. Another of my criticisms is that it’s difficult to read.

I’ve had a number of conversations with other developers on the subject, over many months, and almost every single developer that I talked to uses strong and inflammatory language about its unreadability.

If you’re a fan of this style, you might think that developers shouldn’t feel this way. My point is that, like it or not, they do.

You might not remember what it was like to look at this code before you understood it. Or you might be the kind of person who naturally takes to this particular style, and maybe it never seemed alien to you at all. Totally fine, of course, but remember that you’re not typical.

The revolution

I agree strongly with reactive proponents who say that the current standard ways of writing apps are broken. Too much state, for sure, and not enough ways to specify flow.

The less state we have to manage, and the more declarative code we can write, the better. I’m totally on board.

But if the revolution is about using this specific set of APIs, then I’m not on board.

My hope is that we’re using this specific set of APIs as a stepping-stone on the path to something better, something that appeals to a broader set of developers.

In the meantime, you could insist that there’s no readability issue, but I think that if you do then you’re potentially holding back the larger goal.

You could say, instead, “Yes, I know it sometimes looks like Perl in a blender. But we’re making the future here, and it doesn’t always start out pretty and it certainly doesn’t start out universally liked. This is step one. This is how we get from here to there.”

If so, then you’re taking one for the team, and I’m not — and I thank you.

PS Attribution note: the Perl-in-a-blender bit comes from Martin Pilkington:

I’ve yet to see reactive code that didn’t look like Perl shoved in a blender, even though I like the idea in theory

PPS I may not have this story entirely right, but it went something like this: Picasso invents Cubism, and people think it’s ugly. Because it is. Then Braque, or Derain, or both (I forget) come along and do a prettier version. Picasso remarks that it takes a genius to do the first ugly version, and the people who make it nice don’t have to be geniuses.

(Or maybe it was Stravinsky, and it was some musical thing. Whatever. I like the honesty about the first genius version being ugly.)

Comparing Reactive and Traditional

My friends Jamie Pinkham and Casey Liss wrote a short sample meant to illustrate the kind of code you’d write in RxSwift to implement a text field that runs a search via the web and then updates a table view.

The rules:

  • Changes to the search text must be coalesced over a period of 0.3 seconds.

  • When the search text changes, and the text has four or more characters, an http call is made, and the previous http call (if there is one) must be canceled.

  • When the http call returns, the table is updated.

  • And: there’s also a Refresh button that triggers an http call right away.

Basic live search text field, in other words, with just the added wrinkle of a Refresh button.

Because I thought it would be fair to compare to a traditional version, I wrote one. Both samples — theirs and mine — surely have errors, and neither compiles. They’re for the sake of discussion rather than meant as actual, running code.

Here they are:

Reactive version by Jamie and Casey
Traditional version by me

Status Quo

The traditional version is, in general shape, the same code you’d have written 15 years ago. We have blocks and Swift and ARC now, and so it’s smaller and simpler — and more readable and maintainable — than it used to be. But the main idea is the same. And we’re all just plain tired of writing code like this.

The two biggest knocks against it:

  1. Dealing with mutable state sucks. Every time you add something it gets more complex. “State” is a fancy name for “where bugs live.”

  2. There’s no high-level view of what’s actually happening, unless it’s in a comment. It’s a collection of small functions and properties without a linear story.

It’s not all bad, though. It sticks close to the frameworks and the language, and so any Cocoa developer can understand it, even the newest member of your team. The properties and functions are named reasonably well, and they’re small and logical. It’s the least clever thing you can imagine that still does the job.

New Coolness

The reactive version has the advantages that the traditional version lacks:

  1. There is far less state to manage directly.

  2. There is a linear description of what happens — it reads almost like a paragraph.

These are huge advantages. Giant.

It’s not all good, though. To the uninitiated, it looks like write-only code, which means the newest member of your team faces a learning curve. It also means there’s a large dependency on a third-party framework.

The trade-offs

As a (very) hypothetical CTO, I’d nix any dependency that great, and especially one that comes with that much learning curve. But that’s just me — another person might say the trade-offs are worth it. (See those awesome advantages again.)

My experience tells me to avoid cleverness and stick as closely as possible to what Apple provides — “don’t fight the frameworks” is old and still-good advice. This is not just for the sake of new members to the team but also for the sake of the future, so that you can debug and extend the code in one year or five years or ten without rewriting it. It also means that as the frameworks evolve you can take advantage of those changes with the least amount of trouble.

Another worry is illustrated by the use of throttle(0.3) in the reactive version. I seriously doubt that it’s polling textField.​stringValue every 0.3 seconds — but you have to look, because you’re responsible for the quality of your app, which means you have to know implementation details about the framework.

But!

But doesn’t the traditional version just plain suck?

Damn right it does, and, even though it’s gotten easier to write these things, it’s been just matters of degree. We’ve been writing this stuff that same way for a long time, and it’s still bug-prone and tedious, and I don’t want to do it any more than you do.

I think the future is declarative, and the Reactive solution is closer to that in many ways — it tells the story of the flow. But one problem with it is that it’s not that readable. The traditional version is, in some ways, more readable.

What I really want

I want to be able to write something like this:

  • runFetch with textField.stringValue when textField.stringValue changes and its character count is 4 or greater, with changes coalesced by 0.3 seconds.

  • runFetch withTextField.stringValue when the Refresh button is tapped.

But if I look at the above, it looks kind-of like AppleScript. And that means it will fake you out — it looks like English, but in reality it would be strict and weird and hard-to-write. So I don’t really want to write faux-English code.

I think I want something more like this:

runFetch with textField.stringValue when {
  textField.stringValue changes {
    distinctly
    coalescedBy(0.3)
    count >= 4
  }
  or button "Refresh" tapped
}

That’s not Swift, or anything else, of course.

Change

Part of me does not want to encourage people to use RxSwift for the reasons I’ve outlined. But part of me very much wants to encourage people to use RxSwift — because change comes, in part, from the community pushing the state of the art.

(Example: were it not for all the enthusiasm for functional programming in recent years, Swift might not have filter and map functions.)

Luckily, you’re not going to listen to me either way.

If you don’t use RxSwift, I totally don’t blame you. We’re in the same boat.

But if you do use it, and some time in the future there’s a nice, declarative way of handling events and dealing with state, then I’ll have you to thank for helping make that come true.

PS Jamie wrote an entire working example that uses RxSwift. Definitely check it out. (Huge thanks go to Jamie and Casey for all their work here. Top-notch humans.)

The Non-Reactive Solution

The Reactive Revolution in Swift intrigued me not only because the solution was different from what I’d normally write but so was the problem.

Here is what’s going on (I think):

  1. A view controller, part of a chat app, initiates reading data from a socket.

  2. The view controller parses that data into a message object.

  3. The view controller adds the parsed message to its array of messages. (And, presumably, updates the UI.)

The Old-Fashioned Way

The old-fashioned way is presented like this:

On a background queue, load the data and parse it. Then call back to the main thread and update the messages array and the UI.

This is clearly wrong. The author is absolutely right to call this “callback hell” — he’d be right to use stronger language. This is not how you do things.

In fact: any time a view controller is making network calls, it’s wrong. Any time a view controller references any kind of queues or background threads, it’s wrong. (View controllers — and views — are main-thread-only creatures.)

The New-Fashioned Way

The new-fashioned solution, according to the author, is to use Reactive Programming via RxSwift.

I think, but I can’t tell for sure, that roughly the same thing is going on. (It’s hard for me to read, which surely can be explained by my not knowing RxSwift. The addDisposableTo(disposeBag) part especially worries me, since it looks like a parallel memory management system.)

But let’s set that aside and talk about how I’d solve this problem.

How I’d Actually Write It

First thing: the view controller should not be reading data from a socket and parsing the data.

Instead there should be a separate network controller object whose lifetime is not tied to the view controller’s lifetime.

It may be that the view controller needs to tell that network controller to do a thing — such as download more messages — and that’s fine. So give the view controller access to the network controller. A refresh() method or whatever.

Ideally, the network controller makes an http call via NSURLSession — this is almost always preferable to sockets. But let’s assume that the server API uses a socket.

So that network controller has a background queue of some kind, which could be a serial queue if needed. Or an NSOperationQueue. Whatever. On that queue it…

  1. Loads data from the socket.

  2. Parses the data into a JSQMessage object. (JSQMessage is from the original blog post.)

Then, on the main thread, it posts a NewMessage notification meaning that there’s a new JSQMessage.

This way the network controller knows nothing about any view controllers. It knows how to pull data and turn it into an object, and it does so without blocking the main thread.

Yes, you might use GCD, or you might use NSOperationQueue + performSelectorOnMainThread — but, either way, the use of background threads is entirely hidden inside the network controller. The outside world can’t see in and doesn’t know those implementation details.

This way threading issues don’t leak out of the network controller, which is crucially important.

And though you’re potentially using a callback (depending on how you do it) you don’t have to nest them into some kind of hellish situation. It’s minimal, readable, and debuggable.

The chat view controller then needs to do three things:

  1. Subscribe to the NewMessage notification.

  2. Handle the NewMessage notification by appending to the messages array.

  3. Update the UI when the messages array changes.

The second step looks something like this. (Typed into MarsEdit, not actually compiled; might not be completely correct.)

dynamic func newMessage​DidDownload​(notification: NSNotification) {
  if let message: JSQMessage = notification.​userInfo​[messageKey] as? JSQMessage {
    messages = messages + [message]
</code>  }</code>
</code>}</code>

The messages property should have a didSet method which calls the thing that updates the UI. This way, any time you change that array, the UI updates.

(In the real world, by the way, it’s probably plural — you don’t handle one new message but potentially many new messages.)

NSNotificationCenter is, I grant, old-school and totally not glamorous. It just plain works, simply and reliably. Among other things, it has the advantage of being a well-known part of the Foundation framework, and you ought to be able to count on every Mac and iOS developer to know how it works and how to use it.

No Locks Needed

From the original article:

Asynchronous programming is not just about running tasks or perform computation in a separate thread, at some point, we will need to synchronize values across threads and the most common solution is to add locks. As soon as locks are introduced, the complexity of the code raises of at least one order of magnitude and one big new component is added to the complexity equation: unpredictability.

There are no locks in the solution I outline above. (I’ve used that general pattern in NetNewsWire, Glassboard, Vesper, and in my two in-development apps — I know it works.)

At most there might be a serial queue, but I don’t think I’ve ever used a serial queue with networking. (I do use them for database access, though.)

Here are the tricks: views and view controllers should be main-thread-only. When you have a task in a controller that can block the main thread, make it isolatable and use a background queue of some kind — but keep that implementation detail hidden from the rest of the app. And any networking and parsing must be done in an object whose lifetime isn’t tied to the view controller’s lifetime.

* * *

I’m not saying that Reactive programming is bad, or that RxSwift is bad. I totally don’t know enough to say.

However, there are problems — such as the one the author presents — that have existing solutions that don’t require callback hell, or locks, or tricky-to-understand threading issues.

I don’t think the author intends to misrepresent current best practices — they may just not be as well-known as I think they are. Hence this article.

PS Definitely read Marcus Zarra’s Exploring MVC-N in Swift. While Marcus and I might implement some details differently, those details are matters of style — in broader terms we are absolutely sitting at the same counter.

PPS I struggled with this article because the last thing I want to do is discourage a developer who’s presumably younger than I am (safe bet) to stop writing. Note to the author: if you’re of a mind to, please write a follow-up! I’ll happily and very gladly link to it.

On UIKit for Macs

Every time it comes up that Macs should support some sort of extended UIKit rather than AppKit, I think about all the differences between Macs and iOS devices.

On iOS you don’t have to deal with multiple, resizable, movable windows open at the time. Or with being open but not frontmost. Or with a window moving between screens with different resolutions.

You don’t have menus (for the most part), and I’d bet most iOS developers don’t have to think about the responder chain much, or about enabling and disabling user interface items.

There’s no AppleScript support.

And sandboxing is a whole other thing on Macs. Etc.

* * *

There are plenty the two platforms have in common — and, indeed, we use some of the same frameworks: Foundation and Core Data, for instance. It’s already true that an app can share its under-the-hood code between Mac and iOS. You can even share some UI code via Quartz and Core Animation.

However, there are areas where AppKit and UIKit have the same things but with slightly different APIs: tables, for instance, are similar but different between the two platforms. NSView (Mac) and UIView (iOS) are nearly the same, but aren’t actually the same.

And there are things Macs don’t have at all — navigation controllers, for instance, since they don’t make sense in a context where you can just show the hierarchy via multiple panes.

* * *

Were Macs to get some form of UIKit, it would have to be extended with all the things Macs need. Let’s assume we’ll still have multiple, resizable, movable windows; we’ll still have a menubar; we’ll still have AppleScript and Services and similar.

Anybody bringing an iOS app to the Mac is going to have to learn those things and handle them. This is a much bigger deal than just getting an iPhone app working on iPads.

I think the premise is that the porting job would be quicker if Macs supported things like UITableView — you wouldn’t have to rewrite your table view to make it work on Macs.

But I have to wonder. Given that there’s a bunch of stuff you’d have to learn and do in any case, how onerous is the difference between NSTableView and UITableView? They’re extremely similar already.

Your biggest challenge is probably just that the dimensions of a table view (or most any view) can change arbitrarily, at any time, on a Mac — and you’d have to deal with that whether you were using UIKit or AppKit.

* * *

I have a theory on why there aren’t more Mac apps.

One is that the additional stuff — menus, live resizing, AppleScript, etc. — is enough of a burden that people just don’t want to do it. You’d still have those things even with UIKit for Macs: they’d have to be added to UIKit, and so that particular burden is not going away.

But I think the more important reason is that Macs aren’t exciting to most developers in the way iOS devices are exciting. Macs are where people quietly get their work done, in much the same ways they did 10 and 20 years ago. There’s your spreadsheet and your word processor. Web browser and email. Graphics editor and text editor. Chat window. You may be swiping a bit these days, but you’re also still just clicking with a mouse.

It’s boring.

(That is, until you realize that Mac users love software that helps them get their work done. They support indies and small businesses passionately. Doing great work for these folks is terrifically exciting — but I realize you’re not going to listen to me.)

How do you fix that? How do you make Mac apps exciting to developers?

I think — perhaps surprisingly — that you bring UIKit to the Mac. Even though I’ve spent just about this entire post explaining why it’s not needed and wouldn’t be particularly helpful, I think you do it anyway, as marketing to developers.

There’s a risk, though — once developers realize that UIKit for Macs doesn’t get them out of dealing with all that extra stuff Mac apps need, they may complain that Mac apps are still too much work. Sure.

But I think you do it anyway. Note to Apple: go for it.