inessential by Brent Simmons

April 2020

Me and Newark, NJ

We’ve been enjoying the HBO series “The Plot Against America.” I’m a long-time fan of Philip Roth books, though I haven’t read this one yet.

The action, at least in the first few episodes, takes place in the Weequahic neighborhood in Newark, NJ.

I recalled that my father’s mother is from that same neighborhood.

So I was doing a little research on my family connection last night, and I ran across the wedding announcement of my great-grandfather and great-grandmother, and I found it fascinating.

Here’s the headline:

Harry W. Crawford Weds Miss Marie Bertha Keer. Wedding held at the Church of the Holy Apostles, followed by a Reception at Inlet Terrace Club — will reside in Newardk after wedding trip.

Here’s the PDF — it’s from The Coast Advertiser on September 16, 1921.

The story has a lot of detail:

…she wore a gown of white satin trimmed with rose point lace. A court train of satin trimmed with tulle and orange blossoms fell from the shoulders and her veil of rose point lace was arranged in cap effect and caught on each side with orange blossoms. She carried a shower bouquet of white roses and lilies of the valley.

(It goes on.)

The story also omits a bunch of details — where did they go on their honeymoon?

To tie this back to Philip Roth: I used Maps to find out how far their house was from Philip Roth’s childhood house, presumably the location for “The Plot Against America” — just under a mile.

* * *

I knew my great-grandmother, who we called Ohma. I didn’t know my great-grandfather.

Ohma succumbed to Alzheimer’s disease eventually. But, before then, when I was quite young, she used to tell me the story of Peter Cottontail — who was me, she said, since my first name is Peter. (It is.)

For many years I’ve had a picture of her father, Ernest Keer — my great-great-grandfather — on the wall in my office. In the picture he’s doing what I do — sitting in his office at a desk, doing some reading. He was a lawyer in Newark. The picture is from April 1912.

NetNewsWire Code Layout

I don’t claim that this is a beautiful diagram, and it might scale weirdly, but it does show how NetNewsWire is layered.

When writing an iOS or Mac app — or an app that’s both, as in this case — I like to 1) break up the app into separate components, and 2) make those components depend on each other as little as possible, and 3) when there are dependencies, make them clear and sensible.

Submodules

Starting at the bottom level are the submodules: RSCore, RSDatabase, RSParser, RSTree, and RSWeb. These are built as frameworks: RSCore.framework and so on.

Each of these is in a standalone repo and is useful on its own. They don’t even depend on each other — they don’t depend on RSCore, for instance, though you might have expected that they do.

The lack of dependencies promotes reuse — not just by me, among my projects, but by other people too.

It also makes these easier to work on. I don’t have to worry that a change in one affects another one. I don’t have to pull the latest RSCore before working on RSDatabase, for instance.

In NetNewsWire we treat these as Git submodules. It would be great to switch to Swift Package Manager, but I’m not sure if that has all the features we need yet. (Maybe it does. If so, then great, but there’s no rush.)

In-app Frameworks

We continue our bias, inside the app itself, toward using actual frameworks.

The bottom layer is Articles.framework, which is the data model for articles, article status, authors, and so on. Articles depends on nothing else in the app.

ArticlesDatabase.framework and SyncDatabase.framework depend on Articles. ArticlesDatabase stores actual articles data; SyncDatabase stores data used to implement syncing.

The last in-app framework is Account.framework, and it depends on everything below it. An Account is what you think it is: it’s an On My Mac (or iPhone or iPad) account or it’s an account that connects to a syncing system (such as Feedbin or Feedly). It’s at the top of the data storage — to fetch articles for the timeline, for instance, the code asks an Account.

All of these in-app frameworks — like everything in the actual app — may depend on the submodules.

Shared Code

Here live a number of controllers that do various things like OPML import and export, downloading feed icons and favicons, rendering articles, handling user commands and undo (such as mark-all-read).

Some could be broken out into yet more in-app frameworks. (We would be more vigilant about that if we felt, at this point, that we’re losing the battle against app complexity. I’m glad to say we’re not in that position.)

UI Code

NetNewsWire is a Mac and iOS app. It’s built on AppKit on Macs and UIKit on iOS (as opposed to using Catalyst, which would have let us use UIKit for both).

As the diagram shows, there’s a lot of code shared between the platforms, but that stops at the UI code. The UI level is the top level, and it depends on everything below it.

Why use actual frameworks?

The benefits of components and being careful with dependencies are clear — but why use actual frameworks? After all, a conceptual module doesn’t have to translate to an actual separate library target.

