Methodology
8 Apr 2025
AI Software Delivery: Collaborative Intent Articulation
Something changed in the past six months. I don’t think we’ve fully processed it yet.
I’ve been writing code professionally for eighteen years. For all of those years, one thing stayed constant: the code was the source of truth. Requirements documents got stale. Design specs drifted. Jira tickets turned into archaeological artifacts. But the code? The code was always right — because the code was what actually ran.
That assumption is breaking down.
10 Mar 2023
Smartcast and Null Safety: Influences from Kotlin to TS
Working at Google means living in a polyglot environment. Android teams write Kotlin. Web teams write TypeScript. Backend teams write a mix of Java, Go, and (increasingly) Kotlin. When you cross those boundaries regularly — and in DevRel, crossing boundaries is the job — you start noticing how ideas migrate between language ecosystems.
One migration that doesn’t get discussed enough: the convergence of type narrowing between Kotlin and TypeScript.
Kotlin’s smart casts #
Kotlin shipped smart casts from day one in 2016. The idea was simple and, at the time, felt radical compared to Java: if you check a type at runtime, the compiler should remember that check and narrow the type automatically.
30 May 2022
ADRs as Feedback Loops for Distributed Performance
I wrote about Architecture Decision Records a while back. Back then, I saw them as documentation—a way to capture the why behind decisions so future teams wouldn’t repeat past mistakes. Useful, sure. But kind of… administrative?
I’ve changed my mind. Or rather, I’ve realized I was only seeing half the picture.
At Google scale, working with distributed teams scattered across time zones, ADRs turned out to be something else entirely. They’re feedback loops. And that distinction matters more than I expected.
26 Jul 2021
Rethinking Errors, Warnings, and Lints in Large Codebases
Last week I opened a pull request on one of our older services at TaskRabbit and got hit with 347 ESLint warnings. Not errors. Warnings. The build passed, the tests passed, and the PR got merged. Nobody looked at a single one of those 347 signals.
That moment bothered me more than it should have.
I’ve been managing large codebases for a while now, and the way most teams handle the spectrum between errors, warnings, and lints is — to put it politely — chaotic. We tend to treat them as a binary: either something blocks the build or it doesn’t. The nuance in between? Lost. Completely.
8 Dec 2020
Using Architecture Decision Records (ADRs) to Prevent Chaos
Last month I watched two senior engineers spend an entire sprint debating whether to use GraphQL or REST for a new internal API. They eventually chose GraphQL. The thing is, we’d already made that decision eight months ago for a different service — with reasoning that lived nowhere except maybe in Dave’s head. (Dave left in March.)
This happens constantly. A decision gets made in a meeting, or a Slack thread, or occasionally in someone’s head while they’re showering. Then people leave, context evaporates, and the next team walks into the same intersection and argues from scratch. Same debate, same circular reasoning, same outcome — or worse, a different one.