Why Matt Pocock Is Right About Making Codebases AI Agents Love
05 Mar 2026Matt Pocock is once again on the money in his video “How To Make Codebases AI Agents Love”.
Here's why I agree with him.
Read More →Matt Pocock is once again on the money in his video “How To Make Codebases AI Agents Love”.
Here's why I agree with him.
Read More →AI coding agents produce code faster than you can review and understand it.
One pattern works in both new and legacy codebases because you can adopt it incrementally, without breaking callers.

For business logic, treat every function as having two inputs: data (args) and capabilities (deps).
Without a clear constraint, generated code becomes harder to reason about: dependencies disappear, side effects spread, composition gets messy. This is why visible structure is essential.
fn(args, deps) is that constraint
For existing code, start with:
functionName(args, deps = defaultDeps)
Dependencies are explicit, not hidden.
There’s no framework and no package to install.
Read More →You have an Awaitly workflow: a few steps, some dependencies, typed results. It works. When someone asks "what does this do?" or you need to debug a run, you're left tracing through code.
What if you could see the same workflow as a diagram? awaitly-visualizer plugs into your workflow's events and turns them into that picture. For a checkout that runs fetchCart, validateCart, processPayment, then completeOrder, you get output like this:
┌── checkout ────┐
│ ✓ fetchCart │
│ ✓ validateCart│
│ ✓ processPayment
│ ✓ completeOrder
│ Completed │
└────────────────┘
Same idea as Mermaid flowcharts: steps, order, success and failure. This post walks through adding it step by step. All of the code below lives in a test in the repo so you can run it yourself.
Read More →As of today, Opus 4.5 is the best coding model I've used. That is not praise by vibes. That is, after building libraries and utilities that fixed problems I could not solve with the tools I was using before.
The progress is impressive.
However, it’s not all sunshine and rainbows, as people on social media and YouTube claim.


We've all written this code:
const lambdaHandler = async () => {
try {
const db = await connectToDb();
const result = await errorHandler({ taskId, error }, { db });
return { statusCode: 200, body: { message: 'Success', task: result } };
} catch (error) {
return { statusCode: 500, body: { message: 'Error' } };
}
}
That catch (error) swallows everything. Was it a "task not found"? A database connection failure? A permissions issue? Who knows.
Throwing exceptions for expected failures is like using GOTO. You lose the thread.
Awaitly fixes this by treating errors as data, not explosions. This guide teaches the patterns one concept at a time.
Read More →The OneUptime team is spot on in their Instrument Message Queues with OpenTelemetry post.
Inject trace context on the producer, extract on the consumer; use PRODUCER and CONSUMER span kinds; set semantic conventions (messaging.system, messaging.destination.name, messaging.operation, Kafka partition/offset/consumer group).
They show the raw OpenTelemetry code. It's comprehensive. It's also verbose. Every team ends up re-implementing the same patterns: inject, extract, span kinds, semantic attributes, error handling.
We've all been there: copying "best practice" code from blog posts and adapting it for our broker.
Their key insight:
For batch processing, use a batch span with links or child spans to contributing traces.
But there's still a gap...
Read More →The Signadot team is spot on in their Testing Event-Driven Architectures with OpenTelemetry post.
Message isolation using a shared queue: propagate tenant ID in Kafka message headers; consumers use tenant ID for selective message consumption.
They make the case that infrastructure duplication is expensive. Instead of separate Kafka clusters per environment, use tenant ID filtering on a shared queue. Instrument producers and consumers for context propagation.
We've all been there: maintaining four "identical" Kafka setups that slowly drift apart.
Their key insight:
Requires modifying consumers and using OpenTelemetry for context propagation.
But there's still a gap...
Read More →The CNCF team is spot on in their Testing Asynchronous Workflows using OpenTelemetry and Istio post.
Request-level isolation is the most cost-effective approach.
They make the case against duplicating infrastructure for testing. Instead of spinning up separate Kafka clusters per tenant, use OpenTelemetry Baggage to propagate tenant ID through async flows. Consumers filter by tenant ID. Istio handles routing.
We've all been there: every team has their own "staging Kafka" and costs balloon.
Their key insight:
Use OpenTelemetry Baggage to propagate tenant ID through sync and async. When publishing to Kafka, producers inject trace context (including baggage) into message headers; consumers extract and make routing decisions.
But there's still a gap...
Read More →The OSO team is spot on in their End-to-End Tracing in Event Driven Architectures post.
Traces break at queues unless you extract context from message headers and put it in the appropriate context.
They walk through the real pain: stateful processing loses trace context in caches, Kafka Connect can only do batch-level tracing, and every team ends up writing custom interceptors and state store wrappers.
We've all been there.
Their key insight:
In Kafka Streams and Kafka Connect this often means manual work: interceptors, state stores, batch spans, or extending tracing logic to extract from headers.
But there's still a gap...
Read More →Boris is spot on in his Logging Sucks post
logs are optimised for writing, not querying
He explains why debugging in production feels like archaeology.
You grep for user-123, find it logged 47 different ways, then spend an hour correlating timestamps across services.
We've all been there.
His wide event example nails it:
{
"user": {"id": "user_456", "subscription": "premium", "lifetime_value_cents": 284700},
"cart": {"item_count": 3, "total_cents": 15999, "coupon_applied": "SAVE20"},
"payment": {"method": "card", "provider": "stripe", "latency_ms": 1089},
"error": {"type": "PaymentError", "code": "card_declined", "stripe_decline_code": "insufficient_funds"}
}
One event. High-cardinality keys (user.id, traceId). High dimensionality. Queryable.
But there’s still a gap…
Read More →