I’ve found that it’s easier, when using a framework, to ensure for a fact that you don’t let an unwanted dependency to slip in. It’s kind of like treat-warnings-as-errors — it makes sure you’re not getting sloppy with dependencies.

Other reasons: when I’m working on a framework, I find it easier to just concentrate on exactly what I’m doing there and let the rest of the app slip from my mind temporarily. And, finally, we’re more likely to write tests for frameworks.

It may just be psychology, but it’s important anyway: smaller, self-contained (or mostly so) things are just easier to treat well.

After Two Months of Quarantine

I went outside yesterday to bring my emptied garbage and yard waste cans back from the street.

It was a pretty nice day — not really sunny but warm enough. Lots of people were outside. The woman on the corner was talking to somebody on the sidewalk. My neighbors were out. There was a bicyclist on the street, some folks walking on my side of the street, some folks walking on the other side of the street. The guy who lives behind me was outside and playing music.

Way too many people. It felt oppressive. I beelined it back inside after taking off my gloves.

A Coding Challenge Can’t Show How I Solve A Problem

Some number of people, on Twitter and elsewhere, have told me that it’s not about getting the right answer — it’s about showing the interviewer how you go about solving problems.

I’ve read a bunch of the advice on this, and the advice says things like: “Start talking. Restate the problem. Talk out an approach. Consider how much space/time it will use. And then start writing code.”

Which is of course not at all how I solve problems. I usually start with some hazy intuitive approach and start writing code. I code and think at the same time. I revise what I wrote, or even delete it. Then I go for lunch.

I come back to it, and if I’m still stuck I look in the documentation. Or Apple’s dev forums or Stack Overflow or Wikipedia. I might ask someone on my team or I might ask some friends on a Slack group. Or maybe I figure out an approach on my own after all, and then just do web searches to validate the approach.

And — this is critical — as I’m doing all of this I’m using the IDE I always use, with autocorrect, profiler, debugger, etc. All my tools. Where I’m used to the text editor and its syntax coloring and how it balances braces. Where hitting cmd-S — as I habitually do — doesn’t result in my browser prompting me to save the current page.

And — even more critical — I don’t have a 45-minute time constraint. Nobody is watching me type and judging. I’m writing code to solve a problem, rather than writing code to get a job.

There’s a huge difference between “solve this performance problem with a binary search” and “pass this test so you can feed your family.”

* * *

There’s a whole small industry to help people prepare for these tests — so it’s not like you’re getting the authentic programmer showing up. You’re getting the person who’s prepared for one of these.

Because of that, an interviewer is even less likely to learn how a candidate approaches solving a problem. Instead, they’ll learn how well the candidate prepared to make a good impression — which tells you nothing about how they’d actually solve a problem.

I think these end up favoring people with more time to prepare. It probably helps if college isn’t a decades-old memory — the closer you are to taking tests in school, the more comfortable you’ll be, and the less you’ll feel like this is an absurd exercise with no meaning.

Practicing the Coding Challenges

As part of my job hunt I’ve been doing some problems on LeetCode to prepare for coding challenges.

I don’t have a CS degree, but I have decades of experience — I know what a linked list is, for instance, and could write one by hand easily if called to. In a few different languages, even. I could talk about the trade-offs between a linked list and a contiguous array. Etc. I’ve got all that.

But these tests are kicking my butt a little bit. I think I’ve figured out why.

Consider a question like this:

You need to add two numbers and get a sum. But, importantly, the digits of those numbers are stored in arrays, and they’re backwards.

The return value also needs to be in a backwards array.

If inputs are [4,2,6] and [3,8,0,8], the function should return [7,0,7,8] — because 624 + 8083 == 8707.

My style of coding is to break problems into steps and make it super-obvious to other people — and future-me — what the code is doing. I like to write code so clear that comments aren’t needed.

I’d start with a top-level function something like this:

let num1 = number(from: array1)
let num2 = number(from: array2)
let sum = num1 + num2
return array(from: sum)

That’s clear, right? There are two functions referenced in the above code that are clearly transformers — one goes from an array to a number, and the other goes from a number to an array.

So the next steps are to fill those in, along with any additional helper functions.

If I were on the other side of the table, and this is what the candidate did, I would be quite happy — because they’ve achieved not just correctness but clarity. They’ve solved the problem using a coding style that I’d want to see in production code.

But that’s not what these questions want to see at all.

What the Questions Actually Want

What they want — at least in the experience I’ve had so far — is for you to have some kind of insight into the problem that allows you to solve it in a more efficient way.

You may have already figured it out for this particular question: but, just in case not, here’s the tip — the answer should mirror the way we actually do sums on paper.

