inessential by Brent Simmons

Writing Mac and iOS Apps Shouldn’t Be So Difficult

In the ’90s and early 2000s I worked for UserLand Software — Dave Winer was founder and CEO — on a Mac app called UserLand Frontier.

The app was a scripting system and hash-table-oriented database that powered the early blogging and podcasting worlds. (That sounds grand, but it’s probably an understatement — but this post isn’t all about Frontier’s impact on the web, so I won’t go into details.)

The app was implemented in two pieces:

  • The kernel, written in C, implemented the database, networking, inter-application communication, various built-in data types, script compiler and evaluator and debugger, and so on
  • The scripts used the kernel and implemented most of the actual app behavior

Since it was an app, it had plenty of UI — menus, contextual menus, buttons, larger UI components, and so on. What was brilliant was that you could, for instance, add and edit menus, and when you chose a menu command it would run your script. (Or when you clicked a toolbar button, etc.)

You could write an entire static blog publishing system and the UI to go with it without ever restarting the app. Click a thing, then see what happens in the app — and if it’s not right you’d edit the script, which would be automatically recompiled when called the next time.

In other words, there was absolutely no friction when it came to iteration. Write some code without restarting and see your changes immediately.

How good was this really in practice?

You might imagine that we could do this for an hour or so before having to make changes to the kernel. Not so.

In fact, for the first three years I was there (might have been longer), I never even saw the kernel code. I worked all day every day as a professional developer at the script level, never having to restart the app. Just iterating like this all day long.

You might also imagine that the app was sluggish and slow since much of it was scripts instead of C code. It wasn’t! Scripts could be slow for the same reasons any code could be slow (I/O, of course, and algorithms and data structures not suited to the problem at hand) — but the app never felt slow.

I’ll remind you of the timing: this was the ’90s. We worked this way for real, and we were amazingly productive.

A scripting language plus key bits implemented in C was more than fast enough for an app. Even all those years ago.

A scripting language built for productivity

I’m not writing this article to praise Frontier — I’m talking about it to make a point, which I’ll get to.

But I wanted to bring up a second aspect to this: it’s not just frictionless iteration that was so great, it was also the scripting language and environment.

One of the best parts of this was how easy persistence was. I mentioned the hash-table-based database. Hash tables could contain hash tables (Swift developers: picture a Dictionary inside a Dictionary, and so on).

(We just called them tables for short — but remember that these are hash tables, not tables in a SQL database.)

In any script, at any time, without any ceremony, you could read and write from the database simply using dot notation: user.prefs.city = "Seattle" would set the value of city in the prefs table which was contained by the user table. This value would persist between runs of the app, because it was stored in the database.

(You could also pass around addresses of things too — it was quite common to pass the address of a table to another script, so that the other script wouldn’t need to hardcode a location.)

It was utterly automatic. And it meant that while we did have to choose where in the database to store things, and how to structure our storage, we didn’t have to choose a storage mechanism. It was the database.

(Note: of course we could read and write files, and did so when necessary. But the point is that the database handled almost all our persistence and in a super-easy way.)

(Also note: the database had a UI. It was visible and browsable. You could and often did hand-edit it. Even the scripts lived in the database, and were addressable via dot notation, like everything else.)

We had nice things!

I’ll say again — this was in the ’90s, more than 25 years ago, and it was a great way of working on an app.

I’m not saying apps these days need to be Frontier-like in any details. But it seems absolutely bizarre to me that we — we who write Mac and iOS apps — still have to build and run the app, make changes, build and run the app, and so on, all day long. In the year 2025.

And it seems retro in the worst way that we’re still using anything other than a scripting language for most of our code. We should be using something simple and light that can configure toolbars, handle networking callbacks, query databases, manage views, and so on. And maybe with a DSL for SwiftUI-like declarative UI.

Almost none of that code needs to be in a lower-level language like Swift or Objective-C. It really doesn’t. (I say this as a performance junkie!)

It could be in Ruby, Lua, Python, or JavaScript. Better still would be a new language invented specifically for the problem of writing apps, something designed to make the common challenges of app writing easier.

