I'm in an odd position because developing something in the open generally means developers at least are part of the target userbase, but my end user for Ephem, a Python CLI for casting and storing horoscopes, is me: a professional astrologer and desktop Linux user who lives in the terminal.
There has to be at least one more of us, or an astrologer on macOS who can be swayed to install something with pipx
, so I set out to write a tutorial for my CLI tool beyond a simple README to finally ship with v2.0.0 and quickly realized the user I was neglecting the whole time was me.
I caught five UX issues in one evening of writing documentation that went unnoticed with weeks of automated tests. Of course I'm a few semantic versions into this development life cycle, but I felt like I was doing something wrong: shouldn't documentation be for finished products? But then I discovered documentation-driven development (DDD), described in this Gist first published in 2014:
[F]rom the perspective of a user, if a feature is not documented, then it doesn't exist, and if a feature is documented incorrectly, then it's broken.
I'm not properly doing the suggested order of operations of "document first, code second" for the entirety of a project. But here are the local git commits I made while writing my tutorial first draft on a dev branch confidently tagged v2.0.0b2:
$ git log --oneline
413e0b5 (HEAD -> v2) display.month: add day of week
5ddf0c9 now/cast: print saved index
ae20773 add --list-zones global
47f2478 cast: accept seconds input
ebb1e2e fix now --save-config output
Since this is Git history, let's start at the bottom.
-
fix now --save-config output
: I modeled how to save your default coordinates because astrology is ultimately geocentric, so I wrote locale in the tutorial as the first thing to configure. However, runningnow --save-config -y 30 -x -80
... didn't actually produce the Chart of the Moment. I just took it in stride that I re-ranephem now
to actually see a chart. -
cast: accept seconds input
: The tutorial starts self-referentially with its own birth chart from its initial Git commit in H:M:S, but I initially only wrote thecast
command to take H:M since that's what's written on most birth certificates. -
add --list-zones global
: I wrote a short section explaining IANA tz strings andzoneinfo
where I sent the user to a third-party website to find the timezone of their birth, which is contrary to a terminal workflow. -
now/cast: print saved index
: There was no immediate confirmation my database--save
option did anything. In my months of dogfooding, I double-checked with a separate command,data view
. In other words, I didn't trust my own app and wrote an entire step of this tutorial telling someone else not to, either. -
display.month: add day of week
: I modeled how to choose an astrologically optimal wedding date without knowing the day of the week.
Every single commit addresses an issue discovered only by roleplaying a new user with real use cases, not from testing individual functions. And these aren't just any users, but experts in their field with needs that only an astrologer-developer could anticipate. For something this niche, I am my own guinea pig.
Unit tests check if code works; documentation checks if humans can actually use it.
Am I weird?
Looking into talks and writing on documentation-driven development beyond Zach Supalla, I didn't find much:
- Lessons Learned in a Year of Docs-Driven Development (Jessica Parsons, 2019)
- A Better Way To Code: Documentation-Driven Development (Corbin Crutchley, 2022)
- What's Documentation-Driven Development? (Andrew Johns, 2025)
Parsons (verythorough) describes exactly what I experienced around the 14:00 mark. A dev realized only after explaining a feature in writing that it was "going to be way too hard for the customer to do it in the way [they've] planned for it" and adjusted accordingly. But I get the impression from sparse writing on the subject since this talk that this is an unusual way of writing code.
Crutchley's article for This Is Learning encapsulates something else I found in this process: "Docs influence code influence docs." It isn't that you write docs once, then code. A document goes through revisions and review just like any codebase. I did graduate work writing footnoted, enormous Markdown files in a Git repo that was originally an Obsidian vault (my trajectory is weird), so I'm frankly more used to using git diff
to compare drafts of prose than code commits. In the process of the five git commits here, I:
- Described a workflow that didn't work or that I discovered was confusing.
- Revised the modules in question.
- Then rewrote anywhere from 100-800 words of documentation after I fixed it.
This is a totally normal process for me as a writer. I find it intuitive, but maybe it's because I'm a self-taught developer. My undergraduate degrees are in theater and journalism and my longest-running side hustle is astrology which is more stable than either of those industries. I've written and spoken plain English professionally for longer than I've written code, but...
I'm drafting this tutorial in a separate Git repo where I do all my writing before I cp
it to my project dir for editing. Why? I suppose it's because in the world of OSS, I don't really see people dedicating chunks of their Git commits to tweaking their READMEs, so I felt like I wanted to keep my history pure or mostly code for no good reason. This seems to be the bifurcation that Documentation As Code wants to address. Their point that "It is time also to train non-developers on how to use a versioning system" is hilarious to me, though, because using Git to manage professional and hobby writing made me a developer.
The Ephem tutorial draft lives in the same directory as one for a newsletter I sent in June: a tutorial for other astrologers about open-source astrology software from the 90s that I use in my client work, Astrolog. It's written in C++, has had one maintainer since 1991, and isn't very popular with my generation of astrologers in part because like most of Gen Z can't even touch-type. I wrote the tutorial knowing that the terminal is a learning curve for astrologers used to mouse-driven GUIs, but it also led me to really ruminate on my frustrations with Astrolog. So not only is this docs-driven development, but docs-inspired development or docs-driven design where writing about someone else's application, an application I still love and use, led me to imagine my own.
Try documentation-driven development yourself
It's totally possible to test drive this process without starting a brand new project or changing an existing one. Here are some ways you can get a taste:
- Write a real tutorial, not just a README. You're essentially in an extended roleplay with yourself as both teacher and student. This lets you re-encounter a codebase you think you know well from the perspective of an end user who is possibly not even a developer.
- Follow the tutorial like you're a user. I kind of combined this step and the previous: I wrote and ran example commands and discovered my output was half as informative as it should've been, or that in my dogfooding I'd gotten used to extra steps I shouldn't have.
- Docs influence code influence docs. It isn't a waste of time to document a flawed iteration, fix it, then rewrite the documentation. This is basically more verbose, more audience-oriented rubber duck debugging.
- Try documenting someone else's project. Take an application you use often and see what points of friction you've accepted as quirks you can live with. This is what I did with Astrolog!
Top comments (0)