Brent Simmons’s weblog.

Overwhelmed in a Good Way 1 Apr 2020, 9:01 pm

I have never in my life had as many people getting in touch with me than over the past 24 hours. (I’m way behind on answering email and Twitter DMs.)

Many are messages of support, which I cherish and thank you for.

There are also people asking if I might be interested in working with them — which is awesome. I have an open mind, and all kinds of different work sound interesting to me.

I do have three requirements:

  • I’m going to stay in Seattle
  • I’m going to continue to work on NetNewsWire
  • I’m going to continue blogging here

I could work in an office again (once that kind of thing is possible again). Or not. I could do coding. Or writing. Or marketing or managing or designing. I could work on iOS or Mac apps. I could do something cloud-related. Good work is interesting, and I’m not stuck on any one particular type of work.

But the things that make me me won’t change. I’m a Seattle guy who blogs and writes an open source RSS reader.

* * *

Have I said how lucky I am? I am amazingly lucky and fortunate. There are plenty of people to worry about during the current crisis. I’m not one of those people.

Looking for Work 31 Mar 2020, 6:59 pm

Yesterday, along with about ten people (I’m not sure exactly), I was laid off from my job at the Omni Group, and now I’m looking for new work.

But first things first. You’re curious about Omni.

* * *

Omni’s been around for almost 30 years, and I hope it’s around for another 30. It’s one of the great Mac and iOS shops — they will sing songs about Omni, at maximum volume, in the great halls.

But businesses go up and down, and Omni’s had a bit of a down period. Normally that would be fine, but the current economic circumstances turn “a bit of a down period” into something more serious — and, in order to get things going the right way again, the company had to lay off some people. Including me.

This is, notably, the first time Omni has ever had to lay off people. And I bet that the company wouldn’t have had to this time, either — but, well, (gestures at everything) there’s all this.

It’s been my pleasure and my honor to be a part, for over five years, of the journey of this wonderful Mac and iOS app-making business.

While the company has some challenges ahead of it, I take heart in knowing it has been around for decades, and that it has calm, cool leadership and, especially, a great group of inspired people working hard to get back to the point where the company is thriving.

Omni deserves your love. I was just there, and I was just laid off — which is a hard thing — but I’m telling you it deserves your love.

* * *

Enough about Omni. Here’s me! I’m looking for work. I’m not sure if I prefer a full-time job or contracting positions — I think the actual work and the people matter more to me than how it’s structured.

If you read my blog, you know me: I ship great apps. I also design apps, write, host a podcast, do marketing, do community relations, project-manage things. Lots of skills right here. 🐣

If you might be interested and want to talk, email me at

* * *

The hard part of all this: normally everyone would get together for a happy hour for a few drops of encouragement and friendship. These rituals are nice, and they matter to me.

But — (gesturing again at this fallen world) — nope.

The iOS and Mac Markets Are the Same Size 27 Mar 2020, 9:45 pm

That headline is a bit provocative, I realize, and it doesn’t capture all the truth. So I’ll elaborate.

Download numbers for NetNewsWire 5.0 for iOS just passed the total for NetNewsWire 5.0.3 for Mac: 37,618 for iOS, 36,774 for Mac.

Yes, the iOS app has more downloads, and it got there in only a few weeks. But if the iOS market were so much larger than the Mac market, you’d have expected this to happen within a day or two of launch day.

This particular app makes for an interesting experiment for a few reasons:

  • It’s free (very little friction, in other words)
  • Both versions have had about the same amount of notice in the press and on blogs and Twitter
  • News reading is probably more of an iOS thing than a Mac thing in general
  • The iOS app is highly-rated (4.9 worldwide) and reviews are quite favorable

Based on the above, and knowing that way more people use iOS than macOS, you’d expect the iOS app to be way more popular. But it’s not. It’s a little more popular.

I find this super-fascinating, because it’s some data — admittedly just one app — that confirms what I’ve thought for a long time, which is that, for some types of apps, a Mac app would do as well as an iOS app.

And, given that Mac apps are less complex to write than iOS apps these days, a Mac app could be more profitable than an iOS app.

On Building NetNewsWire 23 Mar 2020, 5:39 am

On the NetNewsWire blog, I wrote about how it’s easier to build NetNewsWire now — and you don’t even need a paid developer account (just a free one).

Also: we welcome contributors! Of all skills levels and experience. Especially people new to app development. (NetNewsWire is my vehicle for giving back to the community, and one of the best to do that is to help new people get settled into the app development world.)

Slack Group for Socializing 20 Mar 2020, 9:27 pm

I’ve seen a few people on Twitter asking if there’s a Slack group they could join for the purpose of socializing.

So I’ve set up a #socializing channel on the NetNewsWire Slack group. You’re welcome to join — you don’t have to be a NetNewsWire user.

Everybody on the Slack group is super-nice, and there is a Code of Conduct.

I’m not going to try to convince you to use NetNewsWire. 🐯 I’m just using the tool I have to help in this very small way.

Proxyman 20 Mar 2020, 12:28 am

Our lead iOS developer Maurice Parker found an app called Proxyman that looks pretty cool.

It’s like Wireshark or Charles, except that it‘s a Mac-assed Mac app (which I love).

Update a little later: a few people have asked me, “What’s a Mac-assed Mac app?”

Answer: it’s a phrase I stole from my friend Collin Donnell to describe Mac apps that are unapologetically Mac apps. They’re platform-specific and they’re not trying to wow us with all their custom not-Mac-like UI (which often isn’t very accessible).

I consider NetNewsWire to be a Mac-assed Mac app, and it’s a point of pride.

