Added By: Feedage Forager Feedage Grade B rated
Language: English
app  apps  blog  evergreen  feed  it’s  i’m  mac  micro blog  micro  omni  people  read  server  time  web   
Rate this Feed
Rate this feedRate this feedRate this feedRate this feedRate this feed
Rate this feed 1 starRate this feed 2 starRate this feed 3 starRate this feed 4 starRate this feed 5 star

Comments (0)

Feed Details and Statistics Feed Statistics


Brent Simmons’s weblog.


The Omni Show #10: Dave Lonning, Documentation Wrangler

Wed, 14 Mar 2018 12:09:31 -0700


In this episode we talk with Dave Lonning, who writes documentation for Omni apps. Dave’s a long-time fan of role-playing games — running them and creating them — and he lived for years in Japan before making his way to Omni.

Among Dave’s hobbies is painting miniatures:


Dave, it should be noted, is a cat person — but, importantly, he’s learned to love the Omni dogs. They’re good dogs, Dove.

Marketing Human

Fri, 09 Mar 2018 16:50:30 -0800

I’ve got some career-change news that might sound weird at first but that I promise will make sense in a minute: I’m quite happily still at Omni, but I’m switching from engineering over to marketing.

I am the new Marketing Human, a new member of the Design department.

If you think of me as an engineer, you’re not wrong — but the secret, hidden in plain sight, is that throughout my career I’ve done a whole bunch of design and things that could be called marketing.

Blogging could be called marketing, after all, and today I wrote my first post for the Omni blog.

(For whatever freakish reason, writing has never been a chore to me — I love it. Sometimes I think I only make apps just to have something to write about.)

But the new job isn’t just blogging — I’m also doing a podcast. I’ll help figure out the marketing points behind the release of OmniFocus 3. I’ll write some ads. I’ll create new websites. I don’t even know what all the different things are yet.

I’ll also help with defining future versions of our apps, which is super-exciting for me. This keeps me close to the process of app-making — at a different level, sure, but at a place where I’m quite happy, since I’ve done this kind of work with Frontier, NetNewsWire, MarsEdit, Glassboard, Vesper, and now with Evergreen and back to Frontier.

In other words, I’m using the skills I’ve learned as an indie and sort-of-indie over decades — just not the skills I write about here that often.

Make sense? Cool. :)

* * *

For now, until OmniFocus 3 ships, I’m splitting my time: doing this and continuing to work directly on the Mac app. After that I’ll be a full-time Marketing Human.

If you want to get in touch with me, you can email me at marketing at The Omni Group’s domain name.

* * *

One interesting part of this — at least for me — is that, for the first time in decades, I’ll be back to writing code purely for fun. I’ll continue to work on Evergreen and other apps on nights and weekends, for sure. And I’ll keep writing about code on this blog.

But engineering will just be my hobby. I love that.

Greenwood: Unfinished Microblogging System

Fri, 02 Mar 2018 22:06:25 -0800

A year ago I was working on a microblogging system and wrote a bunch of it, but I didn’t actually finish it.

When I realized it’s not what I actually want, I shelved it.

But interest in microblogging has grown since then — thanks to — and so I posted my code on GitHub just in case somebody else wants to fork it and do something with it.

The app is called Greenwood. Partly because I like the freshness it evokes — it’s a great name for a fresh, simple start — and partly because Greenwood is the neighborhood next to mine (I’m in Ballard), and I’ve been giving things Pacific Northwest names lately.

* * *

Blog posts are stored as separate files on disk. There’s a place for attributes at the top of each file, and then the rest is Markdown.

It’s written in Ruby; it’s a Sinatra app. It’s fast. I tested it using eight years of’s files.

My plan was to put it in front of a caching Nginx server, so it would essentially run as fast as a statically-rendered site.

There’s surprisingly not much code. And, well, that’s because it’s unfinished.

And — as it says at the top of the README in the repo — DO NOT DEPLOY THIS APP AS-IS. IT IS NOT SECURE.

Script Debugger 7

Fri, 02 Mar 2018 14:33:37 -0800

Script Debugger has long been the secret weapon of people who write AppleScript scripts — and now it’s at version 7. Better than ever!

Plus really cool new icons!

Evergreen is AppleScript-able. So are Omni’s Mac apps. So is Acorn. And MarsEdit. And so many others.

(Bonus tip: FastScripts is a great utility for running AppleScript scripts. I use it all day every day.)

The Omni Show #9: Ainsley Bourque Olson, OmniPlan PM

Wed, 28 Feb 2018 11:51:33 -0800


The latest episode of The Omni Show features Ainsley Bourque Olson — who’s the product manager for OmniPlan, a project management app. It’s almost meta!

She’s also a knitter — we have a pretty strong group of knitters here — and a cat person.

Me too. In fact, I’m going to go find a place in the sun to curl up. :)

OmniOutliner 3 for iOS

Wed, 14 Feb 2018 16:14:29 -0800

I’d done almost no iOS work since system 7 came out — but, once we were finished with OmniOutliner 5 for Mac (a release I’m super-proud of), it was time to go work on OmniOutliner 3 for iOS, and so they pulled me back in. :)

I was just one person on a much bigger team, of course. I helped indent some things and helped with filters. But there’s a whole bunch more besides — it’s a big release.

And it’s the first OmniOutliner for iOS release with a lower-cost Essentials version ($9.99). And it’s a free trial.

And I’m super-proud of this release, too.

Read all about it on The Omni Blog: OmniOutliner 3 for iOS is here! Get your free trial from the App Store.

The Omni Show #8: Orion, Bug Hunter

Wed, 14 Feb 2018 12:22:22 -0800


In the latest episode of The Omni Show I talk to Orion Protonentis, recovering actor and stage fighter, friend of Shakespeare, and Software Test Pilot.

The Scottish Play is mentioned, but only as “the Scottish play.” So we’re all good there — if you’re in a theater right now you can safely listen to this.

