본문으로 건너뛰기

유스케이스 파이프라인 제약

C# 제네릭 변성에서 Mediator Pipeline 제약 해결까지 실전 가이드


Fin<T>는 sealed struct라 제약 조건으로 사용할 수 없습니다. Mediator Pipeline에서 리플렉션 없이 타입 안전한 응답 처리를 하려면 — 이 한 줄의 제약을 우회하는 인터페이스 계층 설계가 필요합니다.

이 튜토리얼은 C# 제네릭 변성(공변성/반공변성)의 기초에서 시작하여, IFinResponse 인터페이스 계층을 직접 설계하고 Pipeline 제약을 적용하기까지의 과정을 단계별로 학습할 수 있도록 구성된 실전 가이드입니다. 20개의 실습 프로젝트를 통해 변성 기초 → Fin<T> 한계 → IFinResponse 계층 → Pipeline 제약 → 실전 Usecase까지 체계적으로 학습할 수 있습니다.

Fin<T>는 sealed struct라 제약 조건으로 사용할 수 없다 — 이 한 줄의 제약에서 시작된 IFinResponse 인터페이스 계층 설계의 모든 과정을 함께 경험해보세요.

수준대상권장 학습 범위
초급C# 기본 문법을 알고 제네릭 변성에 입문하려는 개발자Part 1
중급Mediator Pipeline과 타입 제약 설계에 관심 있는 개발자Part 1~3
고급Pipeline 아키텍처와 함수형 패턴을 실전에 적용하려는 개발자Part 4~5 + 부록

이 튜토리얼을 완료하면 다음을 할 수 있습니다:

  1. C# 제네릭 변성(공변성, 반공변성, 불변성)의 원리와 적용 조건을 이해
  2. sealed struct의 제약 한계와 인터페이스 계층으로 우회하는 설계 패턴 습득
  3. IFinResponse 인터페이스 계층을 직접 설계하고 CRTP 팩토리 패턴 구현
  4. Pipeline별 최소 제약 조건을 설계하여 리플렉션 없는 타입 안전한 Pipeline 구축
  5. Command/Query Usecase에서 FinResponse 기반 전체 Pipeline 흐름 통합

타입 안전한 파이프라인이 왜 필요한지, 전체 아키텍처의 개요를 소개합니다.

C# 제네릭 변성의 핵심 개념을 코드로 학습합니다.

주제핵심 학습 내용
1공변성 (out)IEnumerable<out T>, 출력 위치, Dog→Animal 대입
2반공변성 (in)Action<in T>, IHandler<in T>, 핸들러 대체
3불변성과 제약List<T> 불변, sealed struct 제약 불가, where 제약
4인터페이스 분리와 변성 조합읽기(out)/쓰기(in)/팩토리 분리, ISP+변성

Part 2: 문제 정의 — Fin과 Mediator 충돌

섹션 제목: “Part 2: 문제 정의 — Fin과 Mediator 충돌”

Fin<T> sealed struct와 Mediator Pipeline의 제약 충돌 문제를 분석합니다.

주제핵심 학습 내용
1Mediator Pipeline Behavior 구조IPipelineBehavior, MessageHandlerDelegate, 제약 역할
2Fin<T> 직접 사용의 한계sealed struct 제약 불가, 리플렉션 3곳 필요
3IFinResponse 래퍼의 한계이중 인터페이스, 리플렉션 1곳, CreateFail 불가
4요구사항 정리4가지 요구사항, Pipeline별 필요 능력 매트릭스

Part 3: 해결 — IFinResponse 계층 설계

섹션 제목: “Part 3: 해결 — IFinResponse 계층 설계”

리플렉션 없이 타입 안전한 Pipeline을 가능하게 하는 IFinResponse 인터페이스 계층을 직접 설계합니다.

주제핵심 학습 내용
1IFinResponse 비제네릭 마커IsSucc/IsFail, Pipeline 읽기 전용 접근
2IFinResponse<out A> 공변 인터페이스out 적용, 공변적 Pipeline 접근
3IFinResponseFactory CRTP 팩토리static abstract, CRTP, CreateFail
4IFinResponseWithError 에러 접근Error 속성, Fail에만 구현, 패턴 매칭
5FinResponse<A> Discriminated UnionSucc/Fail sealed records, Match/Map/Bind, 암시적 변환

IFinResponse 계층을 활용하여 각 Pipeline에 최소 제약 조건을 적용합니다.

