Observability-Driven Development
The Shift: Observability as a First-Class Concern
Before vs. After
Before (Observability as Afterthought)
// Write code first
export async function processOrder(orderId: string) {
const order = await db.query('SELECT * FROM orders WHERE id = $1', [orderId]);
const inventory = await checkInventory(order.items);
const payment = await processPayment(order.total);
const shipping = await createShipment(order);
return { success: true };
}
// Add observability later (painful)
export async function processOrder(orderId: string) {
const span = tracer.startSpan('processOrder');
try {
span.setAttribute('order.id', orderId);
const order = await db.query('SELECT * FROM orders WHERE id = $1', [orderId]);
span.setAttribute('order.total', order.total);
// Forgot to add span for this!
const inventory = await checkInventory(order.items);
const paymentSpan = tracer.startSpan('processPayment');
const payment = await processPayment(order.total);
paymentSpan.end();
// This needs its own span too...
const shipping = await createShipment(order);
span.setStatus({ code: SpanStatusCode.OK });
return { success: true };
} catch (error) {
span.setStatus({ code: SpanStatusCode.ERROR });
span.recordException(error);
throw error;
} finally {
span.end();
}
}After (Observability-First)
Design Patterns for Observability
1. Observability Decorators
2. Observable Domain Models
3. Context Propagation Helpers
Testing with Observability
In-Memory Span Exporter for Tests
Trace Assertions
Documentation Through Observability
Self-Documenting Traces
Performance Budgets
Setting SLOs with Metrics
Prometheus Alerting
Real Production Example
Key Takeaways
Conclusion
Last updated