Screenshot 2025-09-10 101500.png

A subtle problem in using the decorator pattern

#dotnet #decoratorpattern #designpatterns

❔ What’s the issue?

 In .NET, decorators are commonly used to add caching and logging to services. It’s a clean way to separate concerns—but there’s a subtle problem: the order of decorators affects behavior and observability.  For example, if logging wraps caching, the logger might record a successful operation that was actually served from cache. It doesn’t know the call was short-circuited—it just sees the result.  Reverse the order, and now cache-related events (hits, misses, failures) may never get logged at all.

Why does this matter?

 It quietly breaks observability. You lose insight into what’s actually happening under the hood, and debugging becomes guesswork. Especially with caching, where silent failures or unexpected behavior can be notoriously hard to trace.

How to approach it?

  • Revisit SRP pragmatically per each decorator. Adding cache-specific logging inside the caching service may feel messy, but it’s still a single reason to change: caching logic.

  • Be intentional with decorator order. Document it, test it—don’t treat it as interchangeable.

  • Separate logging concerns. Cache decorators should log cache events; business decorators should log domain events.

  • Watch for decorator stacking. It can obscure complexity and make debugging harder.

  • Consider alternatives. For more advanced scenarios, AOP or DI interceptors may offer better control and transparency.

This isn’t a groundbreaking insight - but it’s one of those quiet issues that can cost hours when it’s overlooked. Worth keeping in mind when layering decorators in production (or personal) code.

Sources:

https://github.com/MarcinSredzinski/DecoratorUsageExample.Api