Slack, on the other hand, is most definitely not — though it’s not only Electron apps that miss the mark of Mac-assed-Mac-app-ness.

Two Weeks at Home 16 Mar 2020, 8:02 am

Monday is the 14th day my wife and I will spend in self-isolation. We’re getting groceries once a week, but anything optional is just not done, and everything else is optional.

We skipped the small dinner party we were invited to on the weekend. We haven’t been to a bar or a restaurant or even to a coffee shop. I’m not getting my hair cut tomorrow.

Even with this, we’re still washing our hands frequently and not touching our faces — because the mail still comes and a couple packages have come. Because groceries are things from outside our bubble.

We’re lucky — I know we’re lucky. Incredibly lucky. But, if you’re similarly lucky, I beg you to do this too.

Yes, the economic cost is terrible. But that doesn’t compare to the loss in lives that’s coming.

Maybe you really, really want to go do this one thing, and everyone’s careful, and you’re young and healthy and don’t know any old people. Don’t do it. Don’t.

This may go on for months. Fine. Staying home to save lives is really not hard.

NetNewsWire Download Numbers 15 Mar 2020, 3:32 am

Common wisdom is, I think, that the iOS market is so much larger than the Mac market that an equivalent iOS app would be downloaded five or ten times more than a Mac app.

I kind of accept that wisdom, but I also kind of think the iOS App Store has so many more apps that it may erase that difference. An equivalent iOS app might get downloaded about the same number of times, or even fewer times.

Who knows?

Well, anyone with a Mac and an iOS app has some idea. Like me.

Here’s our situation. NetNewsWire for Mac is direct-download-only, and NetNewsWire for iOS is on the App Store. Both are completely free and have no IAP. NetNewsWire for iOS is, worldwide, a 4.9-star app. Both apps have been reviewed well by places like MacStories.


Downloads for NetNewsWire 5.0.3 for Mac, released Oct. 22, 2019: 32,223

Downloads for NetNewsWire 5.0 for iOS, released March 9, 2020: 26,089

My guess is that the iOS app will surpass the Mac app in downloads in about a week.

But there’s an important thing to remember: the majority of downloads happen in the first couple of days after release.

So I don’t expect the iOS app to be ten or even five times more popular than the Mac app. Maybe twice as popular? It’s early enough that it’s hard to say.

One thing that could really change these numbers is, of course, being featured by Apple. Another thing that could possibly change things, but in the other direction, is if we release the Mac app on the Mac App Store.


Every app is unique, and the situation will be different for each app. But just thinking that the iOS market is so much larger, and your app will do better by that proportion, is probably naive. It’s not nearly as straightforward as that.

On Alternate App Icons for NetNewsWire for iOS 14 Mar 2020, 4:50 am

Releasing an app always comes with surprises. No matter how many beta testers you have, there’s nothing like an app actually going out to the public.

We’ve had, for NetNewsWire for iOS, a startling number of requests for the ability to choose from a list of alternate app icons.

This is a thing that some people really like these days. Even if it’s the exact same icon just with different color treatments. (A dark icon seems to be most commonly wished-for.)

This was not a thing the last time I released an iOS app. (Vesper, back in 2013.) My guess is that, in the intervening years, we got API for this, and some developers have done this because, well, it’s fun. 🍕

And now it’s a thing people expect.

Given that including additional app icons can’t slow down the app, why not just do it? What could possibly be the downsides?

Here Are All the Downsides

The first one is kind of obvious. It’s easy to think that this is something you could do in a couple hours. But remember that it’s not just a case of loading the app icon up in Photoshop and doing some quick versions with different colors.

The colors have to be chosen and tested. Each version has to be created in all the various different sizes. It’s quite a bit of work!

And our app icon maker Brad Ellis is a father. Like everyone else on the team, he’s donating his time. Do I ask him to spend a few nights on this?

A second downside is that this takes time away from fixing bugs and doing things like bringing Feedly syncing to the Mac. (This feature requires layout, code, and testing — it’s not just Photoshop work.)

The third downside is that each option we add takes NetNewsWire one step further away from the simple RSS reader that people love. We will have to add options in the future — but, knowing that, we need to be super-careful about what we add so it doesn’t balloon. (You probably don’t remember NetNewsWire 3.3.2’s preferences window. It was extensive.)

The fourth downside is related to the third, and might be the most important. My previous decade of experience with NetNewsWire tells me that there is a sizable set of users who get kind of stuck on things like this. The more customization there is, the more time they spend on it. Any time we add something like this, we’re adding to their anxiety.

To be clear: I’m not disdainful of these people, not in the least tiny bit. I recognize it in myself, even. I want the ability to make things just-so, and it never, ever is, quite, but I keep trying. And maybe I ask the developer to add just one more option, but with this particular shade of blue or orange — and they do, but it’s still not quite right, so I go back to tweaking some more, maybe going another route… and…

This just isn’t good.

What We’re Doing

These are still very early days for the app — and so we’re going with a couple simple policies.

Add options when needed for accessibility. We support Dark Mode, for instance, which is for many people an accessibility issue. (We use Apple’s colors for this, on the grounds that they’ve done more research and design for this than we ever could.)

Add options that reduce anxiety. An example of this is the option to not show the unread count in the Dock on Macs. (There’s a similar setting in Notifications settings in iOS.)

Alternate app icons won’t help with accessibility, and they certainly won’t help with anxiety.

That’s not to say we wouldn’t ever do this. Or we might just add a dark version. But not right now.