Brenty’s First Pod

Tue, 06 Feb 2018 21:49:09 -0800

RSParser is now a CocoaPod! It’s my first.

I’m super-proud of myself for taking this the last few tiny steps of the way there — Silver Fox did all the rest of the much-appreciated work.

This means that if you’re a CocoaPods user, you can now go forth and parse feeds.

Still to do: support Carthage and Swift Package Manager. And, after this repo, there are at least a half-dozen more to do.

But that’s okay — doing open source is what I signed up for, and learning and using the infrastructure is part of the gig.

PS I really like what happens in the Terminal when you successfully publish a pod. Here’s a screenshot.

On Missing the Point

Tue, 06 Feb 2018 13:08:21 -0800

(Disclaimer: before I get started, I should take extra care to note that I don’t speak for Omni. This is my personal blog, with my personal opinions.)

Every time I make some criticism of the App Store — that, for instance, the 30% cut for Apple is too high, or that free trials would be a good thing — some number of people respond that Apple is a business and they’re allowed to do what they’re doing.

They may also remind me that this is capitalism, and that I can vote with my feet — that is, go create an Android app (or whatever) where the cost is presumably lower.

And they remind me that I should work with the world as it is, rather than the world as I want it to be.

They’re not wrong. Of course Apple is a business and is within their rights to charge whatever they want to charge, and developers could go do something else. And when making business decisions we have to look at facts and best extrapolations, not wishes and ponies.

But that misses the point entirely.

* * *

The point is that we are allowed — even in a capitalist system! — to criticize and to ask for changes. You can ask your spouse to put away the dishes more often; you can ask your kids to do their homework before dinner; you can ask the government for universal health care or corporate tax cuts; and you can ask Apple to lower the App Store cut.

Imagine if Starbucks charged $20 for a latte. You might complain about it and ask them to lower the price. Even if there’s another coffee shop nearby with much less expensive lattes, you still might.

Yes! Even in a capitalist system you can do this! It’s totally a-okay! Even if they’re within their rights (they are) to charge that much. Even if they are a business!

There’s no sacred verse that says businesses acting lawfully can’t be criticized. Nothing says we can’t advocate for change. In fact, I’d say that that’s part of capitalism, too.

* * *

So I got into a lengthy Twitter argument about Apple’s 30% App Store cut.

My thinking is that a lower cut provides more incentive for developers to invest in high-quality, long-lived apps — and that that’s good for the platform and good for users, and good for Apple, and so everybody wins.

It’s at least worth trying (this being capitalism, there are no guarantees of success) — and, since Apple is the wealthiest company in the history of companies, they could afford to try this.

If I’m right, then everybody wins: Apple, users, and developers. And if I’m wrong, Apple is not in any financial jeopardy.

* * *

I don’t think I’m misunderstanding or breaking the rules of capitalism by saying this. Nor am I telling developers to base their business decisions on fantasies.

But somebody will tell me that I am.

Why is Not Another

Thu, 01 Feb 2018 13:01:38 -0800

We could be excused for thinking that is like — a Twitter alternative greeted with enthusiasm but that eventually closed. It’s not the same thing, though, and I’ll explain why. is not an alternative silo: instead, it’s what you build when you believe that the web itself is the great social network. That’s the important part: even if doesn’t last (though I believe it will), the idea — that the web itself is where we are and where we talk to each other — will continue. And: could be just one of thousands of similar services. And those services would all work together, because they’re made of web-stuff. The Dream of 1999 Pick your year. I like 2003, since that was when I released NetNewsWire 1.0, an early Mac RSS reader. You might prefer 2000 (nice round number) or 2005 (things were a bit more advanced). But if you think of the years 1995-2005, you remember when the web was our social network: blogs, comments on blogs, feed readers, and services such as Flickr, Technorati, and BlogBridge to glue things together. Those were great years — but then a few tragedies happened: Google Reader came out, and then, almost worse, it went away. Worse still was the rise of Twitter and Facebook, when we decided it would be okay to give up ownership and let just a couple companies own our communication. Even if those companies had the public interest in mind — and they most definitely do not — they hold far too much power over something too fundamental to give up: our own human voices. Twitter and Facebook are convenient, sure, but so are fossil fuels, and the cost was similarly unknown for a long time. But now we have some idea just how bad these things are for the world. rewinds us to 2005 (or pick your year) — but, also, it has learned the lesson that people really like a timeline of short posts. People like being able to write and reply easily to other people. Good to know! Blogs When you post to, you’re posting to an actual blog with an RSS feed and everything. The blog might be hosted by, or it might be some other blog somewhere else. (Could be a WordPress blog, for instance.) Your posts are just a normal, everyday part of the open web. At this writing, mine appear on — but it’s on my to-do list to have those appear on my main blog (this blog) instead. (Probably won’t happen until after I ship the app I’m currently working on.) And this is how it used to be, and how it never should have stopped being: my blog is me on the web. I own my blog: I own me. And so everyone who follows me on sees my blog posts, and I see theirs. Simple. And anyone who wants to could just read my blog in an RSS reader instead. All good, all open. Replies Replies are a little trickier. ( is not a finished thing — the-web-as-social-network is not a finished thing, and, we hope, never will be. That’s totally fine.) Replies don’t appear on your blog (though this could become an option, I suppose) — but they are sent as a WebMention when possible, which means even replies are part of the open web. You can read more about replies and @-mentions on the help site. I expect this area to get more work in the future, especially as it’s part of the key to making part of the great social network but not the great social network (the web itself). The app in your pocket If you’re running the app on your iPhone or Mac, it really does look like a slimmed-down Twitter. This is by design. But don’t let that deceive you. If the web is a river, is water, where Twitter and Facebook are dams. What about my Uncle Joe? You might think this is too difficult for normal people, that it’s all too nerdy, and t[...]

The Omni Show #7: Ken Case Talks About the 2018 Roadmap

Wed, 31 Jan 2018 10:49:12 -0800

