ADR 0002: Standardize on Result / Result<T> for Public APIs

Status

Accepted — 2025-12-15

Context

ManagedCode.Storage targets multiple providers and integration surfaces (core abstractions, ASP.NET controllers, SignalR, client SDKs).

Providers and vendor SDKs typically expose errors via:

We want consumers to handle failures consistently without needing to know each provider’s exception taxonomy.

Problem

If we let exceptions flow through public APIs, we end up with:

Decision

All public storage operations return ManagedCode.Communication.Result / Result<T>:

This yields predictable, provider-agnostic semantics for callers and for integration layers (controllers/hubs/clients).

flowchart LR
  App[Application code] --> API[IStorage public method]
  API --> Provider[Provider implementation]
  Provider -->|success| Ok["Result&lt;T&gt;.Succeed(Value)"]
  Provider -->|exception| Err["Result&lt;T&gt;.Fail(Exception)"]
  Ok --> App
  Err --> App

Alternatives Considered

  1. Throw exceptions from public APIs
    • Pros: “idiomatic” in many .NET libraries; no wrapper allocation.
    • Cons: inconsistent exceptions across providers; hard to map to HTTP; brittle tests.
  2. Return bool/Try* patterns
    • Pros: simple for some operations.
    • Cons: does not carry rich error context; awkward for non-boolean results.
  3. Custom discriminated union / error codes
    • Pros: could provide stable error taxonomy.
    • Cons: larger surface area; more maintenance; still needs exception preservation for diagnostics.

Consequences

Positive

Negative

References (Internal)