Skip to content

Commit 92ed2ed

Browse files
committed
feat: add ports and adapters pattern
1 parent fc97436 commit 92ed2ed

25 files changed

Lines changed: 773 additions & 13 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -473,11 +473,11 @@ var cachedRemoteProxy = Proxy<int, string>.Create(id => remoteProxy.Execute(id))
473473
---
474474

475475
## Patterns Table
476-
PatternKit currently tracks 118 production-readiness patterns. Each catalog pattern is represented in tests, documentation, real-world examples, IoC integration, and the BenchmarkDotNet coverage matrix.
476+
PatternKit currently tracks 119 production-readiness patterns. Each catalog pattern is represented in tests, documentation, real-world examples, IoC integration, and the BenchmarkDotNet coverage matrix.
477477

478478
| Category | Count | Patterns |
479479
| --- | ---: | --- |
480-
| Application Architecture | 27 | Activity Tracker, Aggregate Root, Anti-Corruption Layer, Audit Log, Bounded Context, Context Map, CQRS, Data Mapper, Domain Event, Domain Service, Event Sourcing, Eventual Consistency Monitor, Feature Toggle, Identity Map, Lazy Load, Manual Task Gate, Materialized View, Repository, Service Layer, Snapshot / Checkpoint Management, Specification, Table Data Gateway, Timeout Manager, Transaction Script, Unit of Work, Value Object, Workflow Orchestration |
480+
| Application Architecture | 28 | Activity Tracker, Aggregate Root, Anti-Corruption Layer, Audit Log, Bounded Context, Context Map, CQRS, Data Mapper, Domain Event, Domain Service, Event Sourcing, Eventual Consistency Monitor, Feature Toggle, Identity Map, Lazy Load, Manual Task Gate, Materialized View, Ports and Adapters, Repository, Service Layer, Snapshot / Checkpoint Management, Specification, Table Data Gateway, Timeout Manager, Transaction Script, Unit of Work, Value Object, Workflow Orchestration |
481481
| Behavioral | 12 | Chain of Responsibility, Command, Interpreter, Iterator, Mediator, Memento, Null Object, Observer, State, Strategy, Template Method, Visitor |
482482
| Cloud Architecture | 20 | Ambassador, Backends for Frontends, Bulkhead, Cache-Aside, Cache Stampede Protection, Circuit Breaker, External Configuration Store, Gateway Aggregation, Gateway Routing, Health Endpoint Monitoring, Leader Election, Priority Queue, Queue-Based Load Leveling, Rate Limiting, Read-Through Cache, Retry, Scheduler Agent Supervisor, Sidecar, Strangler Fig, Write-Through Cache |
483483
| Creational | 6 | Abstract Factory, Builder, Factory Method, Object Pool, Prototype, Singleton |
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using BenchmarkDotNet.Attributes;
2+
using PatternKit.Application.PortsAndAdapters;
3+
using PatternKit.Examples.PortsAndAdaptersDemo;
4+
5+
namespace PatternKit.Benchmarks.Application;
6+
7+
[BenchmarkCategory("ApplicationArchitecture", "PortsAndAdapters")]
8+
public class PortsAndAdaptersBenchmarks
9+
{
10+
[Benchmark(Baseline = true, Description = "Fluent: create ports and adapters pipeline")]
11+
[BenchmarkCategory("Fluent", "Construction")]
12+
public PortsAndAdaptersPipeline<OrderEntryHttpRequest, PlaceOrderCommand, PlaceOrderResult, OrderEntryHttpResponse> Fluent_CreatePipeline()
13+
=> OrderEntryPortsAndAdaptersPolicies.CreateFluent(new InMemoryOrderEntryApplicationPort());
14+
15+
[Benchmark(Description = "Generated: create ports and adapters pipeline")]
16+
[BenchmarkCategory("Generated", "Construction")]
17+
public PortsAndAdaptersPipeline<OrderEntryHttpRequest, PlaceOrderCommand, PlaceOrderResult, OrderEntryHttpResponse> Generated_CreatePipeline()
18+
=> GeneratedOrderEntryPortsAndAdapters.CreateGenerated();
19+
20+
[Benchmark(Description = "Fluent: execute ports and adapters pipeline")]
21+
[BenchmarkCategory("Fluent", "Execution")]
22+
public ValueTask<OrderEntryHttpResponse> Fluent_Execute()
23+
=> OrderEntryPortsAndAdaptersPolicies.CreateFluent(new InMemoryOrderEntryApplicationPort())
24+
.ExecuteAsync(new("order-100", "buyer@example.com", 42m));
25+
26+
[Benchmark(Description = "Generated: execute ports and adapters pipeline")]
27+
[BenchmarkCategory("Generated", "Execution")]
28+
public ValueTask<OrderEntryHttpResponse> Generated_Execute()
29+
{
30+
GeneratedOrderEntryPortsAndAdapters.ApplicationPort = new InMemoryOrderEntryApplicationPort();
31+
return GeneratedOrderEntryPortsAndAdapters.CreateGenerated()
32+
.ExecuteAsync(new("order-100", "buyer@example.com", 42m));
33+
}
34+
}