주제핵심 학습 내용
1Create-Only 제약where TResponse : IFinResponseFactory<TResponse>
2Read+Create 제약where TResponse : IFinResponse, IFinResponseFactory<TResponse>
3Transaction/Caching PipelineCommand/Query 분기, ICacheable 조건부
4Fin → FinResponse 브릿지ToFinResponse() 확장 메서드, 계층 간 변환

전체 Pipeline을 통합한 Command/Query Usecase 완전 예제입니다.


[Part 1] 제네릭 변성 기초 1장: 공변성 (out) → 2장: 반공변성 (in) → 3장: 불변성과 제약 → 4장: 인터페이스 분리와 변성 조합

[Part 2] 문제 정의 — Fin과 Mediator 충돌 1장: Mediator Pipeline Behavior 구조 → 2장: Fin<T> 직접 사용의 한계 → 3장: IFinResponse 래퍼의 한계 → 4장: 요구사항 정리

[Part 3] IFinResponse 계층 설계 1장: IFinResponse 비제네릭 마커 → 2장: IFinResponse<out A> 공변 인터페이스 → 3장: IFinResponseFactory CRTP 팩토리 → 4장: IFinResponseWithError 에러 접근 → 5장: FinResponse<A> Discriminated Union

[Part 4] Pipeline 제약 패턴 적용 1장: Create-Only 제약 → 2장: Read+Create 제약 → 3장: Transaction/Caching Pipeline → 4장: Fin → FinResponse 브릿지

[Part 5] 실전 Usecase 예제 1장: Command Usecase 완전 예제 → 2장: Query Usecase 완전 예제 → 3장: Pipeline 전체 흐름 통합


IFinResponse 비제네릭 마커 (IsSucc/IsFail)
├── IFinResponse<out A> 공변 인터페이스 (읽기 전용)
IFinResponseFactory<TSelf> CRTP 팩토리 (CreateFail)
IFinResponseWithError 에러 접근 (Error 속성)
FinResponse<A> Discriminated Union
├── : IFinResponse<A> 공변 인터페이스 구현
├── : IFinResponseFactory<FinResponse<A>> CRTP 팩토리 구현
├── sealed record Succ(A Value) 성공 케이스
└── sealed record Fail(Error Error) 실패 케이스
└── : IFinResponseWithError Fail에서만 에러 접근
Pipeline TResponse 제약 조건 능력
────────────────────────── ───────────────────────────────────── ────────────
Metrics Pipeline IFinResponse, IFinResponseFactory<...> Read + Create
Tracing Pipeline IFinResponse, IFinResponseFactory<...> Read + Create
Logging Pipeline IFinResponse, IFinResponseFactory<...> Read + Create
Validation Pipeline IFinResponseFactory<TResponse> CreateFail
Caching Pipeline IFinResponse, IFinResponseFactory<...> Read + Create
Exception Pipeline IFinResponseFactory<TResponse> CreateFail
Transaction Pipeline IFinResponse, IFinResponseFactory<...> Read + Create
Custom Pipeline (사용자 정의) Varies

  • .NET 10.0 SDK 이상
  • VS Code + C# Dev Kit 확장
  • C# 기초 문법 지식
  • 제네릭 기초 개념 (타입 파라미터, where 제약)

usecase-pipeline/
├── Part0-Introduction/ # Part 0: 서론 (3개)
├── Part1-Generic-Variance-Foundations/ # Part 1: 제네릭 변성 기초 (4개)
│ ├── 01-Covariance/
│ ├── 02-Contravariance/
│ ├── 03-Invariance-And-Constraints/
│ └── 04-Interface-Segregation-And-Variance/
├── Part2-Problem-Definition/ # Part 2: 문제 정의 (4개)
│ ├── 01-Mediator-Pipeline-Structure/
│ ├── 02-Fin-Direct-Limitation/
│ ├── 03-IFinResponse-Wrapper-Limitation/
│ └── 04-pipeline-requirements-summary.md
├── Part3-IFinResponse-Hierarchy/ # Part 3: IFinResponse 계층 (5개)
│ ├── 01-IFinResponse-Marker/
│ ├── 02-IFinResponse-Covariant/
│ ├── 03-IFinResponseFactory-CRTP/
│ ├── 04-IFinResponseWithError/
│ └── 05-FinResponse-Discriminated-Union/
├── Part4-Pipeline-Constraint-Patterns/ # Part 4: Pipeline 제약 (4개)
│ ├── 01-Create-Only-Constraint/
│ ├── 02-Read-Create-Constraint/
│ ├── 03-Transaction-Caching-Pipeline/
│ └── 04-Fin-To-FinResponse-Bridge/
├── Part5-Practical-Usecase-Examples/ # Part 5: 실전 예제 (3개)
│ ├── 01-Command-Usecase-Example/
│ ├── 02-Query-Usecase-Example/
│ └── 03-Full-Pipeline-Integration/
├── Appendix/ # 부록
└── README.md # 이 문서