I know this will disappoint some people. My pledge is that, even when I’m disappointing you, I will tell you honestly why.

(We’ll probably do themes for the article view way before we would do something like this, because 1) that’s fun too!, and 2) it’s an accessibility/readability issue.)

NetNewsWire 5.0 for iOS Shipping 9 Mar 2020, 5:18 pm

Go get it on the App Store! Also see the announcement on the NetNewsWire blog and see the NetNewsWire home page for details.

It’s free and open source. Even though it’s labeled as 5.0, it’s a brand-new app, a fresh start for an app that originally appeared on the App Store on day one.

The big difference is not the price tag — there have been free versions of NetNewsWire before — and it’s not just that it’s open source. It’s that there’s a great team of volunteers behind it now.

Many are coders, for sure — and one of them, Maurice Parker, is the lead developer for the iOS version. We also have Kiel Gillard on Feedly syncing, Nate Weaver on under-the-hood goodness and CSS magic, and many more.

There are also designers, writers, and testers. Brad Ellis made the app icon, which I love. Ryan Dotson wrote the excellent help book.

Our friends at Feedbin generously run the web service that provides the Reader view, and they’ve helped with a number of technical issues.

And, at this writing, we have 8,211 people testing via TestFlight — and they’ve been great reporting crashes and bugs, making feature requests, and providing all kinds of feedback. Having that kind of huge community support has meant everything to the quality of the app. This release is dedicated to them.

I love saying that NetNewsWire is a team. Yes, sure, I wrote the bones and I manage the project and I put my name on it — but this team and what they’ve accomplished makes me so very, very proud and happy. 🎸🐯💥

Adam Klobuchar 8 Mar 2020, 7:01 am

Like all of us, I’ll remember forever that image of Adam Klobuchar announcing his candidacy during a storm, with snow falling on his hair. He looked so tough and heroic and yet just plain real.

(By now we’ve all seen the poster a million times.)

I love his Midwestern credibility. His ability to win in even the reddest of districts. His common sense and his care and empathy. His record as a prosecutor and his record of introducing and passing bills in Senate.

It wasn’t inevitable that we’d have a universally-loved unifier at the top of the ticket this year, but I’m sure glad we do. Definitely the right choice to begin putting this torn country back together.

(Maybe he’ll pick Edward Warren as running mate? He ran a great race, and his many, many progressive plans quite rightly excite a generation of young people.)

More Life in Seattle 8 Mar 2020, 1:29 am

Our state is vote-by-mail — but there are also official ballot drop-off locations, and traditionally we like to walk down and drop off our ballots manually. We like the ritual.

We talked about whether or not we’d have to touch anything. It’s just a slot, right? Not like a mailbox? We think so. We can go the whole mile and back without touching anything in the world.

* * *

We’re mapping out meals to stretch the protein. Think stews and chili. Think beans. Eggs for variety.

We’re constantly surprised when we hear of people planning things that involve other people.

People on TV — they should be home, too, I keep thinking.

And I keep thinking that the air itself has added weight and slowed down.

I feel weird for enjoying, as an extreme introvert, the time at home, with a clear social calendar, with every reason not to go anywhere or see anybody.

I also feel supremely fortunate to have a home, good health, and the means to stock up. I constantly worry about the people who don’t have all three.

I worry that we’re going to run out of hospital beds in Seattle some time in April.

Washington State Primary Next Week 6 Mar 2020, 11:25 pm

I’m very curious to see what happens in the Washington State primary next week.

In 2016, Sanders won the caucuses overwhelmingly. I caucused, and I can say that the state results were pretty close to the results in my particular caucus.

Weirdly, we also held a primary that didn’t count. In that vote, Clinton won narrowly. That was about two months after the caucus.

This year we’re back to a primary vote, with no caucus. All our voting is by mail, and many people cast their votes while Warren, Klobuchar, Bloomberg, and Buttigieg were still in the race and before Biden’s wins in South Carolina and on Super Tuesday.

I’m confident that my neighborhood will vote for Sanders. You could easily argue that Sanders is likely to win the state, given his landslide victory last time.

But this is also a different year, and caucuses tended to favor Sanders, and we’re running a primary.

But, then, lots of people voted early, so… and now there’s this virus.

I have no idea what’s going to happen, but I’m super-curious.

PS For me personally, the remaining candidates in the race are something like my sixth and seventh choices. That’s how it goes sometimes. The people I really wanted are out. But I will of course vote in the general election for the Democrat — always have, always will.

Life in Seattle 6 Mar 2020, 8:48 pm

We’re avoiding other humans.

I’m home and Sheila’s home. Omni asked, earlier this week, that employees not come into the office unless necessary for a task, and I don’t miss jamming myself into the overcrowded and sneezy bus route 40 three days a week.

We’ve stocked-up on food and supplies, at least for a while. I do leave the house to go running, but I figure that’s safe.

Xcoders and NSCoder Night have been canceled. The Quilt Show has been canceled.

I don’t really know what the rest of the city feels like right now, since I’m just home or running on my usual jog path.

Trees and flowers are starting to bloom, so I have the sniffles, like every year in March. Birds are chirping and scrambling outside my office window.

This could be my life for a while. Your life might look something like this pretty soon. Hopefully not.

I miss going to restaurants.

We have a family member in Seattle, who we see twice a month, usually, who’s in the vulnerable class, and I don’t know when we’ll see him next.

A black rooster just walked through my backyard, which is a first. The sun comes and goes during the day.

How We Fixed the Dreaded 0xdead10cc Crash 13 Feb 2020, 11:40 pm