We did have this stuff decades ago. Not for app making in general, sure — but now it’s 25 years later, and a company like Apple could make this real for all its app makers.

It’s easy to see why things are the way they are right now, and you can point to a string of good decisions. No doubt.

But we can think outside of what we have now and ask: what would make app writing easier? What would make it a better experience? How could we get more done for our users with fewer bugs and faster turnaround?

I’m not saying that Frontier’s specific choices are the answer — I’m saying that the combination of frictionless iteration plus a purpose-built scripting language was extremely powerful, and we could use those things now.

And at some point I suspect these things are going to be table stakes for any platform that wants to attract developers. If you were a new developer right now, would you pick Xcode’s build-and-run, edit, build-and-run, edit — plus the growing complexity of Swift — over something like Electron and JavaScript?

Random notes

Yes, I know about PyObjc and RubyCocoa. Without first-class support in Apple’s developer tools, these were never going to work as popular alternatives.

I also know about (and use) Swift playgrounds and SwiftUI previews. Neither of these are as satisfying to use as I’d like, and neither of these are nearly as great as frictionless iteration in the actual app.

I also remember Xcode fix-and-continue, which didn’t work well enough to solve the problem of frictionless iteration.

Anyway… One more thing about Frontier: we had a system where people could get updates to the app automatically via the web. Those updates were just serialized versions of scripts at various database locations, which would get unpacked and stored in each user’s database. (Those who opted-in, of course.) The app would not have to be restarted to get bug fixes and new features! And of course the updates were very small, since they didn’t include the entire app. This seems so futuristic, but we had this in 1999. Why couldn’t we have this now?

Tough Season in the Apple Fields

We’re adopting Liquid Glass for NetNewsWire 7, which we’ll release some time after the new versions of macOS and iOS come out.

Stuart Breckenridge has been doing great work on getting this done — and he’s written up a couple blog posts (with screenshots!) on his progress. See:

Adopting Liquid Glass, Part II (NetNewsWire Mac)
Adopting Liquid Glass, Part III (NetNewsWire iOS)

Since the app is made with mostly stock Apple UI, you might think that using Liquid Glass would be very little work, that it might be pretty automatic or just a matter of checking a few boxes. But that’s not true this year: it’s been a fair amount of work.

Other apps, apps with more custom UI, will probably have even more work, but even for us it’s been more than a bit.

And we’re not done. There will be little things (hopefully just little things) still to do before shipping. Including verifying that it all works as expected on the actual OS releases.

But all credit to Stuart, who got right on this and did a superb job.

(Note: if you want to see the code, you can: it’s on our experimental/liquid-glass branch.)

But My Mac

As pleased as I am with Stuart’s work, I’m not pleased with Liquid Glass itself.

I don’t really care about it on iOS/iPadOS, because whatever. I don’t love those devices. I love Macs because it’s on Macs where you can set out to make new things that change the world.

(Okay. Fine. On iPhones and iPads you can, I guess, but generally it’s much harder, and it has to be an approved activity using an approved app. And one thing you definitely can’t do on those devices is create apps. [All apologies to people who do manage to edit their podcast episodes on an iPad or write at length on an iPhone. Cool! But I hope that even those folks will grant me my point.])

And so I seriously dislike the experience of using a Mac with Liquid Glass. The UI has become the star, but the drunken star, blurry, illegible, and physically unstable. It makes making things way more of a struggle than it used to be.

We had pretty good Mac UI, but Apple took the bad parts of it — the translucency and blurriness already there — and dialed it way up and called it content-centric. But it seems to me the opposite. Liquid Glass is Liquid-Glass-centric.

Perspective

First thing: I have many friends at Apple and I didn’t want to write any of this. And there are legions of engineers and designers who I don’t know but whose work I respect greatly. It’s not their fault that this is the direction of the UI.

And this is not the first time we’re going through a rough patch with Apple. I think of them as seasons — we had, for instance, terrible-keyboard season not so long ago. We were wondering if Apple would just stop making Macs altogether. But then that passed and we even got these wonderful Apple Silicon machines. Seasons end.

