Failure Is a Feature: Designing for the Unhappy Path

Most applications are designed around the happy path; where we have valid input, fast network responses, and dependencies that behave exactly as expected. We tend to treat failure as an annoying edge case, something to be buried in a try/catch block or ignored because it “shouldn’t ever happen.” But in a modern .NET environment, those assumptions are dangerous. Between flaky APIs, transient network timeouts, and users who will inevitably click the “Submit” button ten times in a row, failure isn’t an accident; it’s a guarantee.

This session is about learning to treat the unhappy path as a core part of your application’s design. We’ll dig into the common points of failure that plague .NET apps and why they shouldn’t all be handled the same way. We’ll look at the trade-offs between using exceptions and functional return types, and how design choices around retries and timeouts can either make your system resilient or just hide a much bigger problem. Our goal is to develop a practical strategy for building systems that fail predictably and recover gracefully, so the next production outage becomes a managed event rather than a total surprise.

Learning Objectives:

  • Recognize why designing only for the happy path is dangerous in modern .NET applications
  • Identify different categories of failure and understand why they require different handling strategies
  • Evaluate when exceptions are appropriate versus when functional return types are a better design choice
  • Design retry and timeout strategies that improve resilience rather than masking deeper issues
  • Adopt a failure-aware mindset that leads to predictable, manageable production behavior

Level: Introductory to Intermediate