Four patterns that replace most of the try-catch in your codebase and the mental model that makes the right choice obvious. Every developer has written this code. You’re building something, you get a compiler warning, or maybe a runtime blow-up in testing, and the fastest fix feels obvious: wrap it. Slap a try-catch around it, log the message, return null, move on. Done. Safe. Except it isn’t safe. You’ve just installed a smoke detector that beeps once and then goes quiet forever. I’ve been inside codebases where try-catch was the default answer to every uncomfortable question the compiler asked. Controllers wrapped in it. Services wrapped in it. Utility methods wrapped in it. The team described it as “defensive programming.” What it actually was: a distributed system of silence. Errors happened. Nobody knew. The first sign of a problem was usually a customer email. There’s a reason tutorials teach try-catch first. It works , in the narrowest possible sense. The app doesn’t crash. The stack trace disappears.…