Defensive Programming Vs Fail Fast · Common pitfalls
1 min readRapid overview
Common pitfalls
❌ Anti-Pattern 1: Overly Defensive Core Logic
// Bad: Hiding bugs with defensive checks in domain logic
public class Order
{
public void SetQuantity(decimal quantity)
{
// Too defensive - silently ignoring invalid input
if (quantity <= 0)
{
_logger.LogWarning("Invalid quantity ignored");
return; // BUG IS HIDDEN!
}
Quantity = quantity;
}
}
// Good: Fail-fast in domain logic
public class Order
{
public void SetQuantity(decimal quantity)
{
if (quantity <= 0)
throw new ArgumentException("Quantity must be positive");
Quantity = quantity;
}
}
❌ Anti-Pattern 2: Fail-Fast at API Boundaries
// Bad: Throwing raw exceptions from controller
[HttpPost]
public IActionResult CreateOrder([FromBody] CreateOrderRequest request)
{
// Too fail-fast - letting exceptions crash through
var order = new Order(request.Symbol, request.Quantity, request.Price);
// ArgumentException crashes the request
return Ok(order);
}
// Good: Defensive at boundary
[HttpPost]
public IActionResult CreateOrder([FromBody] CreateOrderRequest request)
{
try
{
var order = new Order(request.Symbol, request.Quantity, request.Price);
return Ok(order);
}
catch (ArgumentException ex)
{
return BadRequest(ex.Message);
}
}
❌ Anti-Pattern 3: Silent Failures
// Bad: Swallowing exceptions
public decimal CalculatePrice()
{
try
{
return _priceCalculator.Calculate();
}
catch
{
return 0; // Silent failure - debugging nightmare
}
}
// Good: Log and re-throw or handle appropriately
public decimal CalculatePrice()
{
try
{
return _priceCalculator.Calculate();
}
catch (Exception ex)
{
_logger.LogError(ex, "Price calculation failed");
throw new PriceCalculationException("Failed to calculate price", ex);
}
}