Engineering Principles I Apply to AI Systems
Lessons from classic software engineering that work just as well when you build AI-powered apps.
I build classic software, and lately AI-powered apps too. The tools are new, but the basics have not changed much. The rules that make a classic system reliable still apply. They just show up in new places.
Observability Over Optimism
The biggest mistake I see in AI systems is to treat the model as a black box and hope for the best. Nobody would ship a web service with no logs and no monitoring. AI systems need the same care, and more.
Log every prompt, every response, and every slow call. The logs help with debugging, and they also show you drift over time. Model behavior changes with updates. If you do not watch it, you will only notice when users complain.
async function queryWithObservability(prompt: string) {
const startTime = performance.now();
const traceId = crypto.randomUUID();
try {
const response = await model.generate(prompt);
const latency = performance.now() - startTime;
metrics.record({
traceId,
latency,
tokenCount: response.usage.totalTokens,
promptHash: hashPrompt(prompt),
});
return response;
} catch (error) {
metrics.recordError({ traceId, error });
throw error;
}
}Test the Boundaries, Not Just the Happy Path
Testing an AI system means testing the edges where it breaks. What happens when the input is unclear? When the context window is almost full? When the model returns wrong output with full confidence?
I write strict tests for structured output and evaluation sets for open-ended output. The aim is to find the weak spots before real users do.
Keep the Escape Hatch Open
Every AI feature I build has a backup path that does not use AI. If the model is down, slow, or wrong, the system still works in a simpler way. A fallback is basic engineering.