Check out episode #7 (I wish we had called it 007) where Ken Case talks about all the good stuff coming up in 2018.

There will be new releases of OmniOutliner, OmniPlan, and OmniGraffle — plus a whole bunch of great stuff for OmniFocus 3.0 for Mac and iOS, including tags, JavaScript scripting, and OmniFocus for the web.

You can subscribe to the podcast or just listen to this episode — there’s a player on the page. Or you can read the transcript.

* * *

I’ve been wondering if other companies in our world are doing similar podcasts.

There is the Supertop Podcast from our friends who make Castro. And there are much larger companies (such as Microsoft) who create videos and podcasts.

It may be that Omni’s size is somewhat unique in the Mac and iOS world: it’s big enough that we won’t run out of people to interview and topics to talk about, which could be tricky for a 5- or 10-person company. And it’s small enough to still be intimate — my goal is to eventually interview every single person who works here. (Though, of course, people can decline: it’s not required!)

Anyway: there was a time before companies had blogs, and now they have blogs. I wonder if more and more companies will find value in having a podcast too.

(And a Slack group. And a account.)

Evergreen Diary #9: On IndieWeb

Thu, 25 Jan 2018 13:21:54 -0800

When IndieWeb started, some years back, the first thing I noticed was that they appeared to be against the idea of feeds — or, at least, what they called side feeds: RSS and similar.

Their idea was that the data a reader might collect should be encoded in the page itself, using microformats. The argument (I think; I hope I’m not misrepresenting anyone) was that microformats are simpler than mantaining a separate file.

I don’t know which thought occurred to me first:

I took it personally, since I’d spent much of my career working with feeds, and I took this as a suggestion that my career was all wrong and they wouldn’t be interested in someone like me, someone who would be an ally in their committment to the open web.

I objected on practical grounds, too. Feeds have been and remain tremendously successful — see podcasting, for one thing — and the way forward is to build on that success. And, while I understand the elegance of microformats, side feeds have critical advantages that microformat-feeds don’t.

So I decided to ignore IndieWeb.

Here’s the thing, though: that was me being a total jerk.

(I’m telling you about this so you can learn from my mistake.)


In the last couple years I’ve been chatting with Manton Reece, creator, a bit — and Manton agrees with me about feeds.

But Manton also works with IndieWeb, and has mentioned any number of good ideas they have that I should look into.

It took me a while, but I realized that I was acting like a Clinton or Sanders supporter still arguing with the other side about the 2016 primaries — after losing the general election to a monster, after the point where those small differences matter at all.

And then I started to get excited about IndieWeb. I may have a difference of opinion when it comes to feeds, but who the hell cares when there’s so much good stuff to do? (They’re not holding my opinion against me; why should I hold theirs against them?)

And so I decided to support the h-feed format in Evergreen (hopefully in 1.0). That’s just for starters: I also decided to look into everything else and see what makes sense to support.

My default position now is: if a format or API or syncing service makes sense for a feed reader, then I’ll (at least try to) support it.

Evergreen Diary #8: Coding Guidelines

Wed, 24 Jan 2018 13:20:45 -0800

I published the first draft of Evergreen’s Coding Guidelines yesterday.

I posted this because I’d like to have people help me with the app — but I’m not ready yet. Or, rather, a few people who I know are starting to help, and I want to keep it small for now since I’ve never done this before.

If you’re interested in helping, I hope you’ll forgive me as I take it slow and learn how to manage an open source app with many contributors.

* * *

This isn’t the only app I want to do: there are several others. Ideally I’ll get to the point where I’m managing several open source apps — assuming people are interested in helping, which is a big assumption — and it’s all going great. But it will take time to get there.

(All my ideas are Mac and iOS apps that have something to do with the open web. I’ve always been happiest when working at that intersection.)

Anyway… it seemed like a good idea to write up coding guidelines early, so I did.

PS When I was faced with that blank document window, I started by typing the words “No subclasses,” because sheesh I really, really hate subclasses. The rest tumbled out.

Evergreen Diary #7: Syncing and Immediate and Deferrable Actions

Fri, 19 Jan 2018 13:29:16 -0800

There are, as I mentioned previously, two types of syncable actions: immediate and deferrable. An immediate action is something like adding a feed: it requires that the server is reachable right now, so that the feed actually gets added. A deferrable action is something like marking articles as read. The sooner the server knows, the better, sure — but it can wait if necessary. It can even wait for weeks or months. I’ve decided to make it simple and categorize these actions like this: any structural action that affects the list of feeds and folders (or tags) is an immediate action, while any action that affects the status (read, starred) of articles is deferrable. Or, in UI terms: if it’s something you do in the sidebar, it’s immediate; it it’s something you do in the timeline, it’s deferrable. Most importantly: you can read articles while you’re offline. Discarded alternate approach You could argue that all actions should be deferrable. For instance, Evergreen could remember that you want to add a given feed, and add that add-feed action to the sync queue and wait for the server to become reachable again. But doing so would add more chance for conflicts. Consider the case where the add-feed action got queued (on your day Mac) and then just sat there. Then, on your night Mac, you add the feed and it succeeds — then you decide you don’t like it after all, then delete it. The next day, back on your day Mac, the add-feed call finally goes through, and then you have to delete it again. (And then you report an Evergreen syncing bug.) There are other issues as well: do you add the feed locally? And read it? No, because this gets ambiguous quickly, as Evergreen’s article IDs won’t match the article IDs the server has assigned. Evergreen might not even have found the same feed URL the server found (in the case where you just gave it a website URL). So we’ll stick with these two categories, immediate and deferrable. To refine the definitions: a deferrable action is one where the state change can be reflected locally without risking serious conflicts or ambiguity. Immediate actions These will result in an immediate API call, and the result will be reflected in the UI. This is straightforward. Deferrable actions These actions will be stored in a database. The simplest way to do this is probably a set of tables: articlesToMarkRead, articlesToMarkUnread, articlesToStar, articlesToUnstar. Each table would have one single column: articleID. This layout is probably the most efficient way to add/delete articles. This is not actually an ordered queue, but I think that’s okay. Most of the time all four tables will be empty. When articles are marked read (for instance), then those articles will be added to articlesToMarkRead and deleted from articlesToMarkUnread. The system will then know that it has pending status changes to the send to the server. Then, periodically, the app will attempt to contact the server. Most of the time this should happen within a minute or so. Part of the idea is using this system to coalesce calls: the app shouldn’t call the server every time you select an article (which marks it read). Better to update the database and call the server very-soon-ish, but not necessarily this exact second, to allow for multiple articles to queue up. The downside to this particular layout, which may make me change it, is that supporting additional status types means adding more tables. But the alternative is to add more columns to a single table, which is better but not necessarily that much better. Another downside is that there’s no automatic guarantee that an article ID won’t exist in, say, both articlesToMarkRead and articl[...]

