Machine Errors and Non-Deterministic Humans

A friendly robot holding onto a railing, illustrating the concept of designing systems that support variable components

“I can’t rely on LLMs because they’re not deterministic. How can I be sure what I’ll get?” — I bet you’ve thought that yourself. I did for sure.

It’s a fair point. LLMs can be unpredictable: the same input can produce different outputs. But here’s the thing: neither are you deterministic, nor am I. A cup of coffee can dramatically improve our “inference.” A bad night’s sleep can tank it. We’re so unpredictable that we have a term for when our variability wreaks havoc: human error.

And when human error happens, we’ve learned not to simply blame the person. Instead, we examine the environment. Why didn’t the system prevent this? We expect systems to withstand human errors, or better yet, prevent them from happening in the first place.

LLMs are made in our likeness. They’re trained on the code, books, and articles we’ve written. So why do we blame them for human errors? Sorry, I meant machine errors.

[Read More]

The Missing Link in Vibe Coding: Feedback Loops

Vibe coding, or as some prefer to call it, “hands-off” software engineering, is having its moment. AI agents write code, implement features, and even spin up entire projects from a prompt. The results are impressive for demos. For production systems, not so much.

The knee-jerk reaction is to blame the models. That was my reaction too. But the problem isn’t the models. It’s what we’re not giving them.

Production-grade code is iterative. No one writes it right on the first attempt. Our profession is built around this fact: code reviews, refactoring, pair programming, testing. Domain-Driven Design makes iterative modeling a first-class concern, because getting the model right requires continuous learning and refinement. We iterate until the code is good enough. Yet when AI doesn’t nail it on the first try, we use it as proof that AI isn’t there yet.

I was in that camp. Then something changed my mind.

[Read More]

Coupling Should Be Weighed, Not Counted

A balance scale where a single heavy weight outweighs many smaller pieces — illustrating that one heavy dependency can matter more than many lightweight ones.

“Words should be weighed, not counted.” — A Yiddish Saying

Static code analysis tools count dependencies, calculate ratios, and assign neat scores. Yet in my experience, chasing those metrics never really made the design more modular. It’s so easy to game the scores without any improvement to the design itself. Let’s see why, and what you can do instead.

The Counting Approach

Most static analysis tools evaluate coupling by counting dependencies. Afferent coupling (Ca) counts how many components depend on yours. Efferent coupling (Ce) counts how many components yours depends on. A popular instability metric combines them into a neat formula:

I = Ce / (Ce + Ca)

The higher the ratio of outgoing to total dependencies, the more “unstable” a component is considered. Simple. Automatable. And deeply misleading.

[Read More]