모든 Part의 예제 프로젝트에는 단위 테스트가 포함되어 있습니다. 테스트는 단위 테스트 가이드를 따릅니다.

Terminal window
# 전체 튜토리얼 테스트
dotnet test --solution usecase-pipeline.slnx

Part 1: 제네릭 변성 기초 (4개)

테스트 프로젝트주요 테스트 내용
1Covariance.Tests.Unit공변성, IEnumerable<out T> 대입
2Contravariance.Tests.Unit반공변성, Action<in T> 핸들러 대체
3InvarianceAndConstraints.Tests.Unit불변성, sealed struct 제약 불가
4InterfaceSegregationAndVariance.Tests.UnitISP + 변성 조합

Part 2: 문제 정의 (3개)

테스트 프로젝트주요 테스트 내용
1MediatorPipelineStructure.Tests.UnitIPipelineBehavior 구조 검증
2FinDirectLimitation.Tests.UnitFin<T> 직접 사용 한계 검증
3FinResponseWrapperLimitation.Tests.UnitIFinResponse 래퍼 한계 검증

Part 3: IFinResponse 계층 설계 (5개)

테스트 프로젝트주요 테스트 내용
1FinResponseMarker.Tests.UnitIFinResponse 마커 IsSucc/IsFail
2FinResponseCovariant.Tests.UnitIFinResponse<out A> 공변 인터페이스
3FinResponseFactoryCrtp.Tests.UnitCRTP 팩토리 CreateFail
4FinResponseWithError.Tests.UnitIFinResponseWithError 에러 접근
5FinResponseDiscriminatedUnion.Tests.UnitFinResponse<A> DU, Match/Map/Bind

Part 4: Pipeline 제약 패턴 (4개)

테스트 프로젝트주요 테스트 내용
1CreateOnlyConstraint.Tests.UnitIFinResponseFactory 제약 검증
2ReadCreateConstraint.Tests.UnitIFinResponse + Factory 제약 검증
3TransactionCachingPipeline.Tests.UnitTransaction/Caching Pipeline 분기
4FinToFinResponseBridge.Tests.UnitFin→FinResponse 변환 브릿지

Part 5: 실전 Usecase 예제 (3개)

테스트 프로젝트주요 테스트 내용
1CommandUsecaseExample.Tests.UnitCommand Usecase 전체 Pipeline
2QueryUsecaseExample.Tests.UnitQuery Usecase 전체 Pipeline
3FullPipelineIntegration.Tests.UnitPipeline 전체 흐름 통합

T1_T2_T3 명명 규칙을 따릅니다:

// Method_ExpectedResult_Scenario
[Fact]
public void Assign_Succeeds_WhenCovarianceApplies()
{
// Arrange
IEnumerable<Animal> animals;
// Act
animals = new List<Dog>();
// Assert
animals.ShouldNotBeNull();
}

이 튜토리얼의 모든 예제 코드는 Functorium 프로젝트에서 확인할 수 있습니다:

  • IFinResponse 인터페이스: Src/Functorium/Applications/Usecases/IFinResponse.cs
  • FinResponse 구현체: Src/Functorium/Applications/Usecases/IFinResponse.Impl.cs
  • 정적 팩토리: Src/Functorium/Applications/Usecases/IFinResponse.Factory.cs
  • Fin→FinResponse 변환: Src/Functorium/Applications/Usecases/IFinResponse.FinConversions.cs
  • Command/Query 인터페이스: Src/Functorium/Applications/Usecases/ICommandRequest.cs, IQueryRequest.cs
  • Pipeline 구현: Src/Functorium.Adapters/Observabilities/Pipelines/

이 튜토리얼은 다음 튜토리얼과 함께 학습하면 더 효과적입니다:


이 튜토리얼은 Functorium 프로젝트의 IFinResponse 인터페이스 계층 설계 경험을 바탕으로 작성되었습니다.