Evergreen Diary #6: Proposed Sync Design

Wed, 17 Jan 2018 21:02:45 -0800

Most of the time, a user will do a thing — mark some articles as read, for instance — and then Evergreen will tell the server (Feedbin, Feedly, etc.) right away. That’s good and easy. The hard part is this: what happens when the server is not reachable for some reason? Continuing the example: Evergreen could, in the case of the unreachable server, refuse to mark those articles as read. It could insist that syncing works only when the server is reachable — which is not that weird, especially given that it can’t pull new data from the server unless it’s reachable. But it’s weird enough. Consider that selecting an article marks it as read. This policy would make it impossible to even just read what you’ve already downloaded. Offline Syncing It’s clear that syncing requires some sort of offline ability. Rather than set a policy for each possible user action (marking articles read, deleting a feed, etc.), I want to set a single policy and single structure for handling these actions. (Note: there will be some things that do actually require a reachable server: downloading new articles and adding a feed come to mind. This design refers to actions where it would be okay to defer notifying the server.) Proposed Policy When the user performs a syncable and deferrable action, that action and the relevant parameters will be remembered. Evergreen will attempt to notify the server periodically. Once it succeeds, it will forget that action and its parameters. (Update 18 Jan: 2018: the original version of this design had a time limit, which has been removed. The concern was that this offline queue would grow unbounded — but it can’t, since if you can’t reach the server you can’t download new articles, which means the queue is limited to your current local data set.) Proposed Implementation When the user performs a deferrable action, the app tries immediately to notify the server. If this first attempt fails, then the action is recorded in a SQLite database with a timestamp and with the parameters it needs to be able to make that call again later. Those parameters will be minimal — article IDs instead of entire Article objects, for instance. The app will periodically attempt to empty this database: starting with the oldest action, it will notify the server of each. On success, a given action is removed from the database. Undo Evergreen supports undo as much as possible. For instance, if you mark a number of articles as read, you can undo it. In this case, Evergreen will notify the server of the mark-read action, and then, upon undo, notify the server of a mark-unread action, thereby undoing the effect of the first action. In the case where the mark-read action is in the offline action queue, that will be found and deleted, and there will be no queued action to reverse the effect. Non-Deferrable Actions Actions that require an immediate response from a reachable server include actions such as adding a feed. In the case where a user attempts one of these and the server can’t be reached, an error sheet will explain the problem. Such actions will not be queued. There will not, however, be an error sheet for performing a refresh when the server is unreachable. Instead, in that case, a warning icon is placed next to it in the sidebar, a la Mail and similar apps. Clicking the icon will attempt a connection to the server, and an error sheet explaining the problem will appear if the server still can’t be reached. Other Notes Evergreen works like Mail and similar apps in that it has a set of accounts for services such as Feedbin, Feedly, and others, along with an On My Mac account that is not synced. Each accoun[...]

The Omni Show #6 with Liz Marley

Wed, 17 Jan 2018 09:05:58 -0800

This episode features Liz Marley, OmniGraffle engineer, formerly a tester and PM.

She talks about switching from testing to writing code — and about how she came to do technical talks using Swift playgrounds. Playgrounds with ducks, that is, because every good playground has ducks.

Evergreen Diary #5: Send to MarsEdit

Mon, 15 Jan 2018 14:26:26 -0800

The latest build of Evergreen, fresh from the lab, now adds MarsEdit to the sharing menu in the toolbar.

When you choose the command, it sends the current article to MarsEdit — which opens it in a new window, and then you can edit and add your own commentary before posting to your blog.

* * *

See SendToBlogEditorApp.m for the code that packages up the article and sends an Apple event.

The code is not MarsEdit-specific — other apps in the past have supported this same Apple event, though I don’t know if any other current apps do. If I find some, I’ll add them to the sharing menu alongside MarsEdit.

* * *

The Apple event code is written in Objective-C, even though I almost always write new code in Swift. But, with Apple events code, Objective-C is easier.

It’s easy to call from Swift: see SendToMarsEditCommand.swift.

(Reminder: this is all MIT-licensed. You can use this code.)

Evergreen Diary #4: Send to

Mon, 15 Jan 2018 09:35:13 -0800

The latest build of Evergreen adds to the Share menu in the toolbar, if you have the Mac app.

It sends the title and link of whatever you’re reading over to the Mac app, and you can edit it before actually posting.

This is hugely important. RSS readers exist not to just make reading easy but to make the web a conversation.

The next release will (probably) include MarsEdit, for the exact same reason. If you have ideas for other apps to include, let me know (see the bottom of the Evergreen site for contact info).

Ideally, every app like and MarsEdit would have a sharing extension — but, where they don’t, I can add them as long as they support some kind of way to do so.

Technical Details supports a URL scheme for sending it a post: see See SendToMicroBlogCommand.​sendObject for the implementation in Evergreen. (And of course feel free to use any Evergreen code in your app.)


