Optima.Net.Domain 3.0.0

Prefix Reserved
There is a newer version of this package available.
See the version list below for details.
dotnet add package Optima.Net.Domain --version 3.0.0
                    
NuGet\Install-Package Optima.Net.Domain -Version 3.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Optima.Net.Domain" Version="3.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Optima.Net.Domain" Version="3.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Optima.Net.Domain" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Optima.Net.Domain --version 3.0.0
                    
#r "nuget: Optima.Net.Domain, 3.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Optima.Net.Domain@3.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Optima.Net.Domain&version=3.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Optima.Net.Domain&version=3.0.0
                    
Install as a Cake Tool

Optima.Net.Domain

Optima.Net.Domain is a lightweight, framework-agnostic toolkit for expressing business rules, decisions, and outcomes in a clear, auditable, and scalable Domain-Driven Design (DDD) style.

It does not try to be a framework. Instead, it provides a small, explicit set of primitives that scale from simple business rules to finance-grade decision systems.

This document is both:

  • a comprehensive reference, and
  • a guided tutorial for engineers new to decision-centric domain modelling.

If you read it top-to-bottom, you should be able to confidently design Specifications, Policies, Diagnostics, and Application flows without burying business logic in if statements.


Table of Contents


Motivation and Mental Model

In many systems, business rules end up:

  • buried in nested if statements,
  • duplicated across services,
  • tightly coupled to infrastructure,
  • or impossible to explain after the fact.

Optima.Net.Domain exists to fix this by making rules and decisions explicit.

Mental Model

Concept Purpose Question Answered
Specification Fact Is this true?
Policy Permission May we proceed?
Diagnostics Explanation Why did this fail?
Application Flow What should happen next?

Each concept has one job.


Core Concepts Overview

Specifications

  • Express facts
  • Pure and side-effect free
  • Independently testable
  • Composable

Policies

  • Express business intent
  • Built from specifications
  • Declare failure semantics
  • Do not orchestrate

Diagnostics

  • Observe evaluation
  • Immutable and structured
  • Explain failures without changing behaviour

Application Layer

  • Coordinates flow
  • Owns retries, compensation, escalation
  • Never enforces business truth

Specifications

A specification answers one factual question.

Example Domain: Orders

public sealed class Order
{
    private readonly List<OrderLine> _lines = new();

    public IReadOnlyCollection<OrderLine> Lines => _lines;
    public decimal Total => _lines.Sum(l => l.Price);

    public void AddLine(OrderLine line) => _lines.Add(line);
}
public sealed class OrderHasLinesSpec : ISpecification<Order>
{
    public bool IsSatisfiedBy(Order order)
        => order.Lines.Any();
}

Each specification:

  • answers one question
  • has no business intent
  • has no side effects

Composite Specifications

Specifications can be composed to express more complex facts.

var discountEligible =
    new OrderHasLinesSpec()
        .And(new OrderTotalExceedsSpec(500m));

Composite specifications are still facts, not decisions.


Policies

A policy declares whether progression is allowed.

public sealed class OrderDiscountPolicy : IPolicy<Order>
{
    private readonly ISpecification<Order> _spec;

    public OrderDiscountPolicy(ISpecification<Order> spec)
    {
        _spec = spec;
    }

    public bool IsSatisfiedBy(Order order)
        => _spec.IsSatisfiedBy(order);

    public PolicyFailureSemantics FailureSemantics
        => PolicyFailureSemantics.Correctable;
}

Policies:

  • do not return results
  • do not create failures
  • do not orchestrate

They declare intent only.


Policy Failure Semantics

Failure semantics describe what is allowed after a failure, not whether something failed.

[Flags]
public enum PolicyFailureSemantics
{
    Terminal     = 0,
    Correctable  = 1 << 0,
    Replaceable  = 1 << 1
}

Examples:

  • Terminal → stop immediately if failed
  • Correctable → user may fix input
  • Replaceable → alternative intent may be proposed

Evaluating Policies

Policies are evaluated using a PolicyDiagnosticEvaluator.

