Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
8 changes: 4 additions & 4 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<Project>
<PropertyGroup>
<PropertyGroup Condition="'$(MSBuildProjectFile)' != 'BenchmarkDotNet.Autogenerated.csproj'">
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;net9.0;net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
Expand All @@ -11,7 +11,7 @@
<NoWarn>$(NoWarn);1591</NoWarn>
Comment on lines 2 to 11
</PropertyGroup>

<PropertyGroup>
<PropertyGroup Condition="'$(MSBuildProjectFile)' != 'BenchmarkDotNet.Autogenerated.csproj'">
<Authors>Jerrett Davis and contributors</Authors>
<Company>JDH Productions LLC.</Company>
<Product>PatternKit</Product>
Expand All @@ -36,14 +36,14 @@
</PropertyGroup>


<PropertyGroup>
<PropertyGroup Condition="'$(MSBuildProjectFile)' != 'BenchmarkDotNet.Autogenerated.csproj'">
<IsPackable>false</IsPackable>
<IsPackable Condition="$([System.String]::Copy('$(MSBuildProjectName)').EndsWith('.Tests'))">false</IsPackable>
<IsPackable Condition="$([System.String]::Copy('$(MSBuildProjectName)').StartsWith('PatternKit'))">true</IsPackable>
</PropertyGroup>


<ItemGroup>
<ItemGroup Condition="'$(MSBuildProjectFile)' != 'BenchmarkDotNet.Autogenerated.csproj'">
<None Include="$(MSBuildThisFileDirectory)README.md" Pack="true" PackagePath="\"/>

<None Include="$(MSBuildThisFileDirectory)docs/images/tiny.png"
Expand Down
33 changes: 28 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -446,8 +446,31 @@ var cachedRemoteProxy = Proxy<int, string>.Create(id => remoteProxy.Execute(id))
---

## Patterns Table
| Category | Patterns |
| -------------- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **Creational** | [Factory](docs/patterns/creational/factory/factory.md) • [Composer](docs/patterns/creational/builder/composer.md) • [ChainBuilder](docs/patterns/creational/builder/chainbuilder.md) • [BranchBuilder](docs/patterns/creational/builder/branchbuilder.md) • [MutableBuilder](docs/patterns/creational/builder/mutablebuilder.md) • [Prototype](docs/patterns/creational/prototype/prototype.md) • [Singleton](docs/patterns/creational/singleton/singleton.md) |
| **Structural** | [Adapter](docs/patterns/structural/adapter/fluent-adapter.md) • [Bridge](docs/patterns/structural/bridge/bridge.md) • [Composite](docs/patterns/structural/composite/composite.md) • [Decorator](docs/patterns/structural/decorator/decorator.md) • [Facade](docs/patterns/structural/facade/index.md) • [Flyweight](docs/patterns/structural/flyweight/index.md) • [Proxy](docs/patterns/structural/proxy/index.md) |
| **Behavioral** | [Strategy](docs/patterns/behavioral/strategy/strategy.md) • [TryStrategy](docs/patterns/behavioral/strategy/trystrategy.md) • [ActionStrategy](docs/patterns/behavioral/strategy/actionstrategy.md) • [ActionChain](docs/patterns/behavioral/chain/actionchain.md) • [ResultChain](docs/patterns/behavioral/chain/resultchain.md) • [ReplayableSequence](docs/patterns/behavioral/iterator/replayablesequence.md) • [WindowSequence](docs/patterns/behavioral/iterator/windowsequence.md) • [Command](docs/patterns/behavioral/command/command.md) • [Mediator](docs/patterns/behavioral/mediator/mediator.md) • [Memento](docs/patterns/behavioral/memento/memento.md) • [Observer](docs/patterns/behavioral/observer/observer.md) • [State](docs/patterns/behavioral/state/state.md) • [Template Method](docs/patterns/behavioral/template/template.md) • [Visitor](docs/patterns/behavioral/visitor/visitor.md) |
PatternKit currently tracks 88 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 | 15 | 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 |
| 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 |
| Enterprise Integration | 30 | Aggregator, Canonical Data Model, Channel Adapter, Claim Check, Competing Consumers, Content-Based Router, Control Bus, Dead Letter Channel, Event Notification, Event-Carried State Transfer, Event-Driven Consumer, Mailbox, Message Channel, Message Envelope, Message Filter, Message Store, Message Translator, Messaging Gateway, Pipes and Filters, Polling Consumer, Publish-Subscribe, Recipient List, Request-Reply, Resequencer, Routing Slip, Saga / Process Manager, Scatter-Gather, Service Activator, Splitter, Wire Tap |
| Messaging Reliability | 3 | Idempotent Receiver, Inbox, Outbox |
| Structural | 7 | Adapter, Bridge, Composite, Decorator, Facade, Flyweight, Proxy |
Comment on lines +453 to +459

## Benchmark Snapshot

BenchmarkDotNet results are documented in [docs/guides/benchmarks.md](docs/guides/benchmarks.md). This snapshot was captured on Windows 11, Intel Core i9-14900K, .NET SDK 10.0.108, .NET 10.0.8, BenchmarkDotNet 0.15.8, using the `current-tfm` job.

| Pattern | Phase | Fluent mean | Fluent allocation | Generated mean | Generated allocation | Read |
| --- | --- | ---: | ---: | ---: | ---: | --- |
| Leader Election | Construction | 14.28 ns | 104 B | 15.91 ns | 104 B | Same allocation; fluent was slightly faster in this microbenchmark. |
| Leader Election | Execution | 43.62 ns | 360 B | 144.37 ns | 312 B | Generated allocated about 13% less memory, while fluent was faster in this path. |
| Scheduler Agent Supervisor | Construction | 47.29 ns | 400 B | 45.40 ns | 400 B | Same allocation; generated was slightly faster in this microbenchmark. |
| Scheduler Agent Supervisor | Execution | 177.46 ns | 1,304 B | 180.14 ns | 1,304 B | Effectively equivalent for this scenario. |
Comment on lines +465 to +470