It’s not that we realized just today that posting from an RSS reader is important. Since posting was always an absolute requirement, way back in 2003 I released NetNewsWire 1.0 with an integrated blog editor.

I got that idea from Radio UserLand, which was an RSS reader and blog editor by the company where I worked before I wrote NetNewsWire. It’s Dave’s idea, not mine.

By the time I was working on NetNewsWire 2.0, it became apparent that smooshing a blog editor into a reader app meant that the blog editor suffers. The blog editor in NetNewsWire 1.x was pretty darn bad. So I had the idea of splitting out the blog editor to a separate app — inducing mitosis — which you can read about in my MarsEdit report of late 2004.

Mitosis was a success.

One of the keys of that success was that the API for contacting MarsEdit had to be open, and NetNewsWire had to support any blog editor, or any other app, that supported that API — because otherwise I would have been unfairly leveraging success with NetNewsWire on behalf of my new blog editor, and that would have been wrong.

MarsEdit still supports that interface, and my next step is to write the client side in Evergreen, so it can send to MarsEdit and any other app that supports that interface.

I am, by the way, delighted to be writing code for a 14-year-old API that still works.

Mentions: Proof-of-Concept

Thu, 11 Jan 2018 13:13:41 -0800

Ben Curtis posted feed_searcher to GitHub — it creates custom search feeds, and even has a handy Deploy to Heroku button. Cool.

(This is in reference to App Idea: Mentions).

App Idea: Inside Story

Thu, 11 Jan 2018 13:09:35 -0800

I had this idea around the time Apple came out with Bonjour (née Rendezvous), and all these years later I realize I’m never going to get around to it.

Here’s the scoop:

The idea is microblog posts (tweet-like) but that live inside a specific network only.

You run a Mac app that:

  • Lets you post short messages.
  • Shows short messages from people inside your network.

The app runs a small webserver that’s discoverable via Bonjour, that has a specific service name. That webserver publishes a feed of your posts.

The app also downloads a feed from every other app it finds (and caches those feeds, for when other apps are offline).

In other words, it’s instant office microblogging with no centralized server. Completely peer-to-peer.

The design is what you expect — a reverse-chronological list of posts with usernames and avatars. You can reply, mention people, mute people, etc. (I think you’d follow everybody on the network automatically — so muting becomes the thing, not following.)

* * *

Important thing: your posts are network-specific. So if you go to a coffee shop or the airport with your Mac, you won’t be publishing your at-the-office posts.

* * *

I haven’t done research into whether this is do-able on iOS. Is it possible to run a little webserver, in a backgrounded app, that other people on the local network could connect to? Seems unlikely — but I don’t know. Cool if you could.

* * *

I have no idea how you’d make money with this one. If you charge for it, not enough people would use it to make it worthwhile. (The standard dilemma of social networking apps.)

Maybe, though, you could add some IAP features? One might be to let people add RSS feeds, so it could also function as a lightweight RSS reader. A person might want posts from Daring Fireball and wherever else added to their timeline.

Or just add that feature anyway, and do the whole thing for fun.

PS “Inside Story” is a long name. Should be one word. Scoops? Bulletins? Officecast? Gossip? (“Gossip” was, if memory serves, the name of an app Chuck Shotton was working on a long time ago. Probably reusable at this point.)

(I mean, c’mon, office Gossip. It’s so perfect.)

App Idea: Mentions

Tue, 09 Jan 2018 13:33:23 -0800

“Hold on — I need to check my Mentions.”

Ten years ago or more we had several blog-specific search engines and services: Technorati, BlogBridge, and others.

One of the great things about these services was not just being able to search for something but being able to set up persistent searches: that is, you’d get a search as an RSS feed, and in your feed reader you’d get results from all over the place on the thing you’re searching for.

In the obvious and common cases, you’d set up searches for people linking to your blog, writing about the apps you work on, mentioning the place where you work, and mentioning you.

I’d like to see something like this for today, but where the scope is just the Apple/Mac/iOS community. It would crawl the obvious sites (such as Daring Fireball and Loop Insight) and it would crawl the many blogs and microblogs that make up the community.

I think this is best as a web service, though it could have Mac and/or iOS client apps. It needs to provide feeds for people using feed readers.

* * *

With that reduced scope, and with the better tools and cheaper cloud computing these days, I don’t think it would be terribly expensive. Not like it was 15 years ago.

You might want to make money with this, though, and there are a few ways to do it: charge extra for things like notifications and email alerts. Charge money for client apps. Make the first three search feeds free, and charge money for a ten-pack of searches. Etc.

* * *

An alternate version of this idea isn’t a web service — it’s a Mac and/or iOS app that does the crawling. A kind of specialized Mac/iOS feed reader.

The list of feeds-to-crawl would probably just be an OPML file on the web, and the app would periodically grab that list.

(If you did this, you could use RSParser as starter code, since it parses OPML, RSS, Atom, JSON Feed, and RSS-in-JSON.)

This would make a great open source project, but it could just as well be free or for-pay.

* * *

One challenge is handling spam and abusive or hateful content. You’d most likely want to have a suggest-a-site form, so you don’t have to go out and find every single site there is.

But you have to be able to say no, and you have to be able to update the list of sites-to-crawl quickly if a site turns bad or inappropriate somehow.

You’d also need a way for users to report an issue.

(Again, the reduced scope — Apple-related blogs — makes this somewhat easier than if you tried to do the entire blogosphere.)

* * *

I want this! I’d use it every day. I know other people who would too.

But I’ve got enough on my plate that there’s no way I can do it myself — though I’d be happy to answer questions and provide feedback to anyone who does want to do it.

Evergreen Diary #3: On Punting

Sat, 06 Jan 2018 13:10:23 -0800

I have a vision for 1.0, and then, as time goes on, I have to cut it back beyond where it hurts. I have to keep punting. I hate this part of shipping software.

But I also love it because it reminds me that I have the stomach for it. Shipping software is an emotional skill.

