softwareopen source

How I build software


A working manifesto. Opinionated on purpose. These are defaults, not dogma — but the burden of proof is on deviating from them.


Open

Open source by default. Transparency builds trust, and it kills the supplier rug-pull: if my vendor disappears or turns hostile, the code is still mine and everyone's. It doesn't have to be MIT — AGPLv3 keeps it honestly open while stopping someone from quietly running my work as a closed service.

License the server and the client differently. AGPLv3 + CLA on the server keeps the copyleft teeth and keeps dual-licensing on the table. Anything an integrator embeds — SDKs, clients — stays permissive (Apache 2.0, for the patent grant). Copyleft should never touch someone else's linked code.

Standard

Conform to the standard, not to my implementation. HTTP, OAuth2/OIDC, OpenAPI. When the standard is the contract, people can migrate in without a rewrite and out without my permission. That's not a concession — it's the whole pitch. Being a drop-in for an incumbent's API is the cheapest growth lever there is.

REST is the default, and the spec is the source of truth. OAS3 with full request/response validation. Docs are generated, never hand-maintained. If the spec and the code disagree, that's a bug, not a documentation task.

Version explicitly. Break rarely. A client written today should keep working tomorrow. Prefer additive change; reserve breaking changes for new versions. Compat-date versioning (Stripe/Cloudflare-style) is a strong option when the surface evolves continuously — but pick the scheme per API. The principle is the stability, not the mechanism.

Portable

Run lean, run anywhere. JavaScript or Wasm so it pushes to the edge by default. Docker when that's the shape you want. Keep runtime assumptions thin enough that the same code doesn't care much where it lands.

Cloudflare-first, locked-in never. Cloudflare is the default when you don't need EU-only data residency — the edge primitives are too good to pass up. The adapter and standards discipline exists precisely so that when something forces a move — sovereignty, pricing, a better option from Bunny or Hetzner, plain old Kubernetes — it's a swap, not a rewrite. The portability is the insurance premium I pay to go all-in on the default.

Composable

Wrap every dependency in an adapter. Database, queue, search, storage, AI provider — all behind a port. Switching a vendor should mean writing one new adapter, not redesigning the core. And don't hand-roll what's already abstracted: Drizzle runs the same query code against D1 and Postgres, so use it.

Shard along natural seams. Tenants that don't talk to each other don't share a database. Prefer an explicit directory mapping over hash-modulo, so you add capacity without remapping anyone. Bonus: that directory doubles as a PII vault keyed by opaque IDs, which makes GDPR erasure a crypto-shred instead of a migration.

Honest about constraints

Treat EU data residency as a design constraint, not an afterthought. It's the single thing most likely to pull me off my default stack — Cloudflare is a US company under the CLOUD Act no matter which edge it runs on. So I design as if the sovereignty-sensitive layer will eventually move, and I keep it cleanly separable. Easy to say, genuinely hard to do.

Observability is mandatory and vendor-neutral. It's a separate concern from the architecture, but it's not optional. Standardize on OpenTelemetry so the telemetry outlives whatever backend I'm sending it to this year.

Keep the boring choices boring. Spend the engineering budget on the one layer that actually differentiates the product. Everything else should be the most standard, most swappable option available. Cleverness in the plumbing is a liability.


Current defaults (not dogma)

  • Validation: Zod
  • HTTP framework: Hono
  • ORM: Drizzle
  • Platform: Cloudflare Workers, D1, R2, Analytics Engine, Cache, Workers for Platforms

These are what I reach for today. The adapter discipline above is what lets me change my mind without changing everything.