Comment on lines +463 to +471
Run the benchmarks on target hardware before making final route decisions:

```powershell
dotnet run -c Release --framework net10.0 --project benchmarks/PatternKit.Benchmarks -- --filter *LeaderElection* --artifacts artifacts/benchmarks --join
```
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
<ProjectReference Include="..\..\src\PatternKit.Generators.Abstractions\PatternKit.Generators.Abstractions.csproj" />
<ProjectReference Include="..\..\src\PatternKit.Generators\PatternKit.Generators.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false"
AdditionalProperties="TargetFramework=netstandard2.0" />
ReferenceOutputAssembly="false" />
</ItemGroup>
</Project>
7 changes: 5 additions & 2 deletions benchmarks/PatternKit.Benchmarks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ This project contains reportable BenchmarkDotNet comparisons for PatternKit flue
Run the full benchmark suite from the repository root:

```powershell
dotnet run -c Release --project benchmarks/PatternKit.Benchmarks -- --artifacts artifacts/benchmarks
dotnet run -c Release --framework net10.0 --project benchmarks/PatternKit.Benchmarks -- --artifacts artifacts/benchmarks --join
```

Run one pattern family:

```powershell
dotnet run -c Release --project benchmarks/PatternKit.Benchmarks -- --filter *LeaderElection* --artifacts artifacts/benchmarks
dotnet run -c Release --framework net10.0 --project benchmarks/PatternKit.Benchmarks -- --filter *LeaderElection* --artifacts artifacts/benchmarks --join
```
Comment on lines 7 to 15

Every pattern-specific scenario benchmark class must:
Expand All @@ -26,3 +26,6 @@ Coverage matrix benchmarks under `Coverage/` include every pattern from `Pattern
source file from `src/PatternKit.Generators`. The TinyBDD production-readiness tests fail when a catalog pattern or generator
is missing from that matrix. Pattern-specific benchmarks can then add deeper scenario timing while the matrix keeps top-to-bottom
coverage complete.

Published benchmark snapshots live in `docs/guides/benchmarks.md` so users can compare fluent and source-generated timing,
overhead, and allocation without running the suite first.
23 changes: 21 additions & 2 deletions docs/guides/benchmarks.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,34 @@ The benchmark suite is structured around fluent-vs-source-generated comparisons.
Run all benchmarks:

```powershell
dotnet run -c Release --project benchmarks/PatternKit.Benchmarks -- --artifacts artifacts/benchmarks
dotnet run -c Release --framework net10.0 --project benchmarks/PatternKit.Benchmarks -- --artifacts artifacts/benchmarks --join
```

Run a single pattern:

```powershell
dotnet run -c Release --project benchmarks/PatternKit.Benchmarks -- --filter *SchedulerAgentSupervisor* --artifacts artifacts/benchmarks
dotnet run -c Release --framework net10.0 --project benchmarks/PatternKit.Benchmarks -- --filter *SchedulerAgentSupervisor* --artifacts artifacts/benchmarks --join
```
Comment on lines 9 to 17

Benchmark output should be reviewed as part of pattern hardening work. When a pattern has both fluent and generated APIs, the benchmark must include both routes with categories for the pattern family, pattern name, route, and phase.

The benchmark suite also includes coverage matrix benchmarks for every pattern in the production-readiness catalog and every source generator under `src/PatternKit.Generators`. Those matrix benchmarks are validated by TinyBDD tests so a new pattern or generator cannot be added without appearing in BenchmarkDotNet output.

## Latest Snapshot

The following numbers were captured on Windows 11, Intel Core i9-14900K, .NET SDK 10.0.108, .NET 10.0.8, BenchmarkDotNet 0.15.8, using the `current-tfm` job. Treat them as directional route guidance; run the suite on deployment-class hardware when the difference matters.

| Pattern | Phase | Fluent mean | Fluent allocation | Generated mean | Generated allocation | Decision signal |
| --- | --- | ---: | ---: | ---: | ---: | --- |
| Leader Election | Construction | 14.28 ns | 104 B | 15.91 ns | 104 B | Same allocation; fluent was slightly faster in this microbenchmark. |
| Leader Election | Execution | 43.62 ns | 360 B | 144.37 ns | 312 B | Generated allocated about 13% less memory, while fluent was faster in this path. |
| Scheduler Agent Supervisor | Construction | 47.29 ns | 400 B | 45.40 ns | 400 B | Same allocation; generated was slightly faster in this microbenchmark. |
| Scheduler Agent Supervisor | Execution | 177.46 ns | 1,304 B | 180.14 ns | 1,304 B | Effectively equivalent for this scenario. |

The coverage matrix is separate from the scenario timings. Matrix benchmarks prove every catalog pattern and every generator source file has a reportable BenchmarkDotNet route; pattern-specific scenario benchmarks provide the fluent-vs-generated construction and execution numbers shown above.

## Interpreting Results

Use construction benchmarks to decide whether source-generated setup meaningfully reduces startup or registration overhead. Use execution benchmarks for hot-path decisions. Allocation columns are often the stronger signal for throughput services because lower allocation reduces GC pressure even when mean time is close.

For source generators, also consider maintainability and deployment shape: generated routes remove runtime boilerplate and make registration explicit, while fluent routes are often faster to read and adjust during application composition.
Loading
Loading