NetNewsWire for iOS, currently in TestFlight beta, was getting a lot of crashes related to background refreshing.

They would happen when the user wasn’t actually using NetNewsWire — it happened when the app would download feeds and sync in the background.

The crash logs were not identical, but they had this same thing:

Namespace RUNNINGBOARD, Code 0xdead10cc

This meant that the system was killing the app because, after the background task was complete, the app still had references to a SQLite database (or sometimes another file).

We did everything we could to fix this over a course of several months, including various forms of major surgery — and the best we could do was make it worse.

I did a lot of research — including reading this blog post from The Iconfactory several times — and we still came up with nothing.

Finally I asked around.


Marco Arment writes Overcast, a podcast player, which is in some important ways similar to NetNewsWire: it downloads data from the web while in the background.

Marco had already been through all this with Overcast, and he gave me this advice:

Don’t keep the SQLite database in the shared container. You’ll never get rid of all of those crashes. Instead, communicate with extensions via other means than having them read/write the DB directly, such as Darwin notifications or writing plist files in the shared container.

iOS will always terminate the app and generate that crashlog whenever your app or extension has an open file handle to a file in a shared container at suspension time.

And there are some cases where your app gets forcibly suspended without calling background-task completion handlers. (Especially in extensions, where they don’t exist.)

I tried wrapping every SQLite query in a background task once to avoid this. A standard Overcast session may issue hundreds or thousands of database queries. I later found that apparently each one generates a process power assertion, the OS wasn’t made for that level of usage, and after some time, Springboard would crash.

There’s also the NSProcessInfo background-task thing that allegedly works in extensions, except that it doesn’t.

The moral of the story ended up being: just don’t keep your SQLite database in the shared group container. There’s no way to avoid these crashes 100% of the time.

We were sharing our SQLite database with one of our extensions! Marco’s advice is, basically, don’t do that.

So we stopped doing that. We un-shared the databases and switched to a super-low-tech thing for communicating between the extension and the app (the extension writes to a plist file which the app later reads).

And — as of last night’s build — the dreaded 0xdead10cc crashes are gone!

Continuing On

That was the last big challenge on our list for shipping. We still have work to do, but we’re getting close — the milestone says we have just four bugs left. Good deal.

PS I’ve since heard from other developers: don’t-share-the-database appears to be the common wisdom, which it just took me longer to learn. 🐥

Knock It the Fuck Off 9 Feb 2020, 11:35 pm

Every day on Twitter I see smart people who I respect dumping on one or another of the Democratic candidates.

Sanders for being cozy with left-wing dictators; Warren for being insufficiently socialist; Klobuchar for having prosecuted drug crimes; Buttigieg for taking money from rich people and for his lecturing; Biden for the stains on his record and for being weird; Steyer for being super-rich; Bloomberg for being even richer and for stop-and-frisk; Yang for… something, probably. (I forget).

I have a favorite, and a second and third choice. And so do you, and ours might not match.

Odds are that your favorite is not going to be the nominee. And that nominee, whoever it is, needs to not have been already labeled a garbage candidate by you and by everyone who’s favorite he or she isn’t.

Here’s the thing: we’re fighting to stop the spread of right-wing extremism. It will get so much worse if we reelect the president. It has to be stopped now. No other issue matters, because nothing else can be done without doing this.

Things I Don’t Care About

I don’t care about Medicare for All or beefing up the ACA. I don’t care about free college. I don‘t care about legalizing marijuana. I don’t care about immigration reform. I don’t care about rolling back the corporate tax cuts.

I don‘t care about any of the wonderful liberal and progressive policies our candidates propose — because they’re not going to get through.

(Well, I do care about them, deeply, but the point stands.)

It’s not that it would take 60 Democratic senators — it would take more like 65 or even more, and that’s not going to happen. We can elect the most wonderful progressive person ever and they’ll just beat their head against the wall.

There’s no magic coming. There’s no amount of will-of-the-people that will move Republican senators. All of the policy we talk about is just fantasy.

I also don’t care where the candidates’ money comes from. In fact, I want it to come from everywhere and I want to see enormous fucking rivers of it — because we’re going to need it to beat that corrupt asshole, our current president.

The Only Thing I Care About

Our job is to stop fascism here in America.

And then we can deal with it in the rest of the world.

I have plenty of doubt about what’s the best way. Will we turn out people who don’t usually vote? Maybe. But, the thing is, those people are people who don’t vote. And there’s no guarantee that, if they did, they’d vote our way.

But maybe there is an untapped well who can be energized and inspired?

Or… instead, will we be able to persuade people in the suburbs who normally vote Republican? In this polarized country, can anyone anywhere be persuaded? I don’t know. But maybe?

If you think you know the answer, I’ll tell you you’re full of shit, because you don’t know and I don’t know.

Here’s what I do know, though: we all need to be prepared for one of these candidates becoming the Democratic nominee, and we need to not have half of us hating that person already.

Because none of them are right-wing extremists. They’re all good people who will do their best to get good things done (and fail, but still).

This is the only thing that matters — they would all, every one of them, turn us away sharply and swiftly from the abyss we’re looking at right now. Even the ones who are not your favorite.

So cut it out.

NetNewsWire Sitrep 8 Feb 2020, 10:10 pm

Alex — @tales on Twitter, blogger at 418 Teapot — ran Sitrep on NetNewsWire, on the branch we’re currently working on (iOS-candidate).