Remember that we go right-to-left, and we build up the answer digit-by-digit.

   624
+ 8083
------
  8707

The arrays are already backward, even! So just write a loop that does exactly what you do when doing this by hand (including the carry-the-one part). You create the answer — the [7,0,7,8] — as you go along.

I’m Not Sure What to Think About This

In production code, if a problem like this came up, I’d ask “How the hell did we get here?” and try to backtrack and figure out what insanity caused this, because it’s just not right.

But, if this code were truly needed, I’d write code the way I normally would, with clarity in mind first.

And then, if my tools told me it was too inefficient with time or space, I’d figure out a more efficient version.

These questions, then, are able to test what you might come up with when you’re in that position.

The thing is, what I would most want to know is how people write code for the 99% of time when they’re not in that position. That’s not being tested here.

Proposal: instead of calling these video things we do “happy hour” or “virtual happy hour,” let’s just call them “video hour.”

Here’s why: it might be the morning for some people on the video; not everybody drinks alcohol; it’s a new thing, not a replacement for an old thing.

NetNewsWire Status: April 2020

It was only few months ago I wrote up a NetNewsWire 2020 roadmap — and that roadmap is already wrong!

Not a surprise. That’s apps for ya.

But also: remember that NetNewsWire is made by a group of volunteers, and we all live in the same world everybody else lives in. I even lost my job, and I’m spending much of my time looking for a new job. (Had I not been laid-off, NetNewsWire 5.0.1 for iOS would probably have shipped already.)

Here’s what — we think — is coming up next. Probably in this order, even!

NetNewsWire 5.0.1 for iOS

This release will include a bunch of bug fixes and improvements. We’re down to the last few bugs right now. I expect this to be on the App Store within a few weeks.

NetNewsWire 5.0.4 for Mac

This release is also a bug-fixes-and-improvements release. No new features.

NetNewsWire 5.1 for Mac

This release will add Feedly syncing, a Reader view, and other features that the iOS version already has. It might be sandboxed and might also be on the MAS. (Not totally sure yet.) Should include support for at least one other sync system.

NetNewsWire 5.1 for iOS

Support for additional sync systems. Other things. (Hard to say at this distance.)

* * *

When will anything actually ship? There are No ETAs. And everything in the above schedule could change!

Day 36: Radioactive but Uninteresting

We haven’t been going anywhere. We’re getting our groceries and things delivered.

I’m going for jogs — but only after 8 pm, once it’s dark, once the sidewalks are clear enough. My neighborhood has a surprising amount of walkers. Normally I love that, but right now I just wish it would rain like hell and keep them all home.

Instead it’s sunny, so I wait till nighttime when everyone’s inside on their various devices.

All My Stuff in a Box

Today was the first time I went anywhere. It’s been more than a month since I was in a car or outside of my neighborhood — but I went to South Lake Union, to the Omni office, to go get my personal things.

I wore a mask that Sheila made me. Wore disposable gloves. Used a pen to touch the buttons in the elevator.

It was certainly weird to be in the office. Almost nobody there. The couple people who were there were nice, of course.

I packed everything I wanted to take home in a small box. A quilted wall hanging Sheila had made, a couple framed photos (Babe Ruth; Avalon, NJ), a laptop that I own, some mints.

I left behind the stuff of mine I didn’t want to bring home — bean bag chair, coat rack, small table, black fleece blanket.

A guitar, too. I left behind a guitar. Just a cheap acoustic guitar, but weirdly awesome for how little I paid for it. It’s free to the first person in the office to grab it.

I can’t remember when it was, now — last year, maybe — there was a meetup for The Automators podcast held in the Omni cafeteria. At some point that evening, James Dempsey sang a few songs while I accompanied him on that guitar.

Which means the guitar has some amount of public life lived, which is good for its soul. I did my part for it, and now it’s someone else’s turn.

Anyway… We took the box home. It’s in a closet, where it will sit quarantined for a week before I’ll touch it. Nothing urgent in there. Radioactive but uninteresting.

I changed all my clothes and washed my hands like crazy. Multiple times. Used the really hot water from that one faucet, which probably doesn’t matter.

Job Hunt

I’m weirdly busy — the job hunt is more than a full-time job. I’m treating it that way, anyway. I’ll be anxious about this until I get a job, and I don’t need more anxiety right now.

I’m keeping an open mind and talking to as many potential employers as I can. I’m leaning strongly toward a full-time job (rather than contracting). I just had one; I’d like another one.

Overwhelmed in a Good Way

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

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

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

I do have three requirements:

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

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

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

* * *

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