Apple’s docs were so bad I rewrote all of them

When SwiftUI came out, it was the most exciting thing to happen to iOS development in a decade. Declarative UI, live previews, a tenth of the code. I was all in on day one.

Then you’d open the documentation.

An Apple SwiftUI documentation page reading “Instance Property, content, No overview available.”A real page from Apple’s SwiftUI reference in 2020. That is genuinely all it said.

“No overview available.” If you wrote SwiftUI in the early days, that phrase is a jump scare. You’d find the exact modifier you needed, click through, and get a type signature and nothing else. No explanation, no example, no hint of what the parameters actually did. The API was beautiful and the manual was blank pages.

Everyone complained about this. What I did was measure the complaining.

The morning sweep

I was running my first company and my life had narrowed to a point. I drank Soylent, essentially only Soylent. I did not go out. I was so hell-bent on making the thing work that I had stopped doing anything that wasn’t making the thing work, and I would not recommend that to anybody, including me.

The one ritual I would defend is the morning one. Before writing any code I read Hacker News — not skimming the front page, going deep, dozens of threads, looking for the same complaint said twice. Not for ideas. For evidence. The founder failure mode I was most afraid of was building something clever that nobody had asked for, so I wanted to see people ask.

On November 10th, 2020, Casey Liss published “On Apple’s Piss-Poor Documentation”. It went to the top of Hacker News with 1,180 points and 335 comments.1 His refrain, the thing he kept quoting back at Apple, was the phrase off that empty page: “No overview available. Fuck you, figure it out.”

That is about as loud as evidence gets. A thousand developers agreeing, in public, with timestamps.

The test

Three days later I posted the meme.

“100 upvotes & I’ll quit my job to document SwiftUI full-time” — r/swift, two and a half days after the Hacker News thread. 903 upvotes, 33 comments. This is the post: the image was the whole argument.

The headline is shaped like a dare because dares get clicked. It wasn’t one. I had no intention of letting a vote count decide anything; I wanted the vote count. The post was an instrument, and the number it returned was the answer to “if we build this, does anybody come.”

I asked for a hundred. It finished at more than nine hundred.2

Fifteen days later, the first commit landed in a new repository called Docs.

The documentation hub

Then I had to sell it internally, which was harder than posting it.

My co-founder wanted to build a package marketplace — a store for Swift components. It was a good idea. It was also an idea we would have to convince people they needed, and I had just watched a thousand of them say out loud what they already wanted.

So I pitched it as a sequence rather than a substitution: documentation is the page a Swift developer opens every single day, more often than any store. Own the reference and you own the front door; the packages could come later, sold to people already standing in your house.

A whiteboard headed “DOCUMENTATION” covered in green marker strategy notesFive weeks after the first commit. “problem big → solution elegant → go to market → team credibility.” Bottom right: “first modern documentation engine for enterprise.” Top right, in January 2021: “we’ll have the absolute best data for docs + AI.”

We never got to later. But the front door got built, and it is still standing.

“I” becomes “we” from here, because it has to. SwiftOnTap3 came out of Peach Blossom Spring, the first company I ever started, with my co-founder Alex — who has more commits on the docs repo than I do. Aaron, Elizabeth, and Elijah wrote alongside us, and by the end 27 people had commits in that repo, most of them strangers who just fixed a page they were annoyed by.

The pitch was simple: documentation for every SwiftUI symbol, with a full working example for every one. Not a blog of tutorials. Not “here are the ten views you actually need.” Every symbol. If Apple shipped it, we documented it, and you could copy the example straight into Xcode and watch it run.

One file

The architecture still makes me smile. Every doc lived in a single file called SwiftUI.swift: the framework’s symbols, redeclared, with our documentation written as ordinary Swift doc comments above each one. The whole site is a /// comment.