Here’s what Sitrep reports:

   Files scanned: 424
   Structs: 145
   Classes: 283
   Enums: 33
   Protocols: 69
   Extensions: 300
   Total lines of code: 56254
   Source lines of code: 50125
   Longest file: SceneCoordinator.swift (2038 source lines)
   Longest type: SceneCoordinator (1080 source lines)
   Imports: Foundation (218), RSCore (146), Account (129), Articles (104), UIKit (91), AppKit (79), RSWeb (53), RSParser (42), XCTest (41), os.log (37), RSTree (20), RSDatabase (18), ArticlesDatabase (13), SyncDatabase (12), WebKit (9), SafariServices (6), UserNotifications (5), CoreServices (4), Intents (3), NetNewsWire (2), MobileCoreServices (2), Social (1), CoreSpotlight (1), SystemConfiguration (1), WatchKit (1), BackgroundTasks (1), Sparkle (1), Darwin (1), AuthenticationServices (1)
   UIKit View Controllers: 7
   UIKit Views: 5
   SwiftUI Views: 0

I would have guessed around 35,000 lines of code, but we’re past 50,000 lines.

More Bug Math 29 Jan 2020, 8:17 am

When an app is under 100 bugs, you can start getting an idea for when it will be done.

The idea will be wrong, of course, but it’s still an idea.


I started keep tracking of the number of open bugs on Jan. 9, when we had 41 open bugs.

Now, 19 days later, we’re down to 12 open bugs.

That does not mean we’ve fixed just 29 bugs: we’ve probably fixed three times that many. And that’s because, this late in the game, we have a lot of testers and bug reports — and also because any bug fix could result in another bug. (Or two. Or three.)

However: the math says we’re netting 1.5 bugs fixed per day. In other words — despite the new bug reports — on average, every day we’re 1.5 bugs closer to shipping. That’s a pretty good rate of progress.

This tells me that we’ll be down to zero bugs in eight days. (We’ll fix a lot more than 12 bugs in those eight days, but in the end we’ll have no bugs left.)

Of course that’s not really true. This is app development, after all — a process so uncertain that it makes Chaos blush.

But still, it gives us an idea of when we might be done. Pretty confident it will be in 2020.

Bug Math 28 Jan 2020, 6:44 am

The NetNewsWire team continues its amazing run — we just released build 31.

When we released build 30 two days ago, we were down to seven bugs.

In the last two days, the team fixed nine bugs.

How many bugs are left? Could it be -2? Nope: it’s 12.

7 - 9 = 12. That’s app-writin’ for ya.

Crash Math 26 Jan 2020, 11:25 pm

We’d like to ship NetNewsWire 5.0 for iOS in the first quarter of this year. The app is really close, but there are a few bugs to fix, including some crashes.

We’re sticklers about crashes: while there’s no way to guarantee the app will never crash — because there are bugs in other parts of the system that we can’t control — we want to get the number of crash reports as close to zero as we can. Ideally we’d go days or weeks between seeing a crash report.

This is about the craft of app-making. It’s about being responsible.

But it’s also about math. Consider this:

NetNewsWire for iOS could have 100,000 users. It’s relatively high-profile, in a popular category, and free.

So if we get it down to, say, a 1% chance that a given user will hit a crash on any given day, that sounds pretty good, right?

But that 1% chance means we’d get 1,000 crash reports per day. In other words, a 1% chance is very, very bad.

If we get it down to a 0.1% chance, we’d still get 100 crash reports per day. At that level, a given user could go, on average, 500 days between crashes. Which sounds great! Sounds like a super-stable app!

But that would mean 100 crash reports a day, which is still a massive number of crashes.

We need to do way better than that. (We will.)

Fair Isle Brewery Opens Today 24 Jan 2020, 1:13 am

The Fair Isle Brewing company’s tasting room opens today! (One of the partners is a friend: the one in the photo with the big gray beard.)

I had a preview a couple weeks ago. The beers are really, really good. 🎩🐥

The beers were…

…created with ingredients farmed and foraged in the Pacific Northwest and fermented with our house blend of wild and feral yeasts and bacterias.

The name “Fair Isle” sounds like “feral.”

PS Here’s their website.

Jeff McLeman 23 Jan 2020, 8:34 pm

It is my sad duty to report that Jeff McLeman — whose work you’ve used, even if you don’t know it — suffered injuries from a very bad fall, and soon after passed away as a result of those injuries.

Jeff was a long-time Seattle Xcoder, before recently moving away, and he was a beloved friend to me and many people.

He was also a walking computer history museum — he was a little older than me, and he’d worked on a number of projects during that heroic age when people wrote new operating systems because they were needed. I learned from every single conversation with him.

There’s a NetNewsWire connection, too. He worked at Black Pixel for a while, and — among many other things — he played a significant role in their shipping NetNewsWire. And when it came back to me, he was super-happy for me, and he encouraged me frequently and cheered on our work.

He was exactly the kind of person you wanted in your corner — and it seemed like he was in everybody’s corner.

We’re all shocked and saddened, and we miss him. I miss him. Our thoughts go to his wife and family.

You’ve probably heard his voice before: he was on Debug #35: Jeff McLeman on porting kernels. I’m re-listening to it right now.

Uniform Type Identifier Bug on iOS — and How It Affects NetNewsWire 21 Jan 2020, 3:15 am

In NetNewsWire you can import your subscriptions from an OPML file. This is the standard way RSS readers work: you can export your subscriptions as an OPML file, and then import them into a different RSS reader.

This way you can move from reader to reader without having to redo your subscriptions list. It’s a good thing.

But in NetNewsWire for iOS (currently in beta) this sometimes doesn’t work because, for some people, the system won’t let you select an OPML file to import. (This does not happen on Macs.)

