# Joan Ayebola > Field notes on developer tooling, APIs, infrastructure, data systems, and the documentation that makes them usable. Joan Ayebola is a technical writer covering developer tools and platforms. Content prioritizes tested workflows, working code, explicit methods, and clear verdicts. ## Categories - [AI developer tooling](https://joanayebola.vercel.app/category/ai-developer-tooling/): Practical work with agents, MCP, RAG, LLM APIs, and evaluation systems. - [APIs & developer platforms](https://joanayebola.vercel.app/category/apis-developer-platforms/): Auth, payments, communications, and the interfaces developers build on. - [DevOps & observability](https://joanayebola.vercel.app/category/devops-observability/): Delivery pipelines, production systems, reliability, and useful telemetry. - [Data engineering](https://joanayebola.vercel.app/category/data-engineering/): Pipelines, warehouses, streaming systems, and the decisions behind them. - [Documentation & DX](https://joanayebola.vercel.app/category/documentation-dx/): Teardowns and rewrites of docs, quickstarts, SDKs, and developer journeys. ## Articles - [Giving an AI Agent a Memory: Patterns, Storage, and What to Forget](https://joanayebola.vercel.app/blog/agent-memory-patterns/): Build a practical memory layer for an AI agent, choose where each kind of memory lives, and design retrieval and forgetting that you can trust. - [From API Keys to Scoped Tokens: Upgrading a Public API's Auth Without Breaking Clients](https://joanayebola.vercel.app/blog/api-keys-to-scoped-tokens/): Migrate a public API from all-powerful API keys to scoped, expiring tokens: design the scopes, run both systems in parallel, and deprecate keys without breaking clients. - [Designing Rate Limits Developers Won't Hate: Quotas, Headers, and Graceful 429s](https://joanayebola.vercel.app/blog/api-rate-limiting-design/): Design rate limits that protect your API without punishing good clients: fair quotas, honest headers, and 429 responses developers can act on. - [Designing an API Reference Developers Actually Read: Examples, Errors, and Auth Up Front](https://joanayebola.vercel.app/blog/api-reference-design/): An API reference is read under pressure, mid-debug. Design it that way: auth before endpoints, a worked example per operation, and errors documented like features. - [API Versioning Without Regret: URLs, Headers, and Sunset Policies Compared](https://joanayebola.vercel.app/blog/api-versioning-strategies/): Compare URL, header, and media-type versioning on real tradeoffs, and design a sunset policy that retires old versions without breaking clients. - [BigQuery Partitioning and Clustering: The Cost Decisions You Make at Table-Creation Time](https://joanayebola.vercel.app/blog/bigquery-partitioning-clustering/): Partition and cluster BigQuery tables with intent: how pruning actually works, where each feature stops helping, and the decisions that are painful to reverse later. - [Changelogs Are Product Writing: Entries Users Read and Releases That Earn Trust](https://joanayebola.vercel.app/blog/changelog-writing/): Why the changelog is product writing, not a commit digest, and how to write entries that users actually read and act on. - [Chunking Strategies for Embeddings: What Actually Changes Retrieval Quality](https://joanayebola.vercel.app/blog/chunking-strategies-embeddings/): Compare fixed-size, recursive, semantic, and structure-aware chunking so you can choose a strategy that improves retrieval instead of quietly breaking it. - [CI That Stops Rebuilding the World: Caching, Matrix Builds, and Flaky-Test Quarantine](https://joanayebola.vercel.app/blog/ci-pipeline-caching/): Cut CI time with dependency and build caching that actually invalidates correctly, matrix builds that parallelise honestly, and a quarantine lane for flaky tests. - [Cursor Pagination for Real APIs: Ordering Guarantees, Opaque Tokens, and Edge Cases](https://joanayebola.vercel.app/blog/cursor-pagination-api-design/): Implement cursor pagination that stays correct under inserts and deletes, with stable ordering, opaque tokens, and honest handling of filters. - [Dagster vs Airflow for a New Data Platform: Assets, Sensors, and Day-Two Operations](https://joanayebola.vercel.app/blog/dagster-vs-airflow/): Dagster and Airflow compared on assets, sensors, partitions, backfills, retries, and observability, so you can choose the right core for a new platform. - [Data Quality Gates with Great Expectations: Expectations, Checkpoints, and CI](https://joanayebola.vercel.app/blog/data-quality-great-expectations/): Build a working data quality gate with Great Expectations: define an Expectation Suite, run it as a Checkpoint, store the results, and fail CI on bad data. - [Incremental Models in dbt: Merge Strategies, Late Data, and Full-Refresh Discipline](https://joanayebola.vercel.app/blog/dbt-incremental-models/): Choose the right dbt incremental strategy, handle late-arriving data with lookback windows, and build the full-refresh habits that keep incremental models trustworthy. - [dbt Tests and Data Contracts: Catching Upstream Breakage Before Your Stakeholders Do](https://joanayebola.vercel.app/blog/dbt-tests-data-contracts/): Layer dbt generic, singular, and unit tests with enforced data contracts so upstream schema and logic changes fail in CI, not in a stakeholder's dashboard. - [Change Data Capture with Debezium: From Postgres WAL to a Consumer That Keeps Up](https://joanayebola.vercel.app/blog/debezium-cdc-postgres/): Stand up Debezium on Postgres logical decoding, protect the replication slot, and write a consumer that handles snapshots, deletes, and schema changes without losing rows. - [Auditing a Developer Onboarding Funnel: Signup to First API Call, Timed and Scored](https://joanayebola.vercel.app/blog/developer-onboarding-audit/): A repeatable audit method for the developer onboarding funnel, with a scoring rubric and a clearly labelled illustrative walkthrough. - [Diátaxis, Applied: Reorganising a Real Docs Site Without a Six-Month Rewrite](https://joanayebola.vercel.app/blog/diataxis-applied/): A field guide to applying the Diátaxis framework incrementally: audit what you have, split the pages that do two jobs, and move content in slices readers never notice. - [Multi-Stage Docker Builds for Node and Python: Smaller Images, Fewer Surprises](https://joanayebola.vercel.app/blog/docker-multistage-builds/): Learn multi-stage Docker builds for Node and Python with cache mounts, slim runtime images, non-root users, and digest pinning to cut bloat and build risk. - [Docs as Code, With Teeth: Linting, Link Checks, and Preview Builds in CI](https://joanayebola.vercel.app/blog/docs-as-code-ci/): Wire documentation into CI so quality is enforced, not hoped for: prose linting that respects writers, link checking without false alarms, and previews on every pull request. - [Error Messages Are Documentation: A Field Guide to Writing Failures Users Can Fix](https://joanayebola.vercel.app/blog/error-message-writing/): A practical method for writing error messages that name the problem, state the cause, and hand the user a fix they can actually perform. - [Function Calling That Survives Bad Arguments: Validation, Retries, and Repair](https://joanayebola.vercel.app/blog/function-calling-error-handling/): Build a validation, retry, and repair layer for LLM function calling that rejects bad arguments, returns useful errors, and protects side effects. - [Grafana Dashboards That Answer Questions Instead of Displaying Data](https://joanayebola.vercel.app/blog/grafana-dashboards/): Design Grafana dashboards around the questions operators actually ask: symptom-first layout, RED and USE panels, honest thresholds, and variables that narrow scope. - [gRPC vs REST vs GraphQL for Internal APIs: A Decision Guide with Working Examples](https://joanayebola.vercel.app/blog/grpc-vs-rest-vs-graphql/): The same internal service built three ways: compare gRPC, REST, and GraphQL on contracts, payloads, streaming, and operability, then decide with a framework you can reuse. - [Runbooks That Get Used at 3 a.m.: Structure, Triggers, and the Last Verified Step](https://joanayebola.vercel.app/blog/incident-runbooks/): Write runbooks an exhausted engineer can execute at 3 a.m.: symptom-based triggers, numbered verifiable steps, explicit stop conditions, and a maintenance loop. - [Kafka Delivery Semantics in Practice: What Exactly-Once Actually Buys You](https://joanayebola.vercel.app/blog/kafka-delivery-semantics/): At-most-once, at-least-once, and exactly-once in Kafka, precisely: which configurations deliver which guarantee, where exactly-once stops, and what to build instead. - [Kubernetes Probes Aren't Interchangeable: Liveness, Readiness, and Startup in Production](https://joanayebola.vercel.app/blog/kubernetes-probes-explained/): Learn what liveness, readiness, and startup probes actually control, how they fail in production, and how to configure all three correctly. - [Cache LLM Responses Without Serving Stale Answers](https://joanayebola.vercel.app/blog/llm-response-caching/): Design an LLM response cache that actually saves money: exact-match keys, versioned prompts, tenant isolation, and the strict rules for when semantic caching is safe. - [Run LLMs Locally with Ollama and Wire Them into Your Existing Tooling](https://joanayebola.vercel.app/blog/local-llm-ollama-tooling/): Install Ollama, serve models over its native and OpenAI-compatible APIs, tune context and quantization, and connect editors, CLIs, and scripts. - [Beyond Tools: MCP Resources, Prompts, and Sampling, Explained by Building](https://joanayebola.vercel.app/blog/mcp-resources-prompts-sampling/): Tools get all the attention, but MCP's resources, prompts, and sampling are what make a server feel native. Build a small server that uses all three. - [OAuth 2.0 with PKCE, Step by Step: The Flow Your SPA Actually Runs](https://joanayebola.vercel.app/blog/oauth-pkce-flow-explained/): Walk the authorization code flow with PKCE exactly as a browser app runs it, including the verifier math, state checks, and token storage decisions. - [Generate Clients from OpenAPI and Stop Hand-Writing Fetch Wrappers](https://joanayebola.vercel.app/blog/openapi-code-generation/): Turn your OpenAPI document into typed clients: pick a generator, wire it into CI so drift fails the build, and handle auth, errors, and versioning without hand-written wrappers. - [Prometheus Metrics That Don't Explode: Cardinality, Naming, and the Queries You'll Actually Run](https://joanayebola.vercel.app/blog/prometheus-metric-design/): Design Prometheus metrics that stay queryable under load: naming, label discipline, histograms, and the PromQL for errors, latency, and saturation. - [Prompt Injection Is a Data Problem: Defending LLM Features in Production](https://joanayebola.vercel.app/blog/prompt-injection-defense/): Prompt injection works because models cannot tell instructions from data. Defend in depth: separate the two, constrain tools, validate actions, and assume breach. - [Rewriting a Quickstart Live: From Feature Tour to First Success in Five Steps](https://joanayebola.vercel.app/blog/quickstart-rewrite-walkthrough/): A step-by-step rewrite method that turns a feature-tour quickstart into a task-first guide ending in a verifiable first success. - [Evaluate a RAG Pipeline Before Your Users Do](https://joanayebola.vercel.app/blog/rag-pipeline-evaluation/): Build a repeatable evaluation harness for your retrieval-augmented generation pipeline: golden datasets, retrieval metrics, faithfulness checks, and CI gates. - [The README Is Your Landing Page: Structure for Open-Source Projects That Want Contributors](https://joanayebola.vercel.app/blog/readme-craft/): How to structure a README that converts a curious visitor into a running install, then into a first contribution. - [API Errors Worth Reading: Adopting RFC 9457 Problem Details](https://joanayebola.vercel.app/blog/rfc-9457-problem-details/): Replace ad-hoc error JSON with RFC 9457 problem details: a standard envelope, extension members for validation, and a migration path that keeps old clients working. - [Schema Evolution Without Breaking Consumers: Avro, Protobuf, and Compatibility Modes](https://joanayebola.vercel.app/blog/schema-evolution-avro-protobuf/): A practical guide to evolving Avro and Protobuf schemas safely with compatibility modes, registries, and expand-and-contract deployments. - [SLOs and Error Budgets a Small Team Can Actually Run](https://joanayebola.vercel.app/blog/slo-error-budgets/): Build a lean SLO practice for a small team: pick few user-facing SLIs, set defensible targets, add burn-rate alerts, and enforce an error budget policy. - [Streaming LLM Responses End to End: Tokens, Backpressure, and Honest Loading States](https://joanayebola.vercel.app/blog/streaming-llm-responses/): Build production-ready token streaming with SSE, ReadableStream, backpressure, aborts, and loading states that tell the truth. - [Streaming vs Batch: Choosing with a Latency Budget Instead of a Trend](https://joanayebola.vercel.app/blog/streaming-vs-batch-latency-budget/): Choose between streaming, micro-batch, and batch by deriving a latency budget from the consumer decision, not by following tooling trends. - [Structured Logging in Node.js That Pays Off During Incidents](https://joanayebola.vercel.app/blog/structured-logging-nodejs/): Build structured JSON logging in Node.js with correlation IDs, redaction, and error serialization so you can trace failures quickly during incidents. - [Structured Outputs from LLM APIs: Schemas, Retries, and the Failure Modes Nobody Documents](https://joanayebola.vercel.app/blog/structured-outputs-llm-apis/): Get reliably typed data out of LLM APIs: strict schemas, parser-backed validation, retry loops that fix errors, and the failure modes that survive all three. - [Subscription Billing Is a State Machine: Trials, Proration, Dunning, and Webhooks](https://joanayebola.vercel.app/blog/subscription-billing-state-machine/): Model subscriptions as an explicit state machine driven by payment webhooks: states, transitions, proration rules, and a dunning sequence that recovers failed payments. - [Terraform Modules Your Team Will Reuse: Interfaces, Versioning, and State Hygiene](https://joanayebola.vercel.app/blog/terraform-module-design/): Design Terraform modules with narrow interfaces, honest versioning, and clean state boundaries so other teams adopt them instead of copying and forking them. - [Trace Sampling Without Blind Spots: Head, Tail, and Rate-Based Strategies Compared](https://joanayebola.vercel.app/blog/trace-sampling-strategies/): Compare head, tail, and rate-based trace sampling by what each keeps, what each silently drops, and how to combine them without losing the traces that matter. - [Docs Teardown: Twilio's Quickstart Funnel and the Art of the Five-Minute Win](https://joanayebola.vercel.app/blog/twilio-docs-teardown/): How Twilio's quickstarts are engineered as a funnel: pre-written code, a working result in minutes, and a deliberate handoff from first success to production depth. - [Docs Teardown: What Vercel's Documentation Gets Right About Developer Journeys](https://joanayebola.vercel.app/blog/vercel-docs-teardown/): A teardown of Vercel's docs: how task-based navigation, framework-aware content, and honest limits pages turn a platform manual into a guided developer journey. - [Warehouse Cost Control: The Queries, Habits, and Guardrails That Cut the Bill](https://joanayebola.vercel.app/blog/warehouse-cost-control/): Cut warehouse spend by finding expensive queries, fixing pruning and sizing, and adding guardrails that stop waste before it becomes the bill. - [Webhook Idempotency, Done Properly: Keys, Storage, and Replay Windows](https://joanayebola.vercel.app/blog/webhook-idempotency/): Build a webhook receiver that safely handles duplicates, retries, and replays without double-charging customers or corrupting state. - [Orchestrate an Airbyte + dbt Pipeline with Kestra: An End-to-End Walkthrough](https://joanayebola.vercel.app/blog/orchestrate-airbyte-dbt-pipeline-kestra/): Build an automated ELT pipeline that runs an Airbyte sync, waits for completion, executes dbt models, and reports status through Kestra. - [Deploy to Managed Kubernetes from GitHub Actions: A Complete CI/CD Walkthrough](https://joanayebola.vercel.app/blog/deploy-managed-kubernetes-github-actions/): Build a GitHub Actions pipeline that tests a Node.js app, publishes its Docker image to GHCR, and deploys it to DigitalOcean Kubernetes. - [Trace a Real Node.js API with OpenTelemetry and SigNoz in 20 Minutes (ESM and TypeScript Included)](https://joanayebola.vercel.app/blog/opentelemetry-nodejs-signoz-tracing/): Trace Express, Postgres, outbound HTTP calls, and custom business logic with OpenTelemetry and SigNoz, including the correct ESM and TypeScript setup. - [Paystack vs Flutterwave vs Stripe: Whose API Docs Give You the Clearest Path to a First Payment?](https://joanayebola.vercel.app/blog/paystack-vs-flutterwave-vs-stripe-api-docs/): A documentation teardown of Paystack, Flutterwave v4, and Stripe for Nigerian developers—from test keys to server verification and a working webhook. - [Sync Postgres to a Data Warehouse with Airbyte in 30 Minutes (and What Breaks)](https://joanayebola.vercel.app/blog/airbyte-postgres-to-bigquery-cdc/): Set up Postgres-to-BigQuery replication with Airbyte CDC, then diagnose six failures involving WAL, permissions, data types, keys, and schema changes. - [Build Your First MCP Server in TypeScript (SDK v2) and Connect It to Claude, Cursor and Codex](https://joanayebola.vercel.app/blog/build-mcp-server-typescript-sdk-v2/): Build a local Markdown search server with MCP TypeScript SDK v2, test it with Inspector, and connect it to Claude Desktop, Cursor, and Codex. ## Important pages - [About](https://joanayebola.vercel.app/about/) - [Work with me](https://joanayebola.vercel.app/work-with-me/) - [Affiliate disclosure](https://joanayebola.vercel.app/affiliate-disclosure/) - [RSS](https://joanayebola.vercel.app/rss.xml)