Engineering & Technical

The Engineer

The Signal

If your team is running Kafka as a task queue with competing consumers and no replay

Audit your actual consumption patterns against the RabbitMQ/Kafka/Pulsar decision tree before your next infrastructure review — the most expensive messaging mistake is choosing based on popularity instead of workload fit.

In Play

  1. Messaging Infrastructure Decision Framework

    RabbitMQ, Kafka, and Pulsar represent three distinct architectural paradigms — push broker, append-only log, and hybrid with separated compute/storage — and the most common anti-pattern is defaulting to Kafka when RabbitMQ's simpler model fits the actual workload.

    Ask Clarity
  2. API Layer Trade-offs: REST vs GraphQL Caching Gap

    GraphQL's HTTP-layer caching story remains fundamentally broken at scale, making REST with a BFF pattern the better default unless you have genuinely diverse client data needs.

    Ask Clarity
  3. AI Agents Writing Infrastructure Code

    WorkOS shipped an AI agent (npx workos) that autonomously reads codebases and writes auth integrations with a self-correction loop — signaling a shift from SDKs-you-integrate to agents-that-integrate-themselves, but authentication is the worst domain to trust to autonomous generation.

    Ask Clarity

Deep Dives

RabbitMQ vs Kafka vs Pulsar: The decision tree your team should actually use

Three Different Machines, Not Three Options

The persistent framing of RabbitMQ, Kafka, and Pulsar as competitors obscures the real insight: they solve fundamentally different problems with different data models. Choosing between them isn't a feature comparison — it's an architecture decision.

DimensionRabbitMQKafkaPulsar
Core modelMessage broker (push)Distributed log (pull)Hybrid broker + log
Message lifecyclePushed → acked → deletedAppended → retained by policyCursor-tracked in ledger
Replay capabilityNone after ackFull via offset resetFull via cursor reset
Storage architectureCoupled to brokerCoupled (partitions on disk)Separated (BookKeeper ledgers)
Scaling modelAdd brokersAdd brokers + rebalance partitionsScale compute and storage independently
Operational complexityLow-mediumMedium-highHigh (broker + BookKeeper + ZooKeeper)

The Decision Tree That Actually Matters

  1. Do consumers need to replay messages? No → RabbitMQ is likely sufficient and simpler. Yes → continue.
  2. Do multiple independent consumers need the same stream? Yes → Kafka or Pulsar. No → still consider Kafka for durability, but RabbitMQ may work.
  3. Do you need to scale storage independently of compute? Yes → Pulsar's architecture wins. No → Kafka's simpler operational model is worth the coupling.
  4. What's your team's operational capacity? Running BookKeeper + Pulsar brokers is meaningfully harder than Kafka with KRaft. Small platform teams should weight this heavily.

The Pulsar Nuance

Pulsar's compute/storage separation via BookKeeper follows the same disaggregated pattern winning in modern databases — architecturally elegant and theoretically superior for independent scaling. But the operational tax is real: you're now running and monitoring BookKeeper clusters alongside brokers, and Pulsar still requires ZooKeeper. Meanwhile, Kafka's KRaft mode has eliminated its ZooKeeper dependency, meaningfully closing the operational simplicity gap.

The most common anti-pattern: teams choosing Kafka because it's the default, then using it as a task queue with competing consumers and no replay — paying Kafka's operational complexity for RabbitMQ's use case.

What to do

  1. Audit your current messaging system's actual consumption patterns this sprint — specifically check whether consumers use replay, or if you're running Kafka as a glorified task queue

  2. If evaluating Pulsar, run a proof-of-concept specifically testing independent storage scaling and mixed queue/streaming workloads against your Kafka baseline before committing

  3. Document your messaging system decision rationale in an ADR (Architecture Decision Record) tied to your actual workload characteristics, not feature matrices

GraphQL's caching gap is worse than you think — and AI agents writing auth code is worse still

The REST vs GraphQL Caching Reality

The standard framing — REST gives server control with native HTTP caching (ETag, Cache-Control, CDN), GraphQL gives client control with a single flexible endpoint — understates the operational cost of that trade-off at scale.

  • GraphQL caching lives at the application layer. Persisted queries and response caching are bolt-ons, not primitives. You lose CDN offload for free, meaning your origin servers handle dramatically more traffic for equivalent read patterns.
  • The complexity shift is asymmetric. GraphQL moves complexity from many clients to one server — which sounds like a win until that server becomes your gateway bottleneck. Resolver fan-out means your GraphQL gateway's p99 is bounded by the slowest downstream service.
  • REST's over-fetching problem is real but often cheaper to solve (sparse fieldsets, BFF pattern) than GraphQL's caching and complexity problems are to mitigate.

The signal to move to GraphQL: when your backend team spends more time building one-off REST endpoints for different client needs than they would spend building and maintaining a schema. That crossover point is higher than most teams think. If you're building a single SPA talking to your own backend, REST with a BFF gives you the same flexibility with dramatically better caching.


AI Agents That Integrate Themselves

WorkOS shipped an AI agent (npx workos) powered by Claude that autonomously reads your codebase, detects your framework, writes a complete auth integration, and self-corrects by feeding build errors back to itself. This signals a meaningful shift in developer tooling: from SDKs you integrate to agents that integrate themselves.

But authentication is the worst possible domain to trust to autonomous code generation. A subtle bug in token validation or session handling doesn't fail a build — it fails a pen test, or worse, a breach.

Treat any AI-generated auth code as untrusted input requiring full security review. The pattern of self-integrating agents is significant; the domain they chose to demonstrate it in is concerning.

What to do

  1. If running GraphQL at scale, measure your actual cache-hit ratio gap versus equivalent REST endpoints this quarter before expanding GraphQL surface area

  2. Establish a policy now: AI-generated authentication or authorization code requires mandatory security review before merge, regardless of the tool that produced it

The bottom line

The most expensive infrastructure mistake isn't picking the wrong tool — it's picking the popular tool without checking whether your workload matches its architecture. If your Kafka consumers don't replay messages and don't share streams, you're running a distributed log as a task queue, and RabbitMQ would serve you at a fraction of the operational cost.