After shipping — no matter what — there will be people who absolutely cannot believe that feature X wasn’t included. In fact, it’s the one thing they totally need.

And they’re right. Not wrong. And I would have loved to have included feature X, loved I not quality (the app maker’s honor) more.

* * *

I wondered if Evergreen as open source instead of as a for-pay app would affect what and how much I punt. I hope the answer is: not at all; the decisions would have been the same.

I think that’s right because I’m trying to make as good an app as I can, which would be true regardless.

But it is nice not to have to consider money as I make decisions. I do think about how I want it to have as many users as possible, and I want people to love the app. And I have to think about the economy of my time. But I don’t have to consider money.

Another difference between open source and commercial is that I can be utterly transparent about what’s been punted. Check out Evergreen’s 2.0 milestone. It will keep growing. Every single one of those things was originally supposed to go in 1.0.

* * *

Some things I keep reminding myself as I make progress toward 1.0…

This isn’t the last release, it’s the first. There will be many more. (I hope to work on this app for 20 years. It’s been only three years so far.)

Any feature I ship, I probably have to support forever. So it’s wise to be cautious.

Quality — design, stability, performance, lack of bugs — is way more important than any collection of features.

And, perhaps most importantly: shipping 1.0 means learning about your users, how they use your app, and what they need — and those lessons will change future plans, as they should. It’s best to learn those lessons early, before doing too much.

The Omni Show #5 with Mark Boszko

Wed, 03 Jan 2018 08:40:02 -0800

In this episode I finally get around to talking to Mark Boszko, the show’s intrepid producer and The Omni Group’s Video Producer.

I’ve known Mark for more than ten years — we met at a SXSW conference many years ago, long before either of us came to Omni. Mark didn’t even live in Seattle in those days. Now he does, and now we have the pleasure of working together on a podcast.

PS If you like movies, definitely check out the podcast Mark hosts: The Optical.

2018: Some Hope

Wed, 03 Jan 2018 06:29:03 -0800

Mike Monteiro writes of Twitter CEO Jack Dorsey: Jack let it happen. He watched as a once-entertaining, once-illuminating, once-vital network to global communication became a garbage fire of hate. He did nothing to stop it. Or curb it. He didn’t see a problem. Our current crises of democracy and good faith did not just blow in with the wind and transform the air without our knowledge or consent. These crises were made by people, and we knew what they were doing, and we agreed to this. Jack Dorsey is one of those many people. Just one. But one with a kind of power that nobody in the world should have: the power to directly control a vast amount of the world’s communication. It’s not that Dorsey failed to consider the good of the world. Or, really, it’s not just that. It’s that this kind of power should not exist at all. But we agreed to it. We’re still agreeing to it. Twitter — and Facebook, and the power of tech companies — is not our only problem. But I have no doubt that had Twitter not become a loving home for hate, Trump would not be President now. In that universe we’d still have big problems, yes, but not like this. How we can stop agreeing to this The great social network is, or ought to be, the web itself. The unruly web — unregulated and uncontrolled — is, perhaps paradoxically, the easiest place to limit hate. Not because we can stop people from publishing, but because we don’t have to live by Dorsey’s and Zuckerberg’s rules and designs. I don’t know all the details of how we get there, or what it will be like once we do. That’s fine: that’s part of what makes the journey fun. Software Consider a few apps. Overcast and Castro and others help ensure that podcasting is not just a vital and exciting medium of independent publishing but is also open and built on standards. Anybody can write any kind of podcasting software they want to — but nobody can control podcasting. And nobody can force you to listen to hate. You pick the shows you want to hear. MarsEdit lets you write whatever you want to write and publish it on the web. You’re limited only by the law and whatever terms of service your hosting provider may have. All the words you read in MarsEdit are your own. And nobody can make you read what other MarsEdit users write. Evergreen (which I’m working on), NetNewsWire, Reeder, Unread and other RSS readers work like Overcast and Castro but for written words. You choose what to read, and if a blogger you like suddenly turns hateful, you hit the Delete key. Then there’s Manton’s new service, which needs its own section… It’s a publishing platform and a social network, based on standards. You don’t even have to use Manton’s Mac or iOS apps: you can write posts in MarsEdit or other blog editor, or read your timeline using an RSS reader. People could, though, sign up for it and flood your mentions with hate. In theory. So I asked Manton about that, and he wrote: is similar to MarsEdit in a way in that it can be used to write hateful posts, etc. What we have to do as a social network is limit the damage. So, by default, if someone writes something terrible… No one sees it. It doesn’t automatically show up in trends (because we don’t have them, for this reason) and it doesn’t show up in Discover (because that’s curated by a human). Replies are where it’s an issue, and that’s where good [...]

Evergreen’s Parser as Separate Open Source Framework

Tue, 26 Dec 2017 18:10:09 -0800

I copied Evergreen’s parsing framework, RSParser, to a separate repository on GitHub.

It has no dependencies other than system-supplied libraries. It’s offered via the MIT License.

It builds a Mac framework only at the moment, but adding an iOS target should be easy. It’s the one issue in the bug tracker (at least so far).

Otherwise it’s fast and stable and does the jobs it’s designed to do.

Things it parses

  • RSS
  • Atom
  • JSON Feed
  • RSS-in-JSON
  • OPML
  • Internet dates
  • HTML metadata
  • HTML links

In addition, you can build your own XML or HTML parser by creating an RSSAXParserDelegate or RSSAXHTMLParserDelegate.

It’s a mix of Objective-C and Swift. More recent code is in Swift.

Parsing a feed that’s RSS, Atom, JSON Feed, or RSS-in-JSON is a matter of calling FeedParser.parse and getting back a ParsedFeed object. Pretty simple.

WKWebView Workarounds

Wed, 20 Dec 2017 15:23:35 -0800