docs/examples/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ Welcome! This section collects small, focused demos that show **how to compose b
5959

6060
* **Customer Profile Lazy Load**
6161
A Generic Host importable deferred profile lookup with fluent and source-generated routes, `IServiceCollection` registration, TTL caching, and invalidation. See [Customer Profile Lazy Load](customer-profile-lazy-load.md).
62+
* **Order Entry Ports and Adapters**
63+
A Generic Host importable hexagonal order-entry flow with fluent and source-generated adapter routes. See [Order Entry Ports and Adapters](order-entry-ports-and-adapters.md).
6264

6365
* **Product Catalog Change Data Capture**
6466
A Generic Host importable mutation capture workflow with fluent and source-generated routes, ordered pending records, and post-commit publication. See [Product Catalog Change Data Capture](product-catalog-change-data-capture.md).
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Order Entry Ports and Adapters
2+
3+
The order entry example maps HTTP-style request records into application commands, calls an application port, and maps the result back to HTTP-style response records. It includes fluent and source-generated factories plus an `AddOrderEntryPortsAndAdaptersDemo` registration method for `IServiceCollection`.

docs/examples/toc.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,9 @@
307307
- name: Product Catalog Cache Stampede Protection
308308
href: product-catalog-cache-stampede-protection.md
309309

310+
- name: Order Entry Ports and Adapters
311+
href: order-entry-ports-and-adapters.md
312+
310313
- name: Product Catalog Read-Through and Write-Through Cache
311314
href: product-catalog-read-write-through-cache.md
312315

