|Special (235): Links | Apple (10): Apple_Developper_Headlines | Apple_Developper_ReferenceLibrary | Apple_Hot_News | Apple_Press_info | Apple_Support_Knowledge_Base_GarageBand | Apple_Support_Knowledge_Base_Mac_OS_X | Apple_Support_Knowledge_Base_iPhoto | Apple_Support_Knowledge_Base_iPod | Apple_Support_Knowledge_Base_iTunes | Mac_Products_Guide_New_Arrivals | Rumors (16): AppleInsider | Apple_x | Chaosmint | CrazyAppleRumorsSite | DifferentDistrict_Rumors | LoopRumors | MacNews_net | MacRumors | MacRumors_p2 | MacScoop | MacosXrumors | Railheaddesign | SpyMac | TheMacMind | TheNorthernSpy | TheUnofficialAppleWeblog | ThinkSecret | iPod (18): Apple_Support_Knowledge_Base_iPod | MacDVD_iPod | Nikkeibp_iPod | iPodBeat | iPodClub | iPodFan | iPodGear | iPodGeneration | iPodHacks | iPodLounge | iPodNN | iPodNoticias | iPod_Fun | iPod_News_de | iPoders | iPodhead | iPoding | pochoirs | Nederlandstalig (11): AppleNieuws_nl | AppleNieuws_be | BluaP | iPhoneclub | iPhoneWereld | InterMactivity | MacFan | MacFan_Forum | MacFreak | MacHouse | MacMinds | MacOSX_nl | MacVandaag | MacWereld | Nieuwslog_Apple | Nieuwslog_iPhone | OneMoreThing | SandS | MacZone | Yooph | Francais (16): Carpo | LeMacEnLigne | Mac4ever | MacADSL | MacBidouille | MacBooster | MacDigit | MacGeneration | MacOS_ws | MacPlus | Mac_Linux | Mac_vnunet | Macmusic_org_FR | Macp2p_net | NyXen | iPodGeneration | Espanol (6): Conexionmac | DiarioX | FaqMac | MacNoticias | NoticiasMac | iPod_Noticias | Portugese (2): Macmagazine_Noticias | Macmagazine_Secrets | Deutsch (11): Apfelgeruechte | Apfeltalk | MacGuardians_de | MacMiniForum | MacMotion_de | MacNews_de | MacTechNews_de | MacWelt | Mac_and_Win_de | iPodFun | iPod_News_de | Danish (3): MacNyt | MacVaerk | MediaMac_dk | Finish (2): MacSanomat | Macmaailma | Swedish (4): MacFeber | MacNytt | MacWorld_se | Se_99mac | Italian (8): AMUG_AV_Italia | BlogMac | Musimac_it | OSXTips | Poc | Spider_mac | Tevac | faqintosh | Greece (2): HelMUG | MacLoaded | Polish (1): Jabluszko | Russian (2): DeepApple | MacOSX_ru | Mactime | MikeOSX | Taiwanese (3): Frostyplace | Maczin | Oikos | Japanese (14): Apple_jp | CubeDeZope | Garageband_jp | Garagers | LifeWithWebObjects | Logicer | MacDVD_iPod | MacFan_net | MacTechLab | Mac_Page_Ne | Nikkeibp_iPod | PowerBooksNews | Sevencolors | iPodClub | Korean (2): Hangul | MUG | News (104): AFP548 | ATPM | AllOSX | AppleAirportWeblog | AppleDefects | AppleLegal | AppleLust | AppleMatters | AppleMenu | Apple_KB | AsTheAppleTurns | Automatorworld | CubeOwner | DailyTunes | DashboardWidgets | Dashboarddev | DifferentDistrict_News | DotMac | EduRSS_Apple | Folkore | Hardmac | InsanelyGreatMac | JoyOfTech | JustOneMoreThing | KeynoteHQ | LockerGnome | LowEndMac | MaCreate | Mac360 | MacCritic | MacDVonline | MacDailyNews | MacDevCenter | MacDigitalAudio | MacEdition | MacFixIt | MacFoo | MacGo | MacHTPC | MacHacks | MacHelp | MacInTouch | MacJams | MacLevel | MacMegaSite | MacMerc | MacMinute | MacMischief | MacNN | MacNet2 | MacNetJournal | MacNewsWorld | MacOSXHints | MacOSXHints_Tiger | MacObserver | MacPolls | MacShrine | MacSlash | MacSofa | MacStudentDev | MacTeens | MacThemes | MacTips | MacVillage | MacWorld_UK | Mac_on_Intel | MacintoshSecurity | Macmusic_org | MacnCell | Macservers | MusiconMac | MyMac | NZMac | NewsTrove | NonStopMac | OReilly | OS9Forever | OSOpinions | OSXFAQ | OSXGuide | OSXHax | OSx86 | PinoyMac | PowerBookCentral | Powerpage | RancheroWeblog | RandomMaccess | Slashdot_Apple | StudioLog | SurfBits | TheAppleCore | TheMacBase | TheMacMind | TheMacOrchard | TheUnofficialAppleWeblog | TidBITS | TigerTracker | World_of_Apple | iCalShare | iCompositions | iOnMac | ifoAppleStore | macCompanion | macTV | xlr8yourmac | news4mac | Macsupport_ca | MacGeekery | Macmini123 | McMACSite | iPhoneAtlas | iwantaniphone | iPhone_Google | |
| Mac News powered by RancheroWeblog |
One Year of The Omni Show
It just popped in my head to check today — and, sure enough, I’ve been doing The Omni Show podcast for just over a year now.
There are a bunch of reasons why I like doing it. The main reason is that it’s fun to show the personalities of the people who work at Omni — and the personality of the company — to the outside world.
It’s also fun as a way for co-workers to get to know each other a little better. We’re showing our personality to ourselves.
I also like it as documentation. This is a special time — our industry is still so young — and so I like it in the same way I liked doing The Record with Chris Parrish. This history will all be lost unless we record it.
And recording this history means not just talking to the usual suspects, the same people you hear every week. It means talking to people who’ve never been on podcasts before, but who all have stories to tell. This is a personal challenge — it takes extra work to prepare for someone different every episode — but it’s so satisfying. I love it.
PS For the curious: last April I wrote, on The Omni Blog, How We Do the Omni Show.
After the firing of Attorney General Jeff Sessions today — not at all unexpected — we’re closer to the break-glass moment where we take to the streets.
It could happen any moment, any day. Could even be minutes from now. Could have happened by the time you read this.
PS The Democrats retaking the House last night was huge. The next two years were going to be perilous and tumultuous either way — but now we have a way better chance of just outcomes.
But we may walk through fire first.
Why I’m Writing These Particular Apps
On the Rainier Slack group, I was asked why I’m writing the app. What are my goals? What’s my exit strategy?
The below is how I replied. It’s unedited Slack-writing, so forgive me for (for one thing) suggesting that at age 65 I might not be writing code anymore. (I very much hope to be.)
Vote for Democrats Everywhere
The president recently called himself a nationalist — and it’s no stretch at all to call him a white nationalist.
From before his campaign, to his remarks after coming down that escalator in Trump Tower, to everything he’s said and done since — including his recent drumming up of fear about refugees planning to seek asylum in the United States — he’s led the effort to ensure that America respects only white power.
This is antithetical to Western democracy, which is built on individual liberty and equal protection, which says that all adult citizens have the right to vote.
If Republicans in Congress had acted as a check on his power, if they had exercised oversight, then I could plausibly suggest voting for the best candidate in each race.
But that didn’t happen. Not even close. It’s been quite the opposite — Republican politicians have aided him at every conscience-shocking turn, and the Republican party has become the party of white nationalism.
I don’t agree with every position of the Democratic Party, and I certainly don’t agree with every position of the candidates available to me. But that’s always true.
What I know, though, is that a Democratic majority in at least one Congressional chamber would finally allow for checks on the president’s power. There would be oversight, at long last.
And we’d have the chance to preserve Western democracy in the United States, and stop this acceleration toward something dark and old and corrupt and dangerous.
Please vote. Please vote for Democrats.
The latest episode of The Omni Show should be of interest to developers — it’s all about building OmniFocus for the Web.
Remember that OmniFocus is a Mac and iOS app written in Objective-C and Swift. The answer for how Omni made it work on the web is the most Omni thing ever. :)
Introduction to Rainier’s Scripting Language
I just posted a tech note for Rainier’s scripting language, Ballard.
Feedback is welcome, of course. Best place is on the Slack group. (You can find my email address near the bottom of this page and then email me to ask for an invitation.)
(Note: other tech notes on the Rainier site are out of date, so I’d skip ’em for now.)
Why Create a Frontier-Inspired Scripting App?
Let me tell you about Frontier.
It still runs (though on its last leg as a 32-bit app), but I’ll talk about in the past tense, because I’m talking about it in its heyday in the ’90s and early 2000s. I was working at UserLand — Dave Winer’s company, which made Frontier — at the time. I was a Frontier enthusiast before I joined the company. It was my dream job.
Frontier began life as a Mac scripting app, before even AppleScript. While it never lost that ability, it turned into a web scripting app around 1995, which is when I first started using it.
In those days — ’90s and early 2000s — Dave Winer invented, collaborated on, popularized, or fleshed-out a number of things we take for granted today: websites created with scripts and templates, weblogs, RSS, RSS readers, podcasting, OPML, and web APIs (XML-RPC).
It was an extraordinary run of creativity. You might just assume that Dave and his team were writing in Perl or Python or similar — but we weren’t. All this work was done in Frontier.
Does the tool matter?
It’s easy to say that the tool doesn’t really matter, that it was all about the people and that particularly fertile time. And it was about that.
But if the tool doesn’t matter, then why do developers care so much about their tools? Tools matter too.
Nothing in my entire career has ever matched Frontier for how it enabled me to make things quickly. Things that are difficult in other environments — persistence, debugging, seeing the results of a script — are so simple in Frontier. It’s just how the app works. It still feels to me like it comes from the future.
The bet I’m making is that there was something special in this design, that this particular tool was capable of unleashing a level of creativity capable of changing the tech world.
What Frontier Was Like
Frontier was a Mac app (yes, there was a Windows port eventually) with an integrated hierarchic database and scripting system.
The key is that it was a Mac app, in the very best sense — it had that old-school Mac philosophy of taking things that were abstruse and difficult and reserved for the priesthood and giving them an easy-to-use GUI. You browse the database and add, edit, and delete values. Everything lives in the database.
Even your scripts live in the database. Open a script in a window, edit it, click Run or Debug, jump to a different script, etc.
Think of the database like a dictionary that could contain dictionaries. We call those tables, but they’re not at all tables in the SQL sense. (Think hash table.) A table can have subtables, and sub-subtables, and so on.
The database holds scripts, outlines, menubars (you can create menus and attach scripts to menu items), styled text, strings, arrays, booleans, numbers of various types, binary data, and more. (Even some things nobody uses anymore, such as QuickDraw rectangles.)
There’s one simple bit of power — it sounds small to say it, but it’s huge: persisting data from a script is as simple as this:
In the code above, there’s a table named
Quit and relaunch the app — it’s still there.
Like dictionaries, tables have no schema. You can put anything you want into any table. And of course scripts have full power to create, edit, and delete tables and not just values (the database is fully scriptable — that’s the point).
Just as you can refer to database values using dot syntax, a script can call another script the exact same way. In fact, you do that all the time, because the standard library is also stored in the database.
If you call
And of course that works with your own scripts too. There are no import statements — you just call, using dot syntax, whatever you want to call.
The debugger has the standard things — step into, continue, etc. — and you can view the stack when you debug. The stack is just more tables! Which you can also edit, while you’re debugging, like any other Frontier tables.
And the debugger works across scripts — you can step into a call to another script and continue debugging. (This is super-common, even.)
Your one-off scripts are typically stored in the
Getting around was super-easy — if you saw
Brilliantly, and I think uniquely, scripts were written in an outliner. Scripts are, after all, tree structures — and using an outliner for code folding and reorganizing has huge advantages. It feels surprisingly natural, too. I know how how weird that must sound to anyone who’s never written code that way. But, really, all other code editors seem sad to me in comparison, like reindeer that can’t fly. The outliner spoiled me.
(Tabs vs. spaces was never an issue, at least!)
In the end
It was just so easy to start something, and then refine it and keep going, and make things that did useful things.
We wrote blogging software and RSS readers and all kinds of early open web things. (It even had a built-in webserver.) It was fun — it was a joy, even.
I think the Mac is missing this app. So my goal with Rainier (which is a mess at the moment) is to do a new, modern Mac app inspired by Frontier. It won’t be compatible with Frontier, and lots of details will be different, but I hope to capture that same lightning, which, I think, we could use right now.
I could be wrong! Worst case is that I’ll just get back the fun that I miss so much. Which is okay. :)
PS Somebody somewhere is thinking that this is like a very weird, not-object-oriented Smalltalk. It is! But that doesn’t make it less awesome.
PPS I’ve left out a ton of details, but I hope I’ve gotten the gist of this across.
PPPS If you’re interested in joining the Slack group and helping me with my thinking, just email me. (You can find my email on this page.)
NetNewsWire Article Age Limits
RSS readers — at least the several where I know how they work — have some limits on how long they keep articles and how long they track read/unread status.
I may not have the details exactly right, but I recall that Google Reader stopped tracking read/unread status for every article older than 30 days. With NewsGator it was two weeks or the most recent 200 articles. Older versions of NetNewsWire had different limits, depending on which version you’re talking about.
There are several good reasons for limits. One is ethical: piling up unread articles forever isn’t fair to people. Your RSS reader should not be a taskmaster or a source of guilt. Articles should age out after a period of time.
Another is that the more data is saved, the slower database lookups tend to get, and the slower the app gets. In the case of a Mac or iOS app, this also means using more disk space and more energy (more battery).
A third is that if an RSS reader sets the expectation that it creates a personal backup of the internet, then the developer will be doing features, bug fixes, and performance optimizations for this forever, to the detriment of the rest of the app and the majority of its users. (I went through this with earlier versions of NetNewsWire.)
Limits are a necessity. The hard part is deciding what the limits should be, and figuring out how to make them understandable to users.
NetNewsWire will sync with various systems (Feedbin and similar), and, for each syncing account, it will just adopt the limits of each system.
But that still leaves one case where the limits need to be worked out: the non-synced On My Mac account. The below is my thinking (after much discussion with other people) on this.
Articles older than n days will be deleted automatically — but it will preserve a minimum of the 10 most recent articles per feed, and it won’t delete starred items.
(Where n is something like 90 days.)
This is slightly more complex than just aging out older articles. It makes sure that feeds that haven’t been updated in a long time still have their most recent 10 articles.
I think this is reasonable because you don’t want to click on a feed and see zero articles just because it hasn’t been updated in six months (or whatever).
But there’s a tricky part here: how do we define the age of an article? Seems like it should be obvious, but it’s not.
Publication Date vs. Arrival Date
Every article has three dates, though two of them may be empty.
Most of the time, arrival date and publication date will be pretty close. Not always, though — not, for instance, when adding a feed. When it reads a feed for the first time, the arrival date is that moment for each item, while the publication date could be anything.
You might think, naturally, that NetNewsWire should use arrival date when deciding whether or not to delete an article. If it arrived more than n days ago, then it should be deleted, because that means the user has had it for more than n days.
But there’s a problem with that: arrival date is never shown in the user interface. It’s not otherwise an interesting piece of information, where publication date is interesting to users.
So if we have a time-based limit that’s triggered by unseen metadata (arrival date) — and there is visible metadata (publication date) of the exact same type and that seems like it’s directly relevant to age — then I think we have to use the visible date, the publication date.
This makes the limit understandable: you can see the dates, after all, that it uses for its calculation.
(Note: when publication date isn’t specified in the feed, then NetNewsWire uses the arrival date as the publication date, since it will usually be pretty close. Luckily, feeds do tend to include publication dates.)
The one drawback to using publication date, though: it could delete an article with a recent arrival date but a long-ago publication date. I think this is okay — I think it’s the best of the available trade-offs.
The Other Tricky Part: Communicating with the User
The app shouldn’t behave mysteriously. How this works should be clearly communicated.
One option is to just to write about it in the Help book. Unfortunately, people don’t read these all that much.
So here’s what I’m thinking:
Since there will be a preference pane where you can add and edit your various sync accounts (much like in Mail), we have a place for settings for the On My Mac account.
In those settings would be something like this:
Though I most definitely like to limit preferences, this is a reasonable thing to want to configure — and having this there makes it much more likely that a user will see it and learn about the limit.
I think that’s the best call, though it’s not set in stone yet.
Reminder: None of This Applies to Syncing
After reading all these words, you might have forgetten that I’m just talking about the limits of the On My Mac account. Different syncing systems have their own limits, and NetNewsWire will adopt those for the synced accounts.
If you go to the repo you can find my email address and find the bug tracker. You can always email me to ask to be added to the Slack group. But — fair warning! — a lot of the discussion is over super-dry stuff like this issue.
The Design of NetNewsWire’s Timeline
I had some principles in mind for the timeline:
The last one of those — super-fast scrolling — is important. (High performance is a principle of the app in general.)
Luckily, I’ve written so many timelines over the years that I know how to make them fast. Even on my five-year-old MacBook Air — where I spend about 20% of my coding time — scrolling in the app is as fast as it could be.
So let’s set that aside.
The first one of these — “it should be appealing” — is also super-important. But, as a principle, it’s too general, and the answer is subjective.
So that leaves me with two things to think about: including graphics to cut down on the wall of text, and making it easily scannable. If I do a good job designing those two things, then hopefully the result is just naturally appealing — on the grounds that something well-designed for scannability and legibility tends to be appealing.
(Before I go any further: if you want to go get the app — it’s free and open source — you can.)
What Scannability Means
A timeline cell should have enough info that you can quickly figure out, when you glance at it, what it’s likely to be about, where it comes from, and how old it is.
It should be large enough to be able to include that much context, but not so large that you find you have to scroll constantly (even though scrolling is fast).
It should include the title — hopefully the entire title — and perhaps some of the text, for further context. It should include the feed name so you know where it comes from.
Each cell should be the same height as other cells, since this also helps scannability. (I tried a variable-height table early in the development process, and found that a regular height was better.)
After trying a bunch of different layouts — my design process often requires me to actually code a thing and try it (for better or worse) — I settled on the following layout:
The title is bold and dark, since it should stand out the most. The first line of body text, when displayed, is lighter in color and is regular text.
In the case of a title-less article, the layout is this:
For title-less articles, the article text weight is in between the title and body text. Not as bold as the title, not as light as article text. This tells you, at a glance, that you’re reading the first line of an article and not an actual title.
The date and feed name are set in smaller type. The date is bold, which sets it apart from the article title/text above it and the feed name below it.
All text is ellipsized when needed, which lets you know when you’re not seeing the whole thing.
I decided against horizontal grid lines in favor of vertical spacing. This means less visual noise in an area of the app that could easily be too noisy. And, well, it’s a news reader, not a spreadsheet, and using spacing instead of gridlines seemed more publication-like.
This all might seem obvious. I hope so! Of course it wasn’t obvious — but I like it if it seems that way.
I knew I wanted graphics too, in part because they brighten up the UI and keep it from being too text-heavy (and thus hard to scan).
But graphics can serve another purpose: they can quickly tell you something about the article, which helps with scannability.
In NetNewsWire Lite 4.0 I added graphics to the timeline, so this wasn’t a new idea for me. For each article, it looked at the HTML text and found the first image, and assumed it was a featured image. It downloaded those images and made thumbnails to show in the timeline.
This looked pretty cool, brightened up the UI, and cut down on wall-of-text. But it had one major drawback: sometimes the results were a bit risible. Because it was making square thumbnails, it had to crop — which meant sometimes you’d get a nose but no eyes.
And sometimes in trying to find the featured image it would just be a social media sharing icon. Or an image of an emoji. Or a blank tracking image. There was no set of rules that was going to make this work correctly all the time.
And then of course there are plenty of feeds that rarely use images at all. This blog, for instance, or Daring Fireball.
In practice I found that those images — while attractive when they worked — didn’t add that much to scannability (except in the case of photo feeds, which are a minority of feeds, surely).
So, for NetNewsWire 5, I decided to go with feed icons. These are like big favicons, basically, and they serve the purpose of providing a super-fast visual indication of which feed an article comes from.
(Finding these is a bit of a chore. There’s a property for this in JSON Feed, but there are plenty of RSS and Atom feeds out there. So, for those, it downloads the HTML for the home page and attempts to find the feed icon by looking at various metadata properties: the apple touch icon, for instance. I’ll write more about the technical side another day.)
Initially I put them on the left side and moved the text to the right. I was thinking of Twitter and chat and similar apps, where the avatar goes on the left.
The problem there, though, was that not every feed has one of these. So I could either leave the left side blank for those feeds, or move the text all the way to the left — but that made it so sometimes the text was indented (when there’s a graphic) and sometimes not, which looked weird.
So I put them on the right — to my surprise, because I never pictured them there — and it works just fine.
The above all works great for the Today, All Unread, and Starred pseudo-feeds. It works great when a folder is selected, or when multiple feeds are selected.
But when you have a single feed selected, it looked weird to have the feed name and the feed icon repeated a whole bunch of times.
So, in that case, the layout removes the feed icon and the feed name. The row height becomes correspondingly shorter.
It does mean the timeline is a bit more wall-of-text in this case — but it’s also a quick reminder that the selection is a single feed. I think it’s fine — though I could imagine revisiting this.
I could also revisit the idea of using thumbnails of images from article text. There are problems to solve with that, of course.
One idea would be to put a larger, non-cropped version of the image below the rest of the cell — as you see in Twitter and various unfurls. This would bring back variable-height cells, but that’s not necessarily the worst thing. (People deal with variable heights just fine in social media apps.)
Another idea for the timeline — one I’m pretty keen on — is to render microblog posts in full in the timeline. (Microblog in the generic sense, not just posts from Micro.blog.) These would have to include clickable links and basic HTML formatting.
The thing is, I don’t want to just use a web view. To make this work well would mean writing a small HTML layout engine that handles the basics (bold, italics, links, blockquotes, images). While this sounds like a fun challenge, it’s also probably not a one-day project. It would take some time. And right now I’ve got enough other things — syncing, especially — to do, so I’ve put off thinking about this until after 5.0 ships.
Another thing put off until after 5.0 ships: an alternate high-density timeline. I’ve heard from a number of people that they really prefer one-line cells with multiple columns: title, date, feed name. For them this is the most scannable UI, and they liked this exact feature in years-ago versions of NetNewsWire. So it’s something to consider — but, again, I’m not thinking about it till after 5.0 ships.
Though I don’t run in Dark Mode normally — even though it’s beautiful — sometimes I switch to it just to look at NetNewsWire. :)
NetNewsWire Diary #2: Switching to OPML
Since the earliest days of NetNewsWire, before 1.0 even shipped, I wanted to make the subscriptions list on disk an OPML file.
It seemed like using the standard format for listing RSS subscriptions would be a good idea. But I was never able to make that happen — until now, with NetNewsWire 5.0d7.
Why It’s a Good Idea
Given that OPML import and export is a must-have feature — which NetNewsWire already has — then storing the subscriptions on disk as OPML means less code, because there’s just one format to support, instead of supporting both OPML and a custom format for just the app.
It means that the OPML reading and writing code will run for every user on every session, which means any bugs in OPML support won’t be able to hide.
It means a user can get their subscriptions list and move it to another system without first having to launch the app and do an export — the OPML file is already there on disk already.
It also means a user could replace their subscriptions list on disk by swapping in a different OPML file, without having to figure out how to do it through the app.
Why I Never Did This Before
The problem, though, is that the standard OPML format for listing RSS feeds doesn’t have slots for additional metadata. I want to store things like Conditional GET information, the hash of the contents from the last fetch, the edited name as well as the feed’s declared name, and so on.
So for all these years I thought, “Well, that’s too bad. I wish I could use OPML, but I can’t.”
Why I Could Do It Now
It occurred to me I could use a “side table” — that is, a separate place to store feed metadata. This would allow me to store whatever additional data I wanted to store in a separate location.
The go-to for this would normally be SQLite, with some kind of table for feed metadata.
But this has another problem: SQLite is structured storage. There’s a schema. But this doesn’t quite suit feed metadata — especially not when you add in syncing. I wanted the ability to store attributes for each feed without knowing, in advance, what all those attributes might be.
Enter Rainier, the inspired-by-UserLand-Frontier app I’m working on. It includes an object database — that is, it includes a hierarchical, schema-less, key-value database. It’s like a dictionary that can contain nested dictionaries.
Which is perfect for what I wanted to do: I could make each feed a table in an ODB database, and then each feed can store arbitrary key-value pairs. (Think of a “table” in an ODB database as really a dictionary.)
So I built this ODB storage — perhaps ironically, it’s built on top of SQLite, but why not? SQLite is amazing — and its first use is in NetNewsWire.
Rainier-the-app isn’t far enough along to actually do anything at all yet. But a key component of it is now part of NetNewsWire. I expect this pattern to get repeated for a few more things, too — including the (not-nearly-finished) scripting language.
NetNewsWire 5.0d7 is up! See the blog for change notes.
Unofficial Seattle Xcoders tonight — at 6:30 pm at the Cyclops in Belltown. I’ll be there!
There might be some other Omni folks there too unofficially celebrating recent releases. :)
All are welcome! You don’t have to be a coder. Find us in back, on the restaurant side.
I’m 50. I vote every single time, no matter what. Midterms. Primaries. Caucuses. I even vote in that weird non-binding primary that Washington State has.
The latest episode of The Omni Show is ostensibly about launch day — but mostly it’s a discussion of the new design in OmniFocus 3 for Mac. How it started, how it evolved, how it ended up.
It’s of obvious interest to OmniFocus users, but I think the discussion is also interesting to anybody who cares about app design.
(I think it’s one of the best episodes, by far.)
There are just 15 seats left for Swift by Northwest. I’ll be there!
It’s in Portland this October, and it’s going to be fun and educational and you will make new friends. :)
My friend Geoffrey — the one with the big beard in the pictures in the linked-to page — is opening Fair Isle Brewing in Seattle, in Ballard (my neighborhood), next year. They’re doing farmhouse and wild beer.
You can invest as little as $100 if this interests you. More about farmhouse beer:
I think it’s going to be a success — but that’s because I know Geoffrey. We’re talking about investing money here, so please make up your own mind!
When Blogger came out, we all got on Blogger. When Flickr came out, we all got on Flickr. Later there was Twitter and Facebook, and we all got on.
(Okay. Not every single person, but you get my drift.)
In those days, for a thing to be important, for it to be a success, it had to get the attention of much of the internet.
It was a lot like TV used to be. There were just a few networks, and for a show to be a hit it had to have some significant percentage of viewers watching it.
Times have changed, and the internet is more mature and diverse. As my friend Kelly Guimont says, the internet is “sort of like TV” these days, and “you can have a successful show and not have half of America watching.”
Like Game of Thrones. It doesn’t have half of America watching it, but it’s still a success.
I argue that the same is true of apps and app categories: we’ve (finally!) entered a period of tech diversity, and Mastodon and Micro.blog and RSS readers and blogging systems and so on do not have to capture the attention of the entire internet to be successful and important.
In fact, those days are gone. TV changed, and so did the internet.
Oh God Not This Again
Every now and again there’s a thing about the tragedy of RSS. Ugh.
I want to make a few points.
One is that, as Greg Reinacker once said, RSS is plumbing.
Another is that millions of mainstream users rely on it — for podcasting, especially, but also because it powers other things that they use. They don’t know that there’s RSS under the hood, and that’s totally fine.
Another is that it’s not necessary for RSS readers to become mass-market, mainstream apps. I’m sure I never said they would be, and I don’t remember anyone else from the early days of RSS saying they would be, either.
It’s totally fine if RSS readers are just used by journalists, bloggers, researchers, and people who like to read. Yes! It’s a-okay.
But note that everyone who uses Twitter and whatever else, and who follows those people, are benefiting indirectly from RSS. RSS is, often, where the links come from in the first place before they show up on social networks.
In a nutshell: judging RSS itself because RSS readers are not mainstream is to miss everything that RSS does. And judging RSS readers for not being mainstream is to judge them against expectations set by some hype artists more than a decade ago — but not by me or anybody else actually doing the work.
I don’t expect to see RSS readers running on every Mac and iOS device. This does not make it a failure.
It’s 2018, and I think by now we’re allowed to have things that some people like, but that not everybody uses.
* * *
From 2011: What we talk about when we talk about RSS
From 2013: Why I love RSS and You Do Too
From 2018: Some Hope
Dana Blankenhorn, No More Mr. Nice Liberal:
I like that Feedbin is private by default.
NetNewsWire 5.0d6 adds Mojave dark mode support.
Why NetNewsWire 5 Doesn’t Support Nested Folders
I was asked on the NetNewsWire Slack group about supporting nested folders — folders inside other folders — and I realized the answer deserves a blog post, because it brings up some larger issues.
But first, some technical stuff.
RSS readers have moved over the years toward tagging as opposed to folders.
A structure where feeds can have multiple tags is the same thing as a structure where you have multiple folders but not nested folders, and a feed can appear in more than one folder.
So that’s what NetNewsWire does, because this looks like a de facto standard to me.
That’s part of the reason, but there’s more…
In earlier versions of NetNewsWire there were too many features that added to the fiddliness of the app.
Those features were invitations to the user to comb and revise their system. They could customize colors and fonts, create deep folder structures, archive articles on disk, and so on.
Over the years I’ve learned that these kinds of things often detract from an app. Every decision is a moment of anxiety for the user. The user wonders: is this the right call? Did I consider all the issues? Can I change it later?
And the user may be motivated to come back and re-do those decisions.
I don’t want my software to do that to you.
Furthermore: simplicity is itself appealing. Delight comes in getting the most power from the smallest effort.
Adding features may make the app more appealing to people who want those specific features — but it chips away at simplicity as a feature, and some people will go look for something less complicated.
To be clear, though, this approach isn’t right for every app. It depends on what you want the app to be. I like Acorn for its relative simplicity over Photoshop, for instance — but Photoshop absolutely needs to be what it is for people like Brad Ellis to get their work done.
I have the luxury of not needing to make money from this, and I also have the luxury of knowing there are other really good RSS readers. I’m not required to make this particular app the RSS reader for every single person.
Our industry has not only been poor ethically, it’s also been substandard at just plain old quality. Sure, the economics of it are partly to blame. It motivates people to sell out their users and to ship broken software.
“Move fast and break things” is a motto that seems to apply to the industry at large. I think it’s wrong, because there’s a human cost to this.
Again — because I have the luxury, because I don’t have deadlines or commercial concerns — I can do something different: I can ship software with no bugs. Zero.
I’ll be more precise: if a bug is any ticket in the issue tracker, then of course there are always bugs. I’m talking about known, reproducible defects.
My plan is to never release a shipping version that has any such defects. I believe that’s a feature in itself.
But that’s much more easily done with a simpler app. Every added feature adds to the combinatorial complexity of the app, and the app becomes harder to test and harder to get right.
My commitment to zero defects outweighs my commitment to adding features.
And I do want to add features. There are some features I haven’t seen in other RSS readers — even earlier versions of NetNewsWire — that I want to do.
I think (I hope) they’ll be fun and useful and that you’ll like them. (We’ll see, of course!)
But when I spend time adding some features from an older version of NetNewsWire, I’m not doing the new features that this new world NetNewsWire wants.
You might end up disappointed, when NetNewsWire 5.0 ships, that some feature you used in an earlier version of NetNewsWire isn’t there. I totally understand that.
But my pitch is this — or will be (it’s not shipping yet): try an app with zero known defects, where performance is critical, where careful, considered design and simplicity are valued, where there is room for future innovation, where development happens in the open, and see if you like it despite the missing things you wish it had.
You might find you do! And you might not, which is okay — as I mentioned earlier, there are other really good RSS readers, which is a great thing.
PS You can join the Slack group too — just send me email.
PPS I could change my mind in the future about nested folders. Very few decisions are set in stone. But the above is all the things on my mind as I make decisions about things like this.
On the NetNewsWire blog I’ve been publishing bits of NetNewsWire history. It’s a look at the history of our industry through the eyes of one single 16-year-old app.
Though I have my own blogging software, for the NetNewsWire blog I decided to go with Micro.blog and my own domain (nnw.ranchero.com). It’s easier to use than my own software — especially when it comes to adding pictures, and I definitely want to use a lot of screenshots on this blog.
I set it up to automatically cross-post to @NetNewsWire on Twitter. I don’t love Twitter, obviously, but I feel it’s important, when you have a product, even a free one, to be accessible wherever the users are.
Daniel Jalkut, Saying Goodbye to NetNewsWire 3:
Decision: Not Publishing NetNewsWire 3.x
The last build of the full version of NetNewsWire, before the sale to Black Pixel, was 3.3.2. I’ve learned that lots of people still use it!
I was considering publishing the source on GitHub and/or making a 3.4 build that strips out the Esellerate and Google Reader syncing parts.
So I sent the code to Daniel Jalkut, who quickly hacked at it and got it running and sent it back to me.
And then I ran it too — and quickly realized a few things:
I might still make a build of NetNewsWire Lite 4.0 available. That code base is not just newer than 3.3.2, it’s just plain way better.
(It was the start of my never-completed NetNewsWire 4 rewrite. NetNewsWire Lite 4, when it shipped, had zero known bugs, and just one known bug within a couple weeks. It was a good app. With modern tools I bet I could find more bugs pretty easily, though.)
But it’s still not nearly as good as the code I’m working on now. (Which should be no surprise — it’s years later, and I’m a better developer.)
Medium is deprecating custom domains. Owning your own content means the ability to use your own domain, so you’re not locked in to a specific service.
NetNewsWire Diary #1: Automatic Hashing and Performance
I like Swift’s recent addition of automatic hashing support — in many cases you can declare conformance to
This let me delete a bunch of code, and I love deleting code.
* * *
I noticed a regression the other day: for some reason, fetching articles from the database and populating the timeline view got noticeably slower when the results are fairly large.
I worried that this is because my articles database is over a year old, and as it grows the fetch times get longer.
And of course fetching articles means creating a whole bunch of these structs. Hundreds or thousands, even, depending.
Those were two cases where I had adopted automatic hashing. The
So I thought about what to do. I wanted a hash that’s unique, or close enough, and I want it to be fast.
The solution, in both of these cases, was obvious — each has an
So I made
I built and ran the app — and the performance issue was fixed.
I put some (temporary) timing code around the code that fetches all unread articles, and it went from 0.37 with automatic hashing to 0.07 with my computed
I realize I could have written a
The point still stands, though, that automatic hashing in the case of objects with lots of properties might be a performance hit. As always — use the profiler.
PS Hashing is important in NetNewsWire because I use sets frequently. In general I make arrays at the UI level, when populating a timeline (for instance), and use sets when fetching from the database, etc.
How To Add Your Micro.blog Feed to NetNewsWire
Figure out the URL. It’s something like this, where my username is replaced with your username:
In NetNewsWire, hit cmd-N. (Or click the + button in the toolbar.) Put that URL in the URL field in the sheet that appears. Give it a name if you want, and choose a folder if you want. Then click the Add button.
Posting to Micro.blog
If you have the Micro.blog app on your Mac, you can select an article in NetNewsWire, then pull down the share menu in the toolbar, and choose Micro.blog.
It will send that article to the Micro.blog app, where you can edit and comment before posting.
The same thing works for MarsEdit, so you can post to any blog.
New World NetNewsWire
So much has changed since I last worked on NetNewsWire, and my thinking about it has changed too.
The big things remain the same — NetNewsWire is at the intersection of my passions: reading and writing, the open web, and Mac apps. I want to make NetNewsWire a great app with lots of users. No change there.
But so much else has changed.
In 2002, when I started NetNewsWire, there was no Facebook and no Twitter, no iPhones, and most people hadn’t heard of RSS. People got their news by visiting a few sites a few times a day. People subscribed to email newsletters. That was about it.
Since those days a whole bunch of RSS readers — most notably Google Reader — have come and gone. But, interestingly, there are probably more web-based readers these days than ever before.
But most people, it seems, get much of their news from Twitter and Facebook these days, and I believe this is unhealthy for society and for individuals. None of that existed in the early days of NetNewsWire.
Another change: the energy in app-making has moved from Mac to iOS. But I still love Mac apps, and I still believe in them as works of art that people use to get their work done.
Another change is a personal change: I don’t need to make money from NetNewsWire. While I always wanted to make NetNewsWire the best app it could be, I used to have to consider money as I made decisions. I no longer have to.
* * *
My goal used to be to make NetNewsWire a great Mac app with lots of paying users. Secondary goals were to promote reading and writing on the web, the blogosphere, and RSS and open web standards.
My goal now is to make NetNewsWire a great Mac app with lots of users. Other, no-less-important, goals are to:
(Yes, I’m strongly considering an iOS version, but I’m concentrating on the Mac app first.)
* * *
Let’s go back to how people get their news these days.
NetNewsWire will never be the sole news-gatherer for anybody. People use social networks. They still visit sites manually and subscribe to email newsletters. They use apps like Apple’s News app. They get news from Slack and other group and personal chat apps.
And they use other RSS readers too.
This means that NetNewsWire does not have to be designed as if it’s anybody’s only source of news. And it doesn’t have to be designed to please the maximum number of people.
My thinking, instead, is to make it fit into an ecosystem: it’s just one of a number of sources, and not even the only RSS reader.
This allows me to design more carefully. NetNewsWire used to be quite over-featured, and now I have the luxury of being able to make a leaner NetNewsWire.
I can say no to things that I would have said yes to — I can make it the app I want it to be, an app that hopefully lots of people love using, but that isn’t trying overly hard to be everybody’s friend.
It’s okay, in other words, to remember that there are other RSS readers, and it’s totally a-okay when somebody likes another one more.
In other words, NetNewsWire of the future will be more me than any previous versions were.
PS Here’s a secret: my favorite version of NetNewsWire was always NetNewsWire Lite, which was the pared-down, free version. I keep thinking that I’m designing in the spirit of NetNewsWire Lite.
If you’d like to run it, go to the NetNewsWire site and download the latest build.
Things to know:
If you’re upgrading from Evergreen, you can either:
Note: I’ve started a Slack group, but I don’t have a public signup form for it yet. You can email me to ask for an invitation. Just let me know if I should use an email address other than the one you used to email me. (You can find my email address at the bottom of the NetNewsWire site.)
You don’t have to be on the Slack to help. You can always contact me by whatever means, and you can post to the Issues tracker on GitHub.
Historical code: NetNewsWire Lite 4.0
NetNewsWire Lite 4.0 was the last version I shipped before the sale to Black Pixel, back in 2011. It was a free app on the Mac App Store.
I put the source up on GitHub.
I’m not publishing it as some kind of example app — some code is good, some is bad, and most is middlin’, and it’s all old. It’s published for historical reasons only.
However — if we can get it building, and I bet we can — I’ll end up making it available as a download.
I don’t know what to do about NetNewsWire 3.3.2, which was the last release of the non-Lite full version. That code is really, really old and I don’t even really want to publish it. But I might. Or I might get it building and release a 3.4 version of it.
We’ll see! No need to rush, of course.