Optima.Net.Domain
3.0.0
Prefix Reserved
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
<PackageReference Include="Optima.Net.Domain" Version="3.0.0" />
<PackageVersion Include="Optima.Net.Domain" Version="3.0.0" />
<PackageReference Include="Optima.Net.Domain" />
paket add Optima.Net.Domain --version 3.0.0
#r "nuget: Optima.Net.Domain, 3.0.0"
#:package Optima.Net.Domain@3.0.0
#addin nuget:?package=Optima.Net.Domain&version=3.0.0
#tool nuget:?package=Optima.Net.Domain&version=3.0.0
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
- Core Concepts Overview
- Specifications
- Composite Specifications
- Policies
- Policy Failure Semantics
- Evaluating Policies
- Diagnostics and Failure Projection
- End-to-End Example: Password Policy
- End-to-End Example: Credit Approval
- Advanced Usage Patterns
- Anti-Corruption Layers (ACL)
- Application Layer: Use Cases and Sagas
- Design Philosophy and Boundaries
Motivation and Mental Model
In many systems, business rules end up:
- buried in nested
ifstatements, - 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 | Versions 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. |
-
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.
RELEASENOTES.md