Here’s What Happens

In our app, we declare an OPML type: org.opml.opml with a file suffix .opml.

The org.opml.opml part is a Uniform Type Identifier (UTI), which is Apple’s way of defining document types.

When the user wants to import subscriptions from an OPML file, the app presents a document picker, and the app tells the picker that the user can select files of type `org.opml.opml.

We don’t want the user to select, for instance, a plain text file, or a Pages document, or a GIF, or whatever. We just want to make OPML files selectable.

This works great — except when, for some people, it never works: it doesn’t allow them to select OPML files, and so they can’t import their subscriptions.

It took a while to figure out the problem, but we did.

Here’s the Problem

We found that if a user has another app that declares an OPML UTI — and that UTI doesn’t match ours — then the document picker will not see those OPML files as the type we accept (org.opml.opml) but as something else.

So far we’ve found two other definitions for OPML: com.reederapp.opml and unofficial.opml (from Overcast). (To be clear: Reeder and Overcast are tremendous apps, and this situation is not at all their fault.)

For someone with one of those apps installed, the system sees a .opml file suffix and decides the file is of type com.reederapp.opml or unofficial.opml. Which doesn’t match our type — org.opml.opml — which means the user can’t select the file. Even though the file suffix is .opml.

One Possible Solution: Declare All the Types

When presenting the document picker, we could declare that we allow com.reederapp.opml and unofficial.opml.

But here’s the rub: those are just the two we know about. We would need to do research on all the RSS readers, podcast players, and outliners to find all the various declarations of the OPML type.

And, furthermore, every time a new declaration appears in a new app we’d have to add support for that one too. (In the meantime, it would break subscriptions importing, for people with that app, until we do add support.)

Another Possible Solution: Tell the System that All Text Files Are Selectable

We could just let the user select any file that’s a text file. OPML files are text files, after all.

But then, so are HTML pages. And Markdown files. And any plain-text documents you may have.

This breaks the principle that you let users select only the kind of file that’s appropriate.

But that’s the solution we’re going with. I don’t like it. I’m not even completely sure it will work in all cases, but I am sure that it makes for a sub-par UI.

I don’t see that we have a choice. Please tell me if I’m wrong!

PS We found a related bug report for this from 2012: Apps can declare bad UTIs that redefine what a file extension conforms to.

On Replacing OperationQueue 20 Jan 2020, 10:37 pm

We fixed our mystery KVO crash by writing a replacement for OperationQueue.

Well, sort of a replacement. It’s not a drop-in replacement, because what we really wanted was slightly different from OperationQueue.

OperationQueue does a few things:

  • Manages a queue of operations
  • Runs operations in multiple threads
  • Supports dependencies — operations can be dependent on other operations
  • Supports canceling operations

But that’s not exactly what we want. We want something that:

  • Manages a queue of operations
  • Runs operations on the main thread
  • Supports dependencies — operations can be dependent on other operations
  • Supports canceling operations

Note the difference: we want to run operations on the main thread. That may sound crazy to you, but I’ll explain why shortly.

Note also some characteristics of OperationQueue:

  • Uses KVO (is finicky and crashy)
  • Subclassing is allowed and expected (of Operation/NSOperation)

But that’s not what we want either. Instead, we want:

  • Low-tech, non-crashy notifications
  • No subclassing

Canceling Is the Most Important OperationQueue Feature

Recall that OperationQueue — at the time just NSOperationQueue — came out before Grand Central Dispatch (GCD), and it was the best way to get code off the main thread.

But these days we do have GCD, and when we want to run code on a background thread, we use GCD. (And, often, a serial queue.) We don’t need OperationQueue just to be able run code on multiple threads.

Instead, the important thing about OperationQueue, the reason to use it instead of just using GCD, is the ability to cancel operations. This is critical in an app where conditions change — the network might fail, the app might move to the background, databases may get closed. Canceling is critical.

This is why we didn’t just stop using OperationQueue in favor of GCD. This is why we needed to write our own thing that supports canceling.

Why Run Code on the Main Thread

I’ve written before about writing main-thread-only code — it’s a paradise when you don’t have to think about concurrency.

You may think you’re good at writing thread-safe code, but are you 100% good? Is everyone on your team as perfect as you are? And, when multithreading bugs inevitably do happen, how quickly can you reproduce them and fix them?

Our default position is to write code that is not thread-safe — and not even safe to run on any thread besides the main thread.

That said, we do have a number of APIs that do async things and then call back to the main thread. Networking, for instance. Updating or querying a database. Parsing feeds.

Even though our operations run only on the main thread, they can — like any other code — call an API that does something on a background thread and then calls back to the main thread.

An operation’s code might look conceptually like this:

func run() {
	// On the main thread right here.
	// doSomeAsyncThing uses GCD
	doSomeAsyncThing(args) { result in
		// Back on the main thread.
		guard !isCanceled else {

To sum up: because we have GCD, we don’t need an operation queue that handles concurrency. In fact, we don’t even want it to handle concurrency.

MainThreadOperationQueue, MainThreadOperation

MainThreadOperationQueue and MainThreadOperation are part of our RSCore framework.

A few things to note:

  • MainThreadOperation is a Swift protocol. You don’t subclass it; you implement it.
  • When an operation is finished, it informs the queue by calling a method on the main thread. No KVO or other form of notifications.
  • The code is quite simple, but there’s more of it than you might expect: managing dependencies adds to the bulk. The code is basically just a thing that does a bunch of housekeeping.
  • It uses precondition(Thread.isMainThread) in a number of places, which will crash even a Release-build app. We use precondition over assert quite deliberately: if these functions are called outside the main thread, then we’re operating in a surrealistic environment, and we refuse to go on.
  • It has some tests, but of course it should have more tests.

At this writing, this code is already running on over 2,300 iOS devices, since it was included in NetNewsWire 5.0 TestFlight build 28 last night. That was the build where we switched our Feedly syncing code from OperationQueue to our own MainThreadOperationQueue. (I just checked number of installations in App Store Connect.) So far so good!

One bonus thing I like about it is that any given MainThreadOperation can create its own MainThreadOperationQueue to run a bunch of child operations, and then call back only when those operations have finished or are canceled. (We use this feature as part of Feedly syncing.)

But my favorite thing about it is how low-tech it is. There’s not even a hint of cleverness in that code — it’ll put you to sleep. But this makes bugs, including crashing bugs, way less likely.

Don’t Do This (Usually)

Normally I am very much against reinventing wheels. No points are awarded for writing your own version of a thing that 1) comes with the system and 2) is well-suited to your needs — instead, points are taken away for showing off and wasting time.

Even if a system-provided thing is not exactly right, but close enough, you should probably use it.

But when you do find you need write your own version of the wheel, think about what you need exactly, and just do that thing and not more. And don’t be clever — you don’t want to trade one problem for another.

Update 1:20 pm: I’ve been asked about using OperationQeue.main to run code on the main thread and still use OperationQueue. Answer: the thing that triggered all this was the mystery KVO crashes. I don’t want to dwell on that, but that’s really why we wrote our own operation queue.

 20 Jan 2020, 4:17 am

The hottest team in iOS development keeps on rockin’! We just released a new TestFlight build of NetNewsWire 5.0 for iOS.


Immutable Swift Structs 17 Jan 2020, 6:52 am

As you read this, consider that I might be a squirrel and not, as I like to pretend, a rational programmer.

My Two Brains

My Objective-C brain — which will never leave me, even though I’ve been writing in Swift for years now — always told me to create immutable objects as often as possible.

Objective-C brain says, “Immutable means you never have to worry about it.”

My Swift brain — which is newer, and has all the fun these days — tells me another thing.

Swift brain says, “Value types are good. Use value types as often as possible.”

So my favorite thing in all of Swift is an immutable struct. It’s a value type, and it can’t be mutated!

Both brains happeeee! 🐥🐣

Var vs. Let

This came up in working on NetNewsWire: some model objects — some structs decoded from JSON returned by a syncing server — used var instead of let for their properties.

These model objects are not mutated anywhere. So, I figured, those declarations should use let instead. (Which would make my brains happy!)

An immutable struct is, after all, the greatest thing ever, right? You don’t have to worry about it. It never gets copied (at least in theory). If you share it across threads, it’s the same everywhere: you don’t get some number of different copies.

So I asked the author to change the vars to lets.

I didn’t expect the response — which was “Why?” (Asked earnestly, of course.)

I struggled with the answer.

Value Types Are Good

Here’s the thing: value types are good. Even though those structs aren’t being mutated now, we could imagine cases where they could be.

Why not leave it up to the code that has one of these to decide to mutate or not? After all, as value types, this makes a copy and doesn’t affect other instances. Value types are safe, regardless of mutability.

And yet…

Here’s Where I Might Be a Squirrel

I still insisted on using let for the properties in these structs.

There’s something to be said, of course, for always starting out strict and loosening up only when it’s actually needed. Don’t loosen up in anticipation. But that’s hardly a big deal here.

Instead I think it goes to code-reading: if I see let instead of var, I have some understanding of the intent. In this case, the structs are parsed versions of stuff-from-the-server, and that’s a case where you could expect immutability, and be surprised to find something else.

Those structs don’t get saved anywhere as-is; they don’t live long; nothing the user does can change them.

These structs are a report: “Server says this.”

So… I think it’s the right call, but I’m absolutely aware of the possibility that I’m just distracted by my Objective-C instincts, and I’m over-tidying.

I don’t know! What do you think? Should I have left it as-is?

 10 Jan 2020, 7:40 am

The NetNewsWire team continues to rock — there’s a new TestFlight build up.

Note the change notes — they represent just three days of work. We’ve got the best team. 🎸

NetNewsWire for Mac Mystery Scrollwheel Crash 6 Jan 2020, 10:19 pm

For NetNewsWire for Mac, I get one or two crash logs a week referencing scrollView:​scrollWheelWithEvent:.

Here’s the bug for it.

Chris Campbell, in a comment, writes:

FYI, I see this crash reported very frequently in the commercial Mac app I work on at my Day Job. Unfortunately, we’ve never been able to reproduce it first-hand. I used a Tech Support Incident to correspond with Apple about this issue (giving them hundreds of sample crash reports), only to have them ultimately give up and credit back the Incident.

-scrollView:scrollWheelWithEvent: is an API of the private NSScrollingBehavior class and its subclasses (class cluster). Those objects are an implementation detail of NSScrollView that are stored in an external structure, so there is significant opportunity for mismanagement of the memory references.

There has been speculation that “responsive scrolling” is somehow involved…

If you know more about this bug, or have more ideas for working around it, please comment on the issue. Thanks!

Update 2:20 pm Jeff Nadeau writes:

This should be fixed in 10.15. The 10.15.2 crash I see linked is something different.

This is great news! I hadn’t noticed that almost all of the scrollWheel-related crashes were in 10.14.

I have just one crash log that references the scrollWheel on 10.15, and it includes this:

Assertion failed: (![currentGestureList containsObject:​self]), function NSScrollingBehavior​ConcurrentVBL​AddToCurrent​GestureList, file /BuildRoot/​Library/Caches/​​AppKit-1894.20.140/Scrolling.subproj/​NSScrolling​BehaviorConcurrentVBL.m, line 102.

Estimating NetNewsWire for iOS Demand 4 Jan 2020, 7:06 am

As we get closer and closer to shipping NetNewsWire for iOS, I’m starting to realize that the iOS version could be quite a bit more popular than the Mac app.

Here are a few numbers:

  • NetNewsWire 5.0 for Mac was downloaded 24,789 times.
  • The NetNewsWire for Mac beta builds are downloaded anywhere from around 630 to around 1,360 times.
  • Number of people who signed up for the public test of NetNewsWire for iOS: 5,263.

Five times more?

The number of testers tells me — very roughly — that there’s about five times more interest in the iOS app than in the Mac app.

If that holds true, then NetNewsWire 5 for iOS, once it ships, will get downloaded about 124,000 times.

Let’s round down — call it 100,000 downloads in the first two weeks. I would be amazed if we got that that many downloads. I’m really expecting a number much closer to the Mac app. But I could be very wrong — I admit to thinking like a Mac developer and not really feeling the greater size of the iOS market.

It’s quite possible that 100,000 might be too low.

At any rate, I’ll be sure to report the actual numbers on this blog. 🐣

What does this mean for interest in RSS readers in general?

Remember that NetNewsWire is just one of many RSS readers on Mac and iOS. There are readers for Android and Windows — and a whole bunch of browser-based readers, such as Feedbin, Feedly, Inoreader, and others.

You can’t just multiply my NetNewsWire estimate by the number of apps and come up with something meaningful.

But you can look at some things and get an idea. For instance: on Feedly, one of the most popular browser-based readers, there are 1.6 million people subscribed to Engadget. No, I have no idea if those are all active readers, but still.

I think it would be reasonable to guess that the number of people who use an RSS reader is probably greater than a million, and could be several million people.

Those aren’t Twitter user numbers, obviously, not even close — but I’m betting it’s more than what most people assume it is.

PS This blog has 16K followers just on Feedly. If it were possible to add up my subscriber counts from each RSS reader, it would be quite a bit more than the 18K Twitter followers I have. Which is as it should be.

The New Ranchero Software 3 Jan 2020, 7:02 am

Ranchero Software, my old company, has actually technically existed in three different forms over the years — I’ve been an indie, then got a job and shut down the company, went back to indie and rebooted it, got a job, etc.

The most recent version — Ranchero Software, LLC — shut down a while ago. A year ago? I forget.

We got tired of reporting every month that it made $0. And we realized we had no plans to ever make money, since, well, I have a great day job at Omni.

But now it’s back, in a new way

The new Ranchero Software isn’t a company: it’s an organization on GitHub. Just today we moved NetNewsWire and associated repos to this new location.

We realized it would be easier if we had an actual organization with various teams — easier to manage, easier to add people, easier to set permissions, etc.

There was a little talk about what to call it. Name it after NetNewsWire? Or use the name Ranchero?

One of the things to remember is that it’s not just about NetNewsWire: there are also stand-alone frameworks and there’s another app: Rainier. (Which is way behind NetNewsWire. Nothing to see yet.) And we might do other apps, too.

So while we could have — a la the Apache folks — named the org after its founding project NetNewsWire, everyone preferred using the Ranchero name.

For me, at least, this is super cool. Ranchero Software lives!

PS You might wonder where the name Ranchero came from. It was 1996, and we were looking for a domain name that was 1) available, and 2) trendy. In those days, the hot stuff was Tango and Marimba and similar. We found that was available, and it kinda fit in with those names — plus it sounded kinda western — so we grabbed it.

PPS No, Ranchero Software isn’t an actual organization with papers filed anywhere. It’s just a thing on GitHub. But that’s all it needs to be.

My New Year’s Resolution Is to Focus My Anger 1 Jan 2020, 11:44 pm

For the last few years I’ve found myself getting angry at small things, which is so unlike me.

My resolution is to try harder to get angry only when it’s actually worth it. I can be angry at cruelty, angry at the forces destroying democracy for their own corrupt power, angry at the malevolences driving our climate crisis.

But I need to not get angry just because Instruments won’t profile my app, or I get a robocall, or someone on Twitter completely misses the point of something I wrote.

Anger — righteous, smashing anger — is completely called-for right now. But only at the right targets. This is the hard part, at least for me — it starts to spill out to where it doesn’t belong, and I can feel it corroding me.

I’m not by nature an angry person. Quite the opposite! But I do care deeply about some things.

My emotions somehow need to get smarter about what’s worth the anger and what things are not actually part of the current vast project of destruction.

I don’t know how to do that other than to constantly remind myself, when I feel it bubbling up over something small, that it’s not worth it.

But the problem with anger — even our current justifiable and necessary anger — is that it becomes a habit, and then it goes blind.

 1 Jan 2020, 2:50 am

NetNewsWire won an Upgradie for Best Newcomer Mac App! The whole team is so happy for this.

Other awesome stuff won too — one of my favorites is Automators, which won Favorite Tech Podcast.

Here’s the episode where Myke Hurley and Jason Snell talk about the winners and runners-up.

Page processed in 3.318 seconds.

Powered by SimplePie 1.5, Build 20180814171753. Run the SimplePie Compatibility Test. SimplePie is © 2004–2020, Ryan Parman and Geoffrey Sneddon, and licensed under the BSD License.