Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -473,11 +473,11 @@ var cachedRemoteProxy = Proxy<int, string>.Create(id => remoteProxy.Execute(id))
---

## Patterns Table
PatternKit currently tracks 103 production-readiness patterns. Each catalog pattern is represented in tests, documentation, real-world examples, IoC integration, and the BenchmarkDotNet coverage matrix.
PatternKit currently tracks 104 production-readiness patterns. Each catalog pattern is represented in tests, documentation, real-world examples, IoC integration, and the BenchmarkDotNet coverage matrix.

| Category | Count | Patterns |
| --- | ---: | --- |
| Application Architecture | 18 | Activity Tracker, Aggregate Root, Anti-Corruption Layer, Audit Log, CQRS, Data Mapper, Domain Event, Event Sourcing, Feature Toggle, Identity Map, Materialized View, Repository, Service Layer, Specification, Table Data Gateway, Transaction Script, Unit of Work, Value Object |
| Application Architecture | 19 | Activity Tracker, Aggregate Root, Anti-Corruption Layer, Audit Log, CQRS, Data Mapper, Domain Event, Domain Service, Event Sourcing, Feature Toggle, Identity Map, Materialized View, Repository, Service Layer, Specification, Table Data Gateway, Transaction Script, Unit of Work, Value Object |
| Behavioral | 11 | Chain of Responsibility, Command, Interpreter, Iterator, Mediator, Memento, Observer, State, Strategy, Template Method, Visitor |
| Cloud Architecture | 17 | Ambassador, Backends for Frontends, Bulkhead, Cache-Aside, Circuit Breaker, External Configuration Store, Gateway Aggregation, Gateway Routing, Health Endpoint Monitoring, Leader Election, Priority Queue, Queue-Based Load Leveling, Rate Limiting, Retry, Scheduler Agent Supervisor, Sidecar, Strangler Fig |
| Creational | 5 | Abstract Factory, Builder, Factory Method, Prototype, Singleton |
Expand Down Expand Up @@ -561,6 +561,8 @@ BenchmarkDotNet guidance is documented in [docs/guides/benchmarks.md](docs/guide
| Decorator | Execution | 60.765 ns | 384 B | 35.551 ns | 304 B | Generated decorator execution was faster and allocated less for decorated storage reads. |
| Domain Event | Construction | 199.5 ns | 1.34 KB | 157.6 ns | 1.04 KB | Generated reduced construction time and allocation in this microbenchmark. |
| Domain Event | Execution | 367.2 ns | 1.77 KB | 346.4 ns | 1.55 KB | Generated reduced execution time and allocation for the order-placed dispatch workflow. |
| Domain Service | Construction | Pending | Pending | Pending | Pending | Covered by the BenchmarkDotNet matrix; publish measured values after the next benchmark refresh. |
| Domain Service | Execution | Pending | Pending | Pending | Pending | Covered by the BenchmarkDotNet matrix; publish measured values after the next benchmark refresh. |
| Event-Carried State Transfer | Construction | 7.552 ns | 48 B | 6.751 ns | 48 B | Same allocation; generated was slightly faster in this microbenchmark. |
| Event-Carried State Transfer | Execution | 58.508 ns | 448 B | 59.071 ns | 448 B | Effectively equivalent for the inventory projection workflow. |
| Event Notification | Construction | 30.920 ns | 232 B | 31.926 ns | 232 B | Effectively equivalent for this microbenchmark. |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using BenchmarkDotNet.Attributes;
using PatternKit.Application.DomainServices;
using PatternKit.Examples.DomainServiceDemo;

namespace PatternKit.Benchmarks.Application;

[BenchmarkCategory("ApplicationArchitecture", "DomainService")]
public class DomainServiceBenchmarks
{
private static readonly ShippingDomainServiceDemo.ShippingRequest Request =
ShippingDomainServiceDemo.CreateHighValueRequest();

private readonly DomainServiceRegistry<ShippingDomainServiceDemo.ShippingRequest, ShippingDomainServiceDemo.ShippingDecision> _fluent =
ShippingDomainServiceDemo.CreateFluentRegistry();

private readonly DomainServiceRegistry<ShippingDomainServiceDemo.ShippingRequest, ShippingDomainServiceDemo.ShippingDecision> _generated =
ShippingDomainServiceDemo.CreateGeneratedRegistry();

[Benchmark(Baseline = true, Description = "Fluent: create domain service registry")]
[BenchmarkCategory("Fluent", "Construction")]
public DomainServiceRegistry<ShippingDomainServiceDemo.ShippingRequest, ShippingDomainServiceDemo.ShippingDecision> Fluent_CreateRegistry()
=> ShippingDomainServiceDemo.CreateFluentRegistry();

[Benchmark(Description = "Generated: create domain service registry")]
[BenchmarkCategory("Generated", "Construction")]
public DomainServiceRegistry<ShippingDomainServiceDemo.ShippingRequest, ShippingDomainServiceDemo.ShippingDecision> Generated_CreateRegistry()
=> ShippingDomainServiceDemo.CreateGeneratedRegistry();

[Benchmark(Description = "Fluent: select shipping decision")]
[BenchmarkCategory("Fluent", "Execution")]
public ShippingDomainServiceDemo.ShippingDecision Fluent_SelectBest()
=> ShippingDomainServiceDemo.SelectBest(Request, _fluent);

[Benchmark(Description = "Generated: select shipping decision")]
[BenchmarkCategory("Generated", "Execution")]
public ShippingDomainServiceDemo.ShippingDecision Generated_SelectBest()
=> ShippingDomainServiceDemo.SelectBest(Request, _generated);
}
30 changes: 30 additions & 0 deletions docs/examples/shipping-domain-service-pattern.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Shipping Domain Service Pattern

This example demonstrates a production-style Domain Service for shipping decisions. It includes a fluent operation registry, a source-generated operation registry, TinyBDD tests, and an `IServiceCollection` extension.

## Import

```csharp
using Microsoft.Extensions.DependencyInjection;
using PatternKit.Examples.DomainServiceDemo;

var services = new ServiceCollection();
services.AddShippingDomainServiceDemo();

using var provider = services.BuildServiceProvider(validateScopes: true);
var service = provider.GetRequiredService<ShippingDomainService>();
```

## Use

```csharp
var decision = service.SelectBest(ShippingDomainServiceDemo.CreateHighValueRequest());
```

The service uses a generated `DomainServiceRegistry<ShippingRequest, ShippingDecision>`. The fluent and generated routes share the same carrier and insurance rules so teams can compare runtime and generated composition without changing domain behavior.

## Production Notes

- Keep domain services stateless.
- Keep operation names stable because callers and tests use them as domain vocabulary.
- Register the example with `AddShippingDomainServiceDemo()` or import all examples with `AddPatternKitExamples()`.
3 changes: 3 additions & 0 deletions docs/examples/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,9 @@
- name: Order Aggregate Root Pattern
href: order-aggregate-root-pattern.md

- name: Shipping Domain Service Pattern
href: shipping-domain-service-pattern.md

- name: Order Value Object Pattern
href: order-value-object-pattern.md

Expand Down
43 changes: 43 additions & 0 deletions docs/generators/domain-service.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Domain Service Generator

The Domain Service generator turns annotated static methods into a named `DomainServiceRegistry<TRequest,TResponse>` factory.

## Usage

```csharp
using PatternKit.Generators.DomainServices;

[GenerateDomainServiceRegistry(typeof(ShippingRequest), typeof(ShippingDecision), FactoryMethodName = "Build")]
public static partial class ShippingServices
{
[DomainServiceOperation("insured-air")]
private static ShippingDecision InsuredAir(ShippingRequest request)
=> new(request.OrderId, "air", request.Weight * 3m);
}
```

Generated output:

```csharp
var registry = ShippingServices.Build();
var decision = registry.Execute("insured-air", request);
```

## Operation Shape

Domain service operations must be static methods with this shape:

```csharp
static TResponse Operation(TRequest request)
```

Operation names must be unique within the generated registry.

## Diagnostics

| ID | Meaning |
|---|---|
| `PKDOM001` | Host type must be `partial`. |
| `PKDOM002` | Host type has no `[DomainServiceOperation]` methods. |
| `PKDOM003` | Operation method signature is invalid. |
| `PKDOM004` | Operation name is duplicated. |
3 changes: 3 additions & 0 deletions docs/generators/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@
- name: Domain Event
href: domain-event.md

- name: Domain Service
href: domain-service.md

- name: Event Sourcing
href: event-sourcing.md

Expand Down
18 changes: 11 additions & 7 deletions docs/guides/benchmark-results.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ The latest measured timings below were captured on Windows 11, Intel Core i9-149
| Decorator | Execution | 60.765 ns | 384 B | 35.551 ns | 304 B | Generated decorator execution was faster and allocated less for decorated storage reads. |
| Domain Event | Construction | 199.5 ns | 1.34 KB | 157.6 ns | 1.04 KB | Generated reduced construction time and allocation in this microbenchmark. |
| Domain Event | Execution | 367.2 ns | 1.77 KB | 346.4 ns | 1.55 KB | Generated reduced execution time and allocation for the order-placed dispatch workflow. |
| Domain Service | Construction | Pending | Pending | Pending | Pending | Covered by the BenchmarkDotNet matrix; publish measured values after the next benchmark refresh. |
| Domain Service | Execution | Pending | Pending | Pending | Pending | Covered by the BenchmarkDotNet matrix; publish measured values after the next benchmark refresh. |
| Event-Carried State Transfer | Construction | 7.552 ns | 48 B | 6.751 ns | 48 B | Same allocation; generated was slightly faster in this microbenchmark. |
| Event-Carried State Transfer | Execution | 58.508 ns | 448 B | 59.071 ns | 448 B | Effectively equivalent for the inventory projection workflow. |
| Event Notification | Construction | 30.920 ns | 232 B | 31.926 ns | 232 B | Effectively equivalent for this microbenchmark. |
Expand Down Expand Up @@ -224,19 +226,19 @@ The latest measured timings below were captured on Windows 11, Intel Core i9-149

## Coverage Matrix Summary

The coverage matrix currently publishes 103 catalog patterns and 412 pattern route results. Each pattern has four BenchmarkDotNet routes: fluent construction, fluent execution, source-generated construction, and source-generated execution. The reusable hosting integration matrix publishes 9 reusable hosting integration route results for package-level `IServiceCollection` registrations.
The coverage matrix currently publishes 104 catalog patterns and 416 pattern route results. Each pattern has four BenchmarkDotNet routes: fluent construction, fluent execution, source-generated construction, and source-generated execution. The reusable hosting integration matrix publishes 9 reusable hosting integration route results for package-level `IServiceCollection` registrations.

| Category | Patterns | Published route results |
| --- | ---: | ---: |
| Application Architecture | 18 | 72 |
| Application Architecture | 19 | 76 |
| Behavioral | 11 | 44 |
| Cloud Architecture | 17 | 68 |
| Creational | 5 | 20 |
| Enterprise Integration | 41 | 164 |
| Messaging Reliability | 3 | 12 |
| Structural | 7 | 28 |

The generator matrix currently publishes 98 generator source route results.
The generator matrix currently publishes 99 generator source route results.

## Hosting Integration Matrix Results

Expand All @@ -262,8 +264,9 @@ The generator matrix currently publishes 98 generator source route results.
| Application Architecture | Audit Log | Covered | Covered | Covered | Covered |
| Application Architecture | CQRS | Covered | Covered | Covered | Covered |
| Application Architecture | Data Mapper | Covered | Covered | Covered | Covered |
| Application Architecture | Domain Event | Covered | Covered | Covered | Covered |
| Application Architecture | Event Sourcing | Covered | Covered | Covered | Covered |
| Application Architecture | Domain Event | Covered | Covered | Covered | Covered |
| Application Architecture | Domain Service | Covered | Covered | Covered | Covered |
| Application Architecture | Event Sourcing | Covered | Covered | Covered | Covered |
| Application Architecture | Feature Toggle | Covered | Covered | Covered | Covered |
| Application Architecture | Identity Map | Covered | Covered | Covered | Covered |
| Application Architecture | Materialized View | Covered | Covered | Covered | Covered |
Expand Down Expand Up @@ -383,8 +386,9 @@ The generator matrix currently publishes 98 generator source route results.
| CompositeGenerator | `src/PatternKit.Generators/Composite/CompositeGenerator.cs` | Covered |
| DataMapperGenerator | `src/PatternKit.Generators/DataMapping/DataMapperGenerator.cs` | Covered |
| DecoratorGenerator | `src/PatternKit.Generators/DecoratorGenerator.cs` | Covered |
| DomainEventDispatcherGenerator | `src/PatternKit.Generators/DomainEvents/DomainEventDispatcherGenerator.cs` | Covered |
| EventCarriedStateTransferGenerator | `src/PatternKit.Generators/EventCarriedStateTransfer/EventCarriedStateTransferGenerator.cs` | Covered |
| DomainEventDispatcherGenerator | `src/PatternKit.Generators/DomainEvents/DomainEventDispatcherGenerator.cs` | Covered |
| DomainServiceRegistryGenerator | `src/PatternKit.Generators/DomainServices/DomainServiceRegistryGenerator.cs` | Covered |
| EventCarriedStateTransferGenerator | `src/PatternKit.Generators/EventCarriedStateTransfer/EventCarriedStateTransferGenerator.cs` | Covered |
| EventNotificationGenerator | `src/PatternKit.Generators/EventNotification/EventNotificationGenerator.cs` | Covered |
| EventStoreGenerator | `src/PatternKit.Generators/EventSourcing/EventStoreGenerator.cs` | Covered |
| FacadeGenerator | `src/PatternKit.Generators/FacadeGenerator.cs` | Covered |
Expand Down
2 changes: 2 additions & 0 deletions docs/guides/benchmarks.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ The following numbers were captured on Windows 11, Intel Core i9-14900K, .NET SD
| Decorator | Execution | 60.765 ns | 384 B | 35.551 ns | 304 B | Generated decorator execution was faster and allocated less for decorated storage reads. |
| Domain Event | Construction | 199.5 ns | 1.34 KB | 157.6 ns | 1.04 KB | Generated reduced construction time and allocation in this microbenchmark. |
| Domain Event | Execution | 367.2 ns | 1.77 KB | 346.4 ns | 1.55 KB | Generated reduced execution time and allocation for the order-placed dispatch workflow. |
| Domain Service | Construction | Pending | Pending | Pending | Pending | Covered by the BenchmarkDotNet matrix; publish measured values after the next benchmark refresh. |
| Domain Service | Execution | Pending | Pending | Pending | Pending | Covered by the BenchmarkDotNet matrix; publish measured values after the next benchmark refresh. |
| Event-Carried State Transfer | Construction | 7.552 ns | 48 B | 6.751 ns | 48 B | Same allocation; generated was slightly faster in this microbenchmark. |
| Event-Carried State Transfer | Execution | 58.508 ns | 448 B | 59.071 ns | 448 B | Effectively equivalent for the inventory projection workflow. |
| Event Notification | Construction | 30.920 ns | 232 B | 31.926 ns | 232 B | Effectively equivalent for this microbenchmark. |
Expand Down
1 change: 1 addition & 0 deletions docs/guides/pattern-coverage.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ The source of truth is `PatternKitPatternCatalog` in `src/PatternKit.Examples/Pr
| Application Architecture | Transaction Script | `TransactionScript<TRequest,TResponse>` | Transaction Script generator |
| Application Architecture | Service Layer | `IServiceOperation<TRequest,TResponse>` and `ServiceLayerOperation<TRequest,TResponse>` | Service Layer generator |
| Application Architecture | Domain Event | `IDomainEvent` and `DomainEventDispatcher<TEventBase>` | Domain Event generator |
| Application Architecture | Domain Service | `DomainServiceOperation<TRequest,TResponse>` and named registries | Domain Service generator |
| Application Architecture | Table Data Gateway | `ITableDataGateway<TRow,TKey>` and `InMemoryTableDataGateway<TRow,TKey>` | Table Data Gateway generator |
| Application Architecture | Event Sourcing | `IEventStore<TEvent,TStreamId>` and `InMemoryEventStore<TEvent,TStreamId>` | Event Sourcing generator |
| Application Architecture | Feature Toggle | `IFeatureToggleSet<TContext>` and `FeatureToggleSet<TContext>` | Feature Toggle generator |
Expand Down
4 changes: 2 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@ if (parser.Execute("123", out var value))

## 📚 Available Patterns

PatternKit covers 103 production-readiness patterns with fluent APIs, source-generated routes where applicable, IoC integration examples, TinyBDD coverage, and BenchmarkDotNet coverage-matrix validation:
PatternKit covers 104 production-readiness patterns with fluent APIs, source-generated routes where applicable, IoC integration examples, TinyBDD coverage, and BenchmarkDotNet coverage-matrix validation:

| Category | Count | Patterns |
| --- | ---: | --- |
| Application Architecture | 18 | Activity Tracker, Aggregate Root, Anti-Corruption Layer, Audit Log, CQRS, Data Mapper, Domain Event, Event Sourcing, Feature Toggle, Identity Map, Materialized View, Repository, Service Layer, Specification, Table Data Gateway, Transaction Script, Unit of Work, Value Object |
| Application Architecture | 19 | Activity Tracker, Aggregate Root, Anti-Corruption Layer, Audit Log, CQRS, Data Mapper, Domain Event, Domain Service, Event Sourcing, Feature Toggle, Identity Map, Materialized View, Repository, Service Layer, Specification, Table Data Gateway, Transaction Script, Unit of Work, Value Object |
| Behavioral | 11 | Chain of Responsibility, Command, Interpreter, Iterator, Mediator, Memento, Observer, State, Strategy, Template Method, Visitor |
| Cloud Architecture | 17 | Ambassador, Backends for Frontends, Bulkhead, Cache-Aside, Circuit Breaker, External Configuration Store, Gateway Aggregation, Gateway Routing, Health Endpoint Monitoring, Leader Election, Priority Queue, Queue-Based Load Leveling, Rate Limiting, Retry, Scheduler Agent Supervisor, Sidecar, Strangler Fig |
| Creational | 5 | Abstract Factory, Builder, Factory Method, Prototype, Singleton |
Expand Down
45 changes: 45 additions & 0 deletions docs/patterns/application/domain-service.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Domain Service

Domain Service models stateless domain behavior that does not naturally belong to a single entity or value object.

Use it when a decision spans aggregates, value objects, policies, or external facts while still representing domain logic rather than application orchestration.

## Fluent Path

```csharp
using PatternKit.Application.DomainServices;

var registry = DomainServiceRegistry<ShippingRequest, ShippingDecision>.Create()
.Add("ground", request => new ShippingDecision(request.OrderId, "ground", request.Weight * 1.25m))
.Add("insured-air", request => new ShippingDecision(request.OrderId, "air", request.Weight * 3m))
.Build();

var decision = registry.Execute("insured-air", request);
```

`DomainServiceOperation<TRequest,TResponse>` keeps the operation named and stateless. `DomainServiceRegistry<TRequest,TResponse>` gives application services a stable injected surface.

## Generated Path

```csharp
using PatternKit.Generators.DomainServices;

[GenerateDomainServiceRegistry(typeof(ShippingRequest), typeof(ShippingDecision))]
public static partial class ShippingServices
{
[DomainServiceOperation("ground")]
private static ShippingDecision Ground(ShippingRequest request)
=> new(request.OrderId, "ground", request.Weight * 1.25m);
}
```

The generator emits a registry factory so domain service operation names and signatures are compile-time checked.

## IoC Usage

```csharp
services.AddShippingDomainServiceDemo();
services.AddSingleton<CheckoutWorkflow>();
```

The example in `docs/examples/shipping-domain-service-pattern.md` shows fluent and generated domain services registered through `IServiceCollection`.
2 changes: 2 additions & 0 deletions docs/patterns/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,8 @@
href: application/service-layer.md
- name: Domain Event
href: application/domain-event.md
- name: Domain Service
href: application/domain-service.md
- name: Table Data Gateway
href: application/table-data-gateway.md
- name: Event Sourcing
Expand Down
Loading
Loading