/// Or use a `Divider` in an ``HStack`` to create a vertical line between
/// horizontally laid out elements:
///
/// ```
/// struct ExampleView: View {
///     var body: some View {
///         HStack {
///             Text("This is a line of text")
///
///             Divider()
///
///             Text("This is an unrelated line of text")
///         }
///     }
/// }
/// ```
///
/// ![A view containing an HStack with two text lines, separated by a vertical
/// divider in the form of a thin gray line.](Horizontally-Split-Text.png)
///
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
public struct Divider : View {

A whiteboard diagram of the publishing pipeline, drawn in blue and green markerEighteen days after the first commit. GitHub master into CI/CD, S3, a Swift-docs lambda, a Python saver, DynamoDB. Every pull request needs two approvals. The box in the corner just says “tree ???”.

That is the real source of the Divider page, alt text and all. A parser we built scanned the comments and published them to swiftontap.com, where you pressed /, typed a symbol, and hit return. Because the docs were just a Swift file on GitHub, anyone could edit them, and the site redeployed with their fix. Documentation as a pull request.

Lines in SwiftUI.swift58,410
Runnable examples1,167
Rendered example screenshots1,158
Commits740
Contributors27

Every one of those is measured from the repo as it stands today, not remembered.4

Every symbol

“An example for every symbol” is easy to say. This is what it looks like as a pile:

A contact sheet of rendered SwiftUI examples from the docs repositoryEighty-four of the 1,158 example screenshots in the repo, picked for variety. Every one of them is the output of a snippet you could paste into Xcode.

Every doc page ends in a picture of the thing actually running, because a screenshot is a promise that the code compiles. When the example moved, we shipped the movement:

The example from the interactiveSpring(response:dampingFraction:blendDuration:) page, exactly as it appears in the docs. 287 of the examples are animated.

The grind

Writing docs for an entire framework is exactly as glamorous as it sounds. You open a symbol. You figure out what it actually does, which often means writing test projects because the official page says nothing. You write the explanation you wish existed. You write an example that compiles. Then you do it again.

A sleeping bag, pillow and hoodie laid out on office carpet next to the wheels of two desk chairsFor a stretch of the documentation grind, this was where I lived: a sleeping bag on the office floor. The photo is timestamped 8:40 in the morning, which is how you can tell it’s a picture of where I’d just woken up.

The fastest way to understand an undocumented API is to try to explain it to someone else. Every gap in your explanation is a gap in your understanding, and the compiler keeps you honest.

DecJanFebMarAprthe testNov 13first commitNov 28launchFeb 1448 commits
Commits per day to the docs repo. Fifteen days between measuring the demand and starting to serve it, five months of grind, and the single biggest day of the entire project three days before launch. 721 of the repo’s 740 commits are in this window.

It was the best SwiftUI education money couldn’t buy. You cannot document a framework without actually learning it, all of it, including the weird corners nobody tweets about.

Then we posted it

On Valentine’s Day, three days after the busiest commit day of the entire project, we took it back to the subreddit that had told us to build it. The title was honest: “We were so frustrated by Apple docs that we made our own.”

The SwiftOnTap documentation page for List, as posted to Reddit at launchThe image in the launch post: the List page, with the explanation Apple didn’t write and the example you could paste into Xcode.

It became the most upvoted post in the history of r/swift. It still is, five years later, and not narrowly:

The SwiftOnTap launch post at the top of r/swift’s all-time rankings
Number one on r/swift, sorted by top of all time, today. 1.2K against 852 for second place.

“We went viral” is the cheapest sentence on the internet, but this one meant something specific: thousands of developers upvoting is thousands of developers saying yes, the docs really are that bad, and yes, this really is what we wanted.

It’s still up

swiftontap.com still serves every one of those pages. The repo still takes the occasional pull request — the most recent commit landed five years after the first one.

The SwiftOnTap documentation page for List, live today
The same page, live, right now — and it picked up a dark mode somewhere along the way, so this screenshot matches whichever one you’re reading in.

The docs are open source, at github.com/SwiftOnTap/Docs. 658 stars of people who cared enough to bookmark documentation, which if you think about it is a strange and wonderful thing for documentation to earn.

Apple’s SwiftUI docs have gotten better since. I’d like to think the most upvoted post in r/swift history was a small, loud data point pushing in that direction.

And if those months left me with one conviction, it’s that nobody reads reference docs to admire the type signatures. They read them to steal working code, at eleven at night, one bad page away from giving up. Every page we wrote led with something you could paste and run, and that single choice did more than all the prose combined.

Footnotes

  1. The thread, submitted by ingve on November 10, 2020 at 15:01 UTC. My post went up on the 13th at 00:01 UTC, which is two days and nine hours later, which tells you roughly how much of my life was Hacker News at the time.

  2. The post is still there, sitting at around 907, though it was later removed from the subreddit’s listings, which is why you won’t find it in the all-time top posts. I reposted the same image to r/iOSProgramming the next day and it picked up another 342.

  3. As in beer. The README’s actual tagline: “We’ve got it all on tap,” followed by a faucet emoji and a cheers emoji. We were very serious people.

  4. 1,167 fenced code blocks, if you count the backticks in the file and divide by two. I did.