docs/generators/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ PatternKit includes a Roslyn incremental generator package (`PatternKit.Generato
7474
| [**Data Mapper**](data-mapper.md) | Domain/data model mapper factories | `[GenerateDataMapper]` |
7575
| [**Identity Map**](identity-map.md) | Scoped object identity caches from key selectors | `[GenerateIdentityMap]` |
7676
| [**Lazy Load**](lazy-load.md) | Deferred value factories with caching, TTL, and invalidation | `[GenerateLazyLoad]` |
77+
| [**Ports and Adapters**](ports-and-adapters.md) | Hexagonal inbound adapters, application ports, and outbound adapters | `[GeneratePortsAndAdapters]` |
7778
| [**Materialized View**](materialized-view.md) | Event projection read-model factories from handlers | `[GenerateMaterializedView]` |
7879
| [**Transaction Script**](transaction-script.md) | Typed application workflow factories | `[GenerateTransactionScript]` |
7980
| [**Service Layer**](service-layer.md) | Application operation boundary factories | `[GenerateServiceLayerOperation]` |
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Ports and Adapters Generator
2+
3+
Annotate a partial host with `[GeneratePortsAndAdapters]` and mark one inbound adapter, one application port, and one outbound adapter.
4+
5+
```csharp
6+
[GeneratePortsAndAdapters(typeof(HttpRequest), typeof(Command), typeof(Result), typeof(HttpResponse))]
7+
public static partial class OrderEntry
8+
{
9+
[InboundAdapter]
10+
private static Command Inbound(HttpRequest request) => new(request.Id);
11+
12+
[ApplicationPort]
13+
private static ValueTask<Result> Handle(Command command, CancellationToken ct) => new(new(command.Id));
14+
15+
[OutboundAdapter]
16+
private static HttpResponse Outbound(Result result) => new(202, result.Id);
17+
}
18+
```
19+
20+
The generated `Create()` factory returns a `PortsAndAdaptersPipeline<TInbound,TCommand,TResult,TOutbound>`.

docs/generators/toc.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,9 @@
312312
- name: Service Layer
313313
href: service-layer.md
314314

315+
- name: Ports and Adapters
316+
href: ports-and-adapters.md
317+
315318
- name: Visitor Generator
316319
href: visitor-generator.md
317320

docs/guides/benchmark-results.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ The latest measured timings below were captured on Windows 11, Intel Core i9-149
5353
| Backpressure | Execution | Pending | Pending | Pending | Pending | Covered by the BenchmarkDotNet matrix; publish measured values after the next benchmark refresh. |
5454
| Lazy Load | Construction | Pending | Pending | Pending | Pending | Covered by the BenchmarkDotNet matrix; publish measured values after the next benchmark refresh. |
5555
| Lazy Load | Execution | Pending | Pending | Pending | Pending | Covered by the BenchmarkDotNet matrix; publish measured values after the next benchmark refresh. |
56+
| Ports and Adapters | Construction | Pending | Pending | Pending | Pending | Covered by the BenchmarkDotNet matrix; publish measured values after the next benchmark refresh. |
57+
| Ports and Adapters | Execution | Pending | Pending | Pending | Pending | Covered by the BenchmarkDotNet matrix; publish measured values after the next benchmark refresh. |
5658
| Cache Stampede Protection | Construction | Pending | Pending | Pending | Pending | Covered by the BenchmarkDotNet matrix; publish measured values after the next benchmark refresh. |
5759
| Cache Stampede Protection | Execution | Pending | Pending | Pending | Pending | Covered by the BenchmarkDotNet matrix; publish measured values after the next benchmark refresh. |
5860
| Cache-Aside | Construction | 19.91 ns | 200 B | 19.85 ns | 200 B | Effectively equivalent for this microbenchmark. |
@@ -258,19 +260,19 @@ The latest measured timings below were captured on Windows 11, Intel Core i9-149
258260

259261
## Coverage Matrix Summary
260262

261-
The coverage matrix currently publishes 118 catalog patterns and 472 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 12 reusable hosting integration route results for package-level `IServiceCollection` registrations.
263+
The coverage matrix currently publishes 119 catalog patterns and 476 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 12 reusable hosting integration route results for package-level `IServiceCollection` registrations.
262264

263265
| Category | Patterns | Published route results |
264266
| --- | ---: | ---: |
265-
| Application Architecture | 27 | 108 |
267+
| Application Architecture | 28 | 112 |
266268
| Behavioral | 12 | 48 |
267269
| Cloud Architecture | 20 | 80 |
268270
| Creational | 6 | 24 |
269271
| Enterprise Integration | 42 | 168 |
270272
| Messaging Reliability | 4 | 16 |
271273
| Structural | 7 | 28 |
272274

273-
The generator matrix currently publishes 113 generator source route results.
275+
The generator matrix currently publishes 114 generator source route results.
274276

275277
## Hosting Integration Matrix Results
276278

@@ -313,7 +315,8 @@ The generator matrix currently publishes 113 generator source route results.
313315
| Application Architecture | Identity Map | Covered | Covered | Covered | Covered |
314316
| Application Architecture | Lazy Load | Covered | Covered | Covered | Covered |
315317
| Application Architecture | Materialized View | Covered | Covered | Covered | Covered |
316-
| Application Architecture | Repository | Covered | Covered | Covered | Covered |
318+
| Application Architecture | Ports and Adapters | Covered | Covered | Covered | Covered |
319+
| Application Architecture | Repository | Covered | Covered | Covered | Covered |
317320
| Application Architecture | Service Layer | Covered | Covered | Covered | Covered |
318321
| Application Architecture | Specification | Covered | Covered | Covered | Covered |
319322
| Application Architecture | Value Object | Covered | Covered | Covered | Covered |
@@ -515,9 +518,10 @@ The generator matrix currently publishes 113 generator source route results.
515518
| RateLimitPolicyGenerator | `src/PatternKit.Generators/RateLimiting/RateLimitPolicyGenerator.cs` | Covered |
516519
| RepositoryGenerator | `src/PatternKit.Generators/Repository/RepositoryGenerator.cs` | Covered |
517520
| RetryPolicyGenerator | `src/PatternKit.Generators/Retry/RetryPolicyGenerator.cs` | Covered |
518-
| SchedulerAgentSupervisorGenerator | `src/PatternKit.Generators/SchedulerAgentSupervisor/SchedulerAgentSupervisorGenerator.cs` | Covered |
519-
| ServiceLayerOperationGenerator | `src/PatternKit.Generators/ServiceLayer/ServiceLayerOperationGenerator.cs` | Covered |
520-
| SidecarGenerator | `src/PatternKit.Generators/Sidecar/SidecarGenerator.cs` | Covered |
521+
| SchedulerAgentSupervisorGenerator | `src/PatternKit.Generators/SchedulerAgentSupervisor/SchedulerAgentSupervisorGenerator.cs` | Covered |
522+
| ServiceLayerOperationGenerator | `src/PatternKit.Generators/ServiceLayer/ServiceLayerOperationGenerator.cs` | Covered |
523+
| PortsAndAdaptersGenerator | `src/PatternKit.Generators/PortsAndAdapters/PortsAndAdaptersGenerator.cs` | Covered |
524+
| SidecarGenerator | `src/PatternKit.Generators/Sidecar/SidecarGenerator.cs` | Covered |
521525
| SingletonGenerator | `src/PatternKit.Generators/Singleton/SingletonGenerator.cs` | Covered |
522526
| SpecificationGenerator | `src/PatternKit.Generators/Specification/SpecificationGenerator.cs` | Covered |
523527
| ValueObjectGenerator | `src/PatternKit.Generators/ValueObjects/ValueObjectGenerator.cs` | Covered |

docs/index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,11 @@ if (parser.Execute("123", out var value))
6666

6767
## 📚 Available Patterns
6868

69-
PatternKit covers 118 production-readiness patterns with fluent APIs, source-generated routes where applicable, IoC integration examples, TinyBDD coverage, and BenchmarkDotNet coverage-matrix validation:
69+
PatternKit covers 119 production-readiness patterns with fluent APIs, source-generated routes where applicable, IoC integration examples, TinyBDD coverage, and BenchmarkDotNet coverage-matrix validation:
7070

7171
| Category | Count | Patterns |
7272
| --- | ---: | --- |
73-
| Application Architecture | 27 | Activity Tracker, Aggregate Root, Anti-Corruption Layer, Audit Log, Bounded Context, Context Map, CQRS, Data Mapper, Domain Event, Domain Service, Event Sourcing, Eventual Consistency Monitor, Feature Toggle, Identity Map, Lazy Load, Manual Task Gate, Materialized View, Repository, Service Layer, Snapshot / Checkpoint Management, Specification, Table Data Gateway, Timeout Manager, Transaction Script, Unit of Work, Value Object, Workflow Orchestration |
73+
| Application Architecture | 28 | Activity Tracker, Aggregate Root, Anti-Corruption Layer, Audit Log, Bounded Context, Context Map, CQRS, Data Mapper, Domain Event, Domain Service, Event Sourcing, Eventual Consistency Monitor, Feature Toggle, Identity Map, Lazy Load, Manual Task Gate, Materialized View, Ports and Adapters, Repository, Service Layer, Snapshot / Checkpoint Management, Specification, Table Data Gateway, Timeout Manager, Transaction Script, Unit of Work, Value Object, Workflow Orchestration |
7474
| Behavioral | 12 | Chain of Responsibility, Command, Interpreter, Iterator, Mediator, Memento, Null Object, Observer, State, Strategy, Template Method, Visitor |
7575
| Cloud Architecture | 20 | Ambassador, Backends for Frontends, Bulkhead, Cache-Aside, Cache Stampede Protection, Circuit Breaker, External Configuration Store, Gateway Aggregation, Gateway Routing, Health Endpoint Monitoring, Leader Election, Priority Queue, Queue-Based Load Leveling, Rate Limiting, Read-Through Cache, Retry, Scheduler Agent Supervisor, Sidecar, Strangler Fig, Write-Through Cache |
7676
| Creational | 6 | Abstract Factory, Builder, Factory Method, Object Pool, Prototype, Singleton |

0 commit comments

Comments
 (0)