명세 패턴
C# Functorium으로 조합 가능한 비즈니스 규칙을 구현하는 실전 가이드
이 튜토리얼에 대하여
섹션 제목: “이 튜토리얼에 대하여”Repository 메서드가 끝없이 늘어나고, 비즈니스 규칙이 서비스 코드 곳곳에 흩어져 있다면 — Specification 패턴이 해답일 수 있습니다.
이 튜토리얼은 Specification 패턴을 활용한 도메인 규칙 구현을 단계별로 학습할 수 있도록 구성된 종합적인 교육 과정입니다. 기본적인 Specification 클래스에서 시작하여 Expression Tree 기반 Repository 통합까지, 18개의 실습 프로젝트를 통해 Specification 패턴의 모든 측면을 체계적으로 학습할 수 있습니다.
단순한 조건 분기에서 시작하여 조합 가능한 비즈니스 규칙으로 진화하는 과정을 함께 경험해보세요.
대상 독자
섹션 제목: “대상 독자”| 수준 | 대상 | 권장 학습 범위 |
|---|---|---|
| 초급 | C# 기본 문법을 알고 Specification 패턴에 입문하려는 개발자 | Part 1 |
| 중급 | 패턴을 이해하고 실전 적용을 원하는 개발자 | Part 1~3 |
| 고급 | 아키텍처 설계와 도메인 모델링에 관심 있는 개발자 | Part 4~5 + 부록 |
학습 목표
섹션 제목: “학습 목표”이 튜토리얼을 완료하면 다음을 할 수 있습니다:
- Specification 패턴의 개념과 필요성을 이해하고 설명
- And, Or, Not 조합으로 복합 비즈니스 규칙 구현
- Expression Tree를 활용한 ORM 호환 Specification 구현
- Repository와 Specification 통합으로 유연한 데이터 조회
- 테스트 전략을 적용한 신뢰할 수 있는 도메인 규칙 검증
Part 0: 서론
섹션 제목: “Part 0: 서론”서론에서는 Specification 패턴의 개념과 환경 설정을 다룹니다.
Part 1: Specification 기초
섹션 제목: “Part 1: Specification 기초”기본 Specification부터 연산자 오버로딩과 항등원까지 학습합니다.
| 장 | 주제 | 핵심 학습 내용 |
|---|---|---|
| 1 | 첫 번째 Specification | Specification |
| 2 | 조합 | And, Or, Not 메서드 조합 |
| 3 | 연산자 | &, |
| 4 | All 항등원 | All 항등원, 동적 필터 체이닝 |
Part 2: Expression Specification
섹션 제목: “Part 2: Expression Specification”Expression Tree 기반 Specification으로 ORM 통합을 준비합니다.
| 장 | 주제 | 핵심 학습 내용 |
|---|---|---|
| 1 | Expression 소개 | Expression Tree 개념과 필요성 |
| 2 | ExpressionSpecification 클래스 | sealed IsSatisfiedBy, 델리게이트 캐싱 |
| 3 | Value Object 변환 패턴 | Value Object→primitive 변환 |
| 4 | Expression Resolver | TryResolve, 재귀 합성 |
Part 3: Repository 통합
섹션 제목: “Part 3: Repository 통합”Specification과 Repository를 통합하여 유연한 데이터 조회를 구현합니다.
| 장 | 주제 | 핵심 학습 내용 |
|---|---|---|
| 1 | Repository와 Specification | Repository 메서드 폭발 방지 |
| 2 | InMemory 구현 | InMemory 어댑터 |
| 3 | PropertyMap | PropertyMap, TranslatingVisitor |
| 4 | EF Core 구현 | TryResolve + Translate 조합 |
Part 4: 실전 패턴
섹션 제목: “Part 4: 실전 패턴”실전 프로젝트에서 Specification 패턴을 활용하는 방법을 학습합니다.
| 장 | 주제 | 핵심 학습 내용 |
|---|---|---|
| 1 | Usecase 패턴 | CQRS에서 Spec 활용 |
| 2 | 동적 필터 빌더 | All 시드 조건부 체이닝 |
| 3 | 테스트 전략 | Spec/조합/Usecase 테스트 |
| 4 | 아키텍처 규칙 | 네이밍, 폴더 배치, ArchUnitNET |
Part 5: 도메인별 실전 예제
섹션 제목: “Part 5: 도메인별 실전 예제”다양한 도메인에서 Specification 패턴을 적용하는 실전 예제입니다.
핵심 진화 과정
섹션 제목: “핵심 진화 과정”Part 1 1장: 첫 번째 Spec → 2장: And/Or/Not 조합 → 3장: 연산자 오버로딩 → 4장: All 항등원 ↓Part 2 1장: Expression 소개 → 2장: ExpressionSpec → 3장: VO 변환 패턴 → 4장: Expression Resolver ↓Part 3 1장: Repository 통합 → 2장: InMemory 구현 → 3장: PropertyMap → 4장: EF Core 구현 ↓Part 4 1장: Usecase 패턴 → 2장: 동적 필터 → 3장: 테스트 전략 → 4장: 아키텍처 규칙Functorium Specification 타입 계층
섹션 제목: “Functorium Specification 타입 계층”이 튜토리얼에서 다루는 Functorium의 핵심 타입 계층은 다음과 같습니다.
Specification<T> (추상 클래스)├── IsSatisfiedBy(T) : bool├── And() / Or() / Not()├── & / | / ! 연산자└── All (항등원)
IExpressionSpec<T> (인터페이스)└── ToExpression() : Expression<Func<T, bool>>
ExpressionSpecification<T> : Specification<T>, IExpressionSpec<T>├── abstract ToExpression()├── sealed IsSatisfiedBy (컴파일 + 캐싱)└── AllSpecification<T> (internal, 항등원: _ => true)
SpecificationExpressionResolver (Expression 합성)PropertyMap<TEntity, TModel> (Entity→Model 변환)필수 준비물
섹션 제목: “필수 준비물”- .NET 10.0 SDK 이상
- VS Code + C# Dev Kit 확장
- C# 기초 문법 지식
프로젝트 구조
섹션 제목: “프로젝트 구조”specification-pattern/├── Part0-Introduction/ # Part 0: 서론├── Part1-Specification-Basics/ # Part 1: Specification 기초 (4개)│ ├── 01-First-Specification/│ ├── 02-Composition/│ ├── 03-Operators/│ └── 04-All-Identity/├── Part2-Expression-Specification/ # Part 2: Expression Specification (4개)│ ├── 01-Expression-Introduction/│ ├── 02-ExpressionSpecification-Class/│ ├── 03-ValueObject-Primitive-Conversion/│ └── 04-Expression-Resolver/├── Part3-Repository-Integration/ # Part 3: Repository 통합 (4개)│ ├── 01-Repository-With-Specification/│ ├── 02-InMemory-Implementation/│ ├── 03-PropertyMap/│ └── 04-EfCore-Implementation/├── Part4-Real-World-Patterns/ # Part 4: 실전 패턴 (4개)│ ├── 01-Usecase-Patterns/│ ├── 02-Dynamic-Filter-Builder/│ ├── 03-Testing-Strategies/│ └── 04-Architecture-Rules/├── Part5-Domain-Examples/ # Part 5: 도메인별 실전 예제 (2개)│ ├── 01-Ecommerce-Product-Filtering/│ └── 02-Customer-Management/├── Appendix/ # 부록└── index.md # 이 문서테스트
섹션 제목: “테스트”모든 Part의 예제 프로젝트에는 단위 테스트가 포함되어 있습니다. 테스트는 단위 테스트 가이드를 따릅니다.
테스트 실행 방법
섹션 제목: “테스트 실행 방법”# 튜토리얼 전체 빌드dotnet build specification-pattern.slnx
# 튜토리얼 전체 테스트dotnet test --solution specification-pattern.slnx테스트 프로젝트 구조
섹션 제목: “테스트 프로젝트 구조”Part 1: Specification 기초 (4개)
| 장 | 테스트 프로젝트 | 주요 테스트 내용 |
|---|---|---|
| 1 | FirstSpecification.Tests.Unit | IsSatisfiedBy 동작 검증 |
| 2 | Composition.Tests.Unit | And, Or, Not 조합 검증 |
| 3 | Operators.Tests.Unit | 연산자 오버로딩 검증 |
| 4 | AllIdentity.Tests.Unit | All 항등원, 동적 체이닝 |
Part 2: Expression Specification (4개)
| 장 | 테스트 프로젝트 | 주요 테스트 내용 |
|---|---|---|
| 1 | ExpressionIntro.Tests.Unit | Expression Tree 기본 |
| 2 | ExpressionSpec.Tests.Unit | sealed IsSatisfiedBy, 캐싱 |
| 3 | ValueObjectConversion.Tests.Unit | VO→primitive 변환 |
| 4 | ExpressionResolver.Tests.Unit | TryResolve, 재귀 합성 |
Part 3: Repository 통합 (4개)
| 장 | 테스트 프로젝트 | 주요 테스트 내용 |
|---|---|---|
| 1 | RepositorySpec.Tests.Unit | Repository + Spec 통합 |
| 2 | InMemoryImpl.Tests.Unit | InMemory 어댑터 |
| 3 | PropertyMapDemo.Tests.Unit | PropertyMap, TranslatingVisitor |
| 4 | EfCoreImpl.Tests.Unit | EF Core TryResolve + Translate |
Part 4: 실전 패턴 (4개)
| 장 | 테스트 프로젝트 | 주요 테스트 내용 |
|---|---|---|
| 1 | UsecasePatterns.Tests.Unit | CQRS + Spec 활용 |
| 2 | DynamicFilter.Tests.Unit | 동적 필터 체이닝 |
| 3 | TestingStrategies.Tests.Unit | Spec 테스트 패턴 |
| 4 | ArchitectureRules.Tests.Unit | 아키텍처 규칙 검증 |
Part 5: 도메인별 실전 예제 (2개)
| 장 | 테스트 프로젝트 | 주요 테스트 내용 |
|---|---|---|
| 1 | EcommerceFiltering.Tests.Unit | 상품 필터링 Spec |
| 2 | CustomerManagement.Tests.Unit | 고객 관리 Spec |
테스트 명명 규칙
섹션 제목: “테스트 명명 규칙”T1_T2_T3 명명 규칙을 따릅니다:
// Method_ExpectedResult_Scenario[Fact]public void IsSatisfiedBy_ReturnsTrue_WhenProductIsActive(){ // Arrange var spec = new ActiveProductSpec(); var product = new Product { IsActive = true }; // Act var actual = spec.IsSatisfiedBy(product); // Assert actual.ShouldBeTrue();}소스 코드
섹션 제목: “소스 코드”이 튜토리얼의 모든 예제 코드는 Functorium 프로젝트에서 확인할 수 있습니다:
- 프레임워크 타입:
Src/Functorium/Domains/Specifications/ - 튜토리얼 프로젝트:
Docs.Site/src/content/docs/tutorials/specification-pattern/
관련 튜토리얼
섹션 제목: “관련 튜토리얼”이 튜토리얼은 다음 튜토리얼과 함께 학습하면 더 효과적입니다:
- CQRS 패턴으로 Command와 Query 분리하기: CQRS 패턴의 IQueryPort, IRepository에서 Specification을 매개변수로 사용합니다.
이 튜토리얼은 Functorium 프로젝트의 실제 Specification 프레임워크 개발 경험을 바탕으로 작성되었습니다.