In Evergreen I’m using WKWebView instead of WebView, because it’s the new and improved WebKit view. NSHipster writes: Boasting responsive 60fps scrolling, built-in gestures, streamlined communication between app and webpage, and the same JavaScript engine as Safari, WKWebView is one of the most significant announcements to come out of WWDC 2014. Sounds great! I’m on board. One of the best parts about it — easily enough to sell me — is that a crash in WKWebView won’t crash my app. (Back when I was doing NetNewsWire, crashes in the old WebView — the predecessor to WKWebView — were the most common crash. But, to be fair, many if not most of those were actually Flash crashes.) I’ve also heard, though I’m not sure how to verify, that WKWebView is better for accessibility, too. So it’s a win all around. But it’s not a win all around WebView — good ’ol trusty friend — has a bunch of things that WKWebView is missing. The new web view has no built-in support for finding text, for instance. I’m not sure what I’m going to do about this, since the ability to hit cmd-F and look for some text is a pretty fundamental thing, and I can’t skip it. It also has no delegate method for when you mouse over a link. Seems like another fundamental thing, right? Any browser offers you a status bar or some way to see the URL of the link your mouse is over. What I ended up doing there: my article renderer adds some JavaScript that adds event listeners. (See ArticleRenderer in the renderedHTML() method.) Then I added handlers in DetailViewController: see viewDidLoad and the WKScriptMessageHandler extension. This worked fine: now my status bar shows the URL of the link your mouse is over. Cool. Then the issue of scrolling came up Evergreen’s design includes a key feature: you can go through all of your news just by hitting the space bar repeatedly. If there’s more to scroll in the web view (the article), it scrolls. If not, then it goes to the next unread article. This is a coffee-in-hand feature, which is critical for a news reader. But WKWebView provides no access to its scroll view. (It does on iOS, yes, but not on Macs.) The logic goes like this: if canScrollDown() scrollDown() else goToNextUnread() There are two parts to this, and both (I thought) required access to the scroll view. canScrollDown() Well… JavaScript comes to the rescue again, just as with the mouseover-link handling. I can run a script in the app and get the results — and JavaScript can tell me the content height and the current amount of scrolling. (I already know the frame size, but I could have gotten that via JavaScript also.) I did this an DetailViewController, in the fetchScrollInfo method. (Unfortunately, this is asynchronous. I expect it to be super-fast, but I won’t know if this is a problem without a bunch of testing. Let’s set that issue aside.) The fetchScrollInfo method creates a ScrollInfo struct (at the bottom of DetailViewController) that has canScrollDown and canScrollUp properties. So that’s how I know if the web view can scroll. Part one of two solved. scrollDown() I tried making it scroll via JavaScript. It’s super-easy. But it’s not animated, and it needs to be. (In Safari, with a scrollable page, hit the space bar — notice how it animates.) So I did some research and found some JavaScript util[...]

Evergreen Diary #2: Random Notes

Sat, 09 Dec 2017 12:57:58 -0800

I’ve been working on Evergreen for about three years, and so I considered writing about playing such a long game — but then Daniel released MarsEdit 4.0 after seven years. I tip my fedora to the master. * * * But there is at least one difference: it’s taking so many years just to get to one-point-oh. I’ve never been on any kind of project that took so long just to get to the initial release. The app’s been built from the bottom up. Since I knew in advance what I needed, I could write code that wouldn’t get actually used for years. Here’s a small example, written almost two years ago: RSHTMLMetadata.h. The scoop: it always bugged me that in NetNewsWire, when it was mine, the favicon downloading system never checked the metadata in a feed’s home page to find the favicon. It always just appended /favicon.ico — which wasn’t always correct. So it would get the wrong one or just not find it. (Note: it’s entirely likely that the current version of NetNewsWire has fixed this bug.) So, a year-and-a-half ago, I wrote code in RSHTMLMetadata that pulls the favicon URL from web page data. And then, just last month, when I finally got around to writing the favicon downloading system, it took very little code to actually pull the favicon URL from a web page (in FaviconURLFinder.swift): let htmlMetadata = RSHTMLMetadataParser.​htmlMetadata​(with: parserData) return htmlMetadata.​faviconLink This pattern — ground-up development, where you know what you need in advance — isn’t really different from apps developed much more quickly. The difference is the amount of satisfaction I feel when I finally connect old and new pieces. It feels great. And that’s the position I’m in now, now that I’m at the top layer: code that I wrote a long time ago is finally getting used. The puzzle is coming together. * * * Of course, I didn’t, and couldn’t, know everything in advance. I didn’t know I’d want Open Graph and Twitter images from web page data — but I was glad when I found that the code I’d already written was easy to extend. * * * Since I have no commercial interest in Evergreen — since it’s free and open source — I can take all the time I need. One of the many advantages of this is spending more time writing unit tests than I used to. There aren’t enough, yet — not even close; and there never are enough — but they do exist. Here, for example, are the tests for HTML metadata parsing. And when I find a bug I add a new test: for example, the feed type detector was not detecting Natasha the Robot’s feed as RSS. So I fixed the bug and added a test. * * * From the now-it-can-be-told department… a couple years ago, in November 2015, I collected a list of blogs written by women that would be “of interest to Mac/iOS developers, designers, and power users.” This was for Evergreen. When I was working on NetNewsWire, the default feeds were all, or almost all, written by men. For Evergreen I wanted to fix that, and I also wanted to create a larger feed directory that was inclusive. (Here’s the plist for the directory. It still needs a bunch of work.) If you have feeds to suggest, please do a pull request. Or send me a note on Twitter via @evergreen_mac. * * * I just started working on syncing via Feedbin. It’s what I use, and syncing is necessa[...]

The Omni Show episode #4 with Andrea McVittie, Omni Slack Group

Thu, 07 Dec 2017 13:21:20 -0800

Yesterday we published an episode with Andrea McVittie, User Experience Designer at The Omni Group.

Andrea will brook nae interference with the puppies. Be nice!

She also talks a bit about how design works at Omni and about design and ethics. After we posted the episode, she followed up with a tweet where she codifies her ethical guidelines.