And we’re in a tough season with Swift these days too. It’s gotten so complex and difficult that I find myself daydreaming about going back to Objective-C. Objective-C is definitely funny-looking, but once you get past that it’s actually small and simple.

But with Swift approachable concurrency and other changes I can see eventually getting through this season and to a pretty great place, so I’m optimistic.

Seasons do end, in other words, or mostly seem to end (though not the App Store monopoly season, not so far), and I’ve resolved to just wait for Liquid Glass’s replacement. Perhaps along the way it will get refined enough so that people like me can use it without eye strain.

Better Perspective

But far, far worse than any of the above is Tim Cook’s gold statue presented to the President. And everything that went along with that. I felt utterly sick and I bet you did too. (And it made me seriously wonder if I wanted to continue writing apps for Apple platforms.)

I understand John Gruber’s argument in Gold, Frankincense, and Silicon that maybe Cook’s move was the best possible move in a terribly corrupted system.

But what’s the use of being so rich and so powerful, I would ask Tim Cook, if you, even more than regular people, have to debase yourself before the dictator?

It’s tempting to think that our current government is just a season, like the bad keyboards or like Liquid Glass will eventually prove to be. Wait till the mid-terms or the next presidential election, you might think.

But there’s no reason to think that this authoritarian turn is just a season. Something besides just wishing and waiting for better is required.

Breakpoints Show Thursday in Seattle

James Dempsey and the Breakpoints will be appearing in a Breakpoints Jam this Thursday (Aug. 21) at Bale Breaker in Ballard. Free show! Awesome songs!

The event starts at 6 pm and music will start around 7 pm. I’ll be on guitar — and you can expect local superstars Ken Case (keyboard, vocals) and Laura Savino (vocals) plus a special mystery guest or two from out of town.

The show will be mostly acoustic, and it will be outside at the picnic tables. I hope to see you there!

Saturday March

Tomorrow is No Kings. There’s one near you!

Chatting with my friends about how I hate these fascist assholes doesn’t do a damn thing. Protests work. (Imperfectly, sure, with no guarantees. But it sure beats not protesting.)

Retirement Day

I wrote in my love letter to my colleagues at Audible that retirement is coming up — and now it’s here. Today’s the day!

I’ve attended my last meetings. I’ve said my goodbyes. My laptop’s ready to ship back to Audible HQ.

* * *

I started working in 1984, while in high school, busing tables part time at Schaefers Canal House in Chesapeake City, MD.

And I stopped working this day in 2025, almost 41 years later, as a senior engineer (which is surprisingly a lot like busing tables — lots of cleanup and setting the table just right for the customers to have a great time).

Along the way I worked on, among other apps, Userland Frontier, NetNewsWire, MarsEdit, Glassboard, Vesper, OmniFocus, OmniOutliner, and Audible.

* * *

My immediate plan — Exhale! Breathe. Enjoy a steak. Watch WWDC from the comfort of home next week. Get back to work on NetNewsWire.

🌲

Retirement and NetNewsWire

To answer some questions people have asked me about my impending retirement…

What does it mean for NetNewsWire?

Good things! I’m not retiring from writing apps — which means I’ll have a lot more time for working on NetNewsWire.

It’s been 15 years since the last time I could work on NetNewsWire during weekdays (as opposed to just nights and weekends), and I’m super-psyched for this.

Will you work on any other apps?

Yes. I have several ideas for other apps I’d like to work on, and have made a little progress on one of them.

They will all be free and open source. I have no plans to create apps for money. (I’ll be retired — not working for money anymore is the point.)

Will you be taking a big trip right after retiring?

Every time this comes up, I joke that the first thing I’ll be doing is sleeping. Forty years of work is a long time, and I’ve earned a long nap.

We do have some travel plans, but no big trips yet. We will. There’s so much of the world we want to see!

My actual first week of retirement will be taken up by WWDC. I won’t be there — I’ll be at home watching the videos like most everyone else. Only this time I won’t have to think about how the changes will affect things at work.