var evaluator = new PolicyDiagnosticEvaluator();

var diagnostic = evaluator.EvaluateAll(
    OrderPolicies.All,
    order);

Policies are evaluated as collections, not composites.


Diagnostics and Failure Projection

Evaluation produces a diagnostic tree.

var failures = diagnostic.GetFailures();

Rules:

  • only failed leaf policies are projected
  • parent/group nodes are never failures
  • failures are immutable facts

End-to-End Example: Password Policy

Specifications:

public sealed class PasswordLengthSpec : ISpecification<string>
{
    public bool IsSatisfiedBy(string password)
        => password.Length >= 12;
}

Policy:

public sealed class PasswordPolicy : IPolicy<string>
{
    private readonly IReadOnlyCollection<ISpecification<string>> _specs;

    public PasswordPolicy(IEnumerable<ISpecification<string>> specs)
    {
        _specs = specs.ToArray();
    }

    public bool IsSatisfiedBy(string password)
        => _specs.All(s => s.IsSatisfiedBy(password));

    public PolicyFailureSemantics FailureSemantics
        => PolicyFailureSemantics.Correctable;
}

End-to-End Example: Credit Approval

public sealed class CreditApprovalPolicy : IPolicy<CreditApplication>
{
    public bool IsSatisfiedBy(CreditApplication app)
        => app.Amount <= 100_000m && !app.HasPriorDefaults;

    public PolicyFailureSemantics FailureSemantics
        => PolicyFailureSemantics.Replaceable;
}

Meaning:

If credit approval fails, an alternative product may be offered.


Advanced Usage Patterns

Multiple semantics

PolicyFailureSemantics.Correctable | PolicyFailureSemantics.Replaceable

Async policies

public sealed class RiskPolicy : IAsyncPolicy<Customer>
{
    public Task<bool> IsSatisfiedByAsync(Customer c, CancellationToken ct)
        => CheckRiskAsync(c, ct);

    public PolicyFailureSemantics FailureSemantics
        => PolicyFailureSemantics.Terminal;
}

Anti-Corruption Layers (ACL)

An ACL protects the domain from foreign models and semantics.

Inbound ACLs translate meaning, not data.

public interface IInboundTranslator<in TForeign, TDomain>
{
    TranslationResult<TDomain> Translate(TForeign input);
}

ACLs:

  • absorb versioning
  • reject ambiguity
  • protect invariants

Application Layer: Use Cases and Sagas

Use Case

public interface IUseCase<in TRequest, out TResult>
{
    TResult Execute(TRequest request);
}

Use cases:

  • coordinate intent
  • call ACLs and policies
  • do not enforce business truth

Saga

public interface ISaga<in TInput>
{
    void Execute(TInput input);
}

Sagas:

  • own retries and compensation
  • handle partial failure
  • never return values

Design Philosophy and Boundaries

Optima.Net.Domain intentionally avoids:

  • rule engines
  • workflow engines
  • infrastructure concerns

Its purpose is singular:

Make domain intent explicit, enforceable, and auditable.

If a rule matters, model it as a specification.
If a decision matters, model it as a policy.
If integration matters, protect it with an ACL.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Optima.Net.Domain:

Package Downloads
Optima.Net.NegotiatR

NegotiatR is a deterministic, single-pass negotiation engine that proposes alternative intents when policies fail. It consumes policy diagnostics, never re-evaluates rules, and guarantees outcomes. Designed for domain-driven systems, it keeps fallback decisions explicit, auditable, and separate from policy evaluation, workflows, and execution logic, without retries or implicit control flow.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
3.1.3 159 1/7/2026
3.1.2 147 12/29/2025
3.1.1 110 12/29/2025
3.1.0 111 12/27/2025
3.0.1 128 12/26/2025
3.0.0 150 12/26/2025
2.0.0 190 12/24/2025
1.0.2 194 12/23/2025
1.0.1 188 12/22/2025
1.0.0 189 12/22/2025

RELEASENOTES.md