* * *

Recently Omni created a Slack group — you can join up.

It’s not intended as a replacement for support. But you can talk with Omni people and with other people who use Omni apps. It’s not super-busy; it’s, well, nice. I like having the people who use the things we work on so nearby.

The Omni Show Episode #3 with Brian Covey, Support Manager

Wed, 22 Nov 2017 13:01:09 -0800

New episode is up!

Brian is the Support Manager at The Omni Group, and he has a bunch to say about how support — and the Support Humans — work at Omni, including how they’re involved with product decisions, and how we came to offer phone support.

DVD extras content: a video from 2006 of Brian doing the worm. Unmissable.

The Omni Show

Wed, 08 Nov 2017 13:15:56 -0800

I’m the host of a new podcast: The Omni Show. Here’s the announcement on the Omni blog with all the details. There’s a Twitter account, @theomnishow, you can follow.

I’m super-excited to be doing this, partly because my co-workers at Omni are interesting, and partly because some of it may actually be useful — that is, learning how we think about UX, testing, engineering, support, and so on might be helpful for other people. That’s my hope.

Our first episode is with Kristina Sontag, Software Test Manager, and the second episode is with Curt Clifton, OmniFocus engineer. The next two episodes will feature support and UX. We’re covering all the bases. :)

I’ve done podcasts before (see Identical Cousins and The Record), so I’m not completely new to this. It’s produced by Mark Boszko, also a podcast veteran, who does The Optical, which is a must-listen for everybody who likes movies. The music is by Aaron Cherof, composer extraordinaire, and the look of the site is by Kaitlin Reiss. My favorite touch is the big “THE OMNI SHOW” title at the top — watch it as the gradient slowly changes. It’s mesmerizing.

And, of course, there are more people working on the show. Like everything else, it’s a team effort, but it goes to the theme of the show (“The Omni Show is people!”) to mention some specific individuals — and to thank them. Thank you to everyone who works on The Omni Show.

On Fixing that NSNull Crasher in Overcast

Tue, 10 Oct 2017 16:08:04 -0700

I don’t normally head home after lunch, but today I was on the bus going back to Ballard, about to open iBooks on my phone and get back to reading The Caledonian Gambit (which I’m thoroughly enjoying), when I decided to check Twitter first — and saw Marco’s tweet about Overcast’s oldest crash. I’ve written before about how I love fixing crashing bugs. Partly because I’m adamant that an app should, at a minimum, keep running — and also because it’s fun detective work. (I’ve even written a series of blog posts on how not to crash in the first place.) So I took this one as a challenge. Here’s how I figured it out: The exception reported [NSNull doubleValue]: unrecognized selector. Now, NSNull is a stand-alone code smell: there’s hardly ever a time where it should be used. Well, there was that one weird thing with the kerning a long time ago, but that’s about it. This crash is probably not that. Then I looked at the backtrace and saw -[NSRTFWriter writeKern], and then I looked a little further and saw that an NSAttributedString was being exported to RTF, and, furthermore, writeKern probably is writing out the kerning attribute, which was set to NSNull. writeKern was expecting an NSNumber. So that was it. I replied: The kerning attribute is NSNull. That used to be the way to specify use font-specified kerning. And then Marco found the bug and fixed it. * * * This is a story about experience and luck, not brains. It’s just that I’ve been working with these APIs for a long time. Here’s the story behind setting NSKernAttributeName to NSNull. Back in the iOS 6 days, when John and Dave and I were working on Vesper — which used a custom font, Ideal Sans — we noticed that the kerning was fucking awful. We obviously couldn’t ship it like that. We had to either figure out how to fix the kerning or switch to the system font — which would have been heart-breaking, since Ideal Sans was so perfect for this app. So I searched around until I found that there was a little bit of magic: in our NSAttributedStrings, we needed to set NSKernAttributeName to NSNull to get the font-specified kerning. I tried it — and it worked! We were able to ship with Ideal Sans. (Here’s a search in Vesper’s code base for that attribute.) I don’t know if this bit of magic is still needed these days. Hopefully not — because 1) it’s weird to have NSNull have a meaning like this, and 2) NSRTFWriter doesn’t know to expect an NSNull instead of an NSNumber (this should get filed as a Radar). I no longer remember exactly where I ran across that bit of magic. Memory tells me what it was a slide from a James Dempsey talk somewhere, though I can’t seem to find it right now. Anyway. This bug was fixed because years ago I was working with type nerds (and I am one myself), and because of James. Fixing crashing bugs takes a village.[...]


Tue, 03 Oct 2017 13:18:16 -0700

As a young developer I didn’t pay that much attention to accessibility. I figured that most people didn’t need those features, and it was something I could get to later. Plus: adding those features wasn’t easy back in those days.

Things have changed.

For one thing, supporting accessibility features — at least on Macs and iOS — has gotten much easier. It’s almost delightful with how much you get for free and how easy it is to add what’s missing. Apple deserves a huge amount of credit for this.

But there are two bigger things I keep thinking of.

First thing: I want to say that access to computing and communications power is a human right. It’s not, not really — but it would be wrong to deny someone access when, with a little extra work, you could make it work for them.

(Would you be lost without your iPhone? I would be.)

Second thing: accessibility is not just for some small number of people with one specific issue. It’s a diverse set of features and solutions. And everybody — even the youngest and healthiest of us — will eventually rely on some accessibility features if they live long enough.

You may not need it now, in other words, but you will, if you’re lucky. And future-you will be proud of past-you if you cared about it before it was personal.

It’s personal to me now, by the way, at age 49: I use the Dynamic Type feature on my iOS devices to bump up the font size. Though I run into layout bugs from time to time (reported: rdar://34791630), I’m still utterly grateful that the feature exists and that so many developers have adopted it (or done the equivalent in their apps).

Without that feature I’d be an iOS programmer who has a hard time actually using an iPhone. Which would be dumb.