Do you have any other hobbies or plans? Are you getting into woodworking? Pizza-making?

Yes to other hobbies and plans, though probably not woodworking or pizza (but never say never — those are pretty tempting ideas!).

Making apps is important to me — contributing to the public stack is how I can best use my abilities to make the world better — but it’s also not the only thing.

I have more ideas than time, which is a good problem to have, and once I have some space to think and feel I’ll be able to start picking and get to work.

Will you be blogging more?

I hope so!

The hard part is, after 25 years, finding things to say that I haven’t already said. Maybe I’ll just decide it’s okay to repeat myself in new ways. 🐥

My Wildly Incorrect Bias About Corporate Engineers

Before I went to work for Audible (five years ago now — time flies!) I had a bias about engineers that worked for large corporations. I assumed that they weren’t as good as indies and engineers at small companies, or else they’d actually be indies or work at small shops like Omni.

Obviously I knew there had to be exceptions, particularly at Apple, or else we wouldn’t have had great things like AppKit and UIKit and everything else we’ve built on over these years. But the bias persisted.

* * *

Before Audible, the largest company I’d ever worked at (Newsgator) had just over 100 people. When I worked at Omni it had roughly half that number.

I’ve spent half my career working at even smaller companies, with just me and Sheila (Ranchero Software) or at places with three people (Q Branch) or like six people (UserLand Software).

And of course I was arrogant enough to think that I was better — much better — than any corporate engineer. While a corporate engineer might own some small part of an app or framework — or just a single button, as the (lame) joke went back in the day — I was shipping entire apps on my own or with a very small team. Popular, valuable, newsworthy apps that people loved.

And I wasn’t the only one: think of Flying Meat, Rogue Amoeba, Bare Bones, Red Sweater, The Iconfactory and many more.

* * *

And so I learned very quickly when I started at Audible that I was very wrong. I was impressed, and grew more impressed as time went on, by my fellow engineers’ rigor, talent, professionalism, care, and, especially, ability to work with other people toward common goals.

While I’m the die-hard introvert who just wants to go into a room and sit in front of a Mac and write some code and get things done, I learned that my co-workers — even if they, like me, kinda just wanted to sit and write code — were great at app development as a team sport. I was impressed with how they wanted to grow and did grow — always leveling-up their individual skills and their ability to work on a team and across teams.

And what a team it was! It’s not a new observation, but the indies I mentioned above, and the ones I didn’t, tend to be white men born in the United States — the people who could most afford to fail, in other words, because for them (for me, absolutely) there’s always another opportunity.

My team didn’t look like that — it was quite a contrast with my previous experience. Many more women, people of color, people born outside the United States. (But note that there’s always more progress to be made!)

The engineers on my team could write apps as well, if not better in many cases, than the indies I know. And the ones who aren’t quite there yet — well, just give them a little more time. They’ve all given me reason to believe in them.

I regret my bias about engineers working in corporate environments, and I’m so glad I learned the truth almost from day one on starting at Audible.

* * *

For a couple years I did a lot of hiring — a lot of interviews — at Audible. And I noticed something: there was a strong correlation between being hirable and having worked with other people.

The folks who’d worked largely by themselves, or on just one small team, weren’t as good candidates as the folks who’d worked with more people. This, of course, went against my original bias that indies are the best engineers — but by then I knew that a candidate who’d worked with lots of other people had been exposed to more code, more dilemmas, more challenges (technical and human), and they were not just more ready to work on a larger team but more knowledgeable. Even their individual skills were greater.

Advice time: if you’re a newer engineer, find ways to work with other people. Not just because you’re more likely to get hired at a place like Audible — but because, no matter where you want to work, you’ll be better at it.

You can’t just sit alone in front of your computer all day and write code and expect to be a great engineer.

Lesson learned!

* * *

With retirement imminent — this is my last job, and June 6 is my last day (maybe I’ve buried the lede here) — I want to thank my team publicly for how they’ve made me a better engineer and, more importantly, a better person. From the bottom of my heart.

I learned more from them than I could ever have taught; I got the better part of this deal.

Thank you, team! So much. ❤️