본문으로 건너뛰기

아키텍처 규칙 검증 커버리지

이 문서는 Functorium의 아키텍처 규칙이 각 레이어와 패턴에 대해 어느 수준까지 검증되는지 보여주는 커버리지 매트릭스입니다. 아키텍처 테스트의 현재 범위를 파악하거나, 추가 규칙이 필요한 영역을 식별할 때 참고하세요.

// ClassValidator로 직접 검증
ArchRuleDefinition.Classes().That()
.ImplementInterface(typeof(IValueObject))
.ValidateAllClasses(Architecture, @class => @class
.RequirePublic().RequireSealed().RequireImmutable())
.ThrowIfAnyFailures("ValueObject Rule");
// DelegateArchRule로 커스텀 규칙
var rule = new DelegateArchRule<Class>(
"No infrastructure suffixes",
(target, _) => target.Name.EndsWith("Dto")
? [new RuleViolation(target.FullName, "Naming", "...")]
: []);
// CompositeArchRule로 규칙 합성
var composite = new CompositeArchRule<Class>(
new ImmutabilityRule(), namingRule, dependencyRule);
// ArchUnitNET 필터로 레이어 의존성 검증
Types().That().ResideInNamespace(DomainNamespace)
.Should().NotDependOnAnyTypesThat()
.ResideInNamespace(ApplicationNamespace)
.Check(Architecture);

1. 규칙 검증 가능 여부 판별:

  1. ClassValidator/InterfaceValidator/MethodValidator API에 1:1 매핑되는가? → ✅ 직접 지원
  2. IArchRule<T> / DelegateArchRule<T>로 구현 가능한가? → 🔧 커스텀 규칙
  3. ArchUnitNET의 ArchRuleDefinition 필터로 검증 가능한가? → ⚠️ ArchUnitNET 필터
  4. 어셈블리 메타데이터/IL 수준에서 판별 불가능한가? → ❌ 검증 불가

2. 새 아키텍처 규칙 추가:

  1. 가이드 문서에서 규칙 식별
  2. 이 매트릭스에서 검증 가능 여부 확인
  3. 적합한 API 선택 (✅ > 🔧 > ⚠️ 순)
  4. 테스트 클래스에 규칙 추가

1. 커버리지 통계

검증 상태기호규칙 수비율
직접 지원5557%
커스텀 규칙🔧99%
ArchUnitNET 필터⚠️1010%
검증 불가2324%
합계97100%

2. 검증 가능 합계: 74건 (76%) — 프레임워크로 자동 검증 가능

3. ArchitectureRules API 구성

컴포넌트역할
ClassValidator클래스 수준 규칙 (visibility, modifier, inheritance, constructor, method, property, naming)
InterfaceValidator인터페이스 수준 규칙 (naming, inheritance, method)
MethodValidator메서드 수준 규칙 (visibility, static, return type, parameter)
IArchRule<T>커스텀 규칙 확장 인터페이스
DelegateArchRule<T>람다 기반 커스텀 규칙
CompositeArchRule<T>여러 규칙의 AND 합성
ImmutabilityRule불변성 종합 검증 (6가지 차원)

요약에서 커버리지 통계와 API 구성을 확인했습니다. 이제 검증에 사용하는 API를 상세히 살펴본 뒤, 규칙별 커버리지 매트릭스를 검토합니다.

카테고리메서드설명
VisibilityRequirePublic(), RequireInternal()접근 제한자
ModifierRequireSealed(), RequireNotSealed()sealed 여부
ModifierRequireStatic(), RequireNotStatic()static 여부
ModifierRequireAbstract(), RequireNotAbstract()abstract 여부
TypeRequireRecord(), RequireNotRecord()record 여부
TypeRequireAttribute(string)특정 어트리뷰트 존재
InheritanceRequireInherits(Type)기본 클래스 상속
InheritanceRequireImplements(Type)인터페이스 구현
InheritanceRequireImplementsGenericInterface(string)제네릭 인터페이스 구현
ConstructorRequireAllPrivateConstructors()모든 생성자 private
ConstructorRequirePrivateAnyParameterlessConstructor()매개변수 없는 private 생성자
PropertyRequireNoPublicSetters()public setter 금지
PropertyRequireOnlyPrimitiveProperties(params string[])원시 타입 프로퍼티만 허용
PropertyRequireProperty(string)특정 프로퍼티 존재
FieldRequireNoInstanceFields()인스턴스 필드 금지
MethodRequireMethod(string, Action<MethodValidator>)특정 메서드 검증
MethodRequireAllMethods(Action<MethodValidator>)모든 메서드 검증
MethodRequireAllMethods(Func<MethodMember, bool>, Action<MethodValidator>)필터링된 메서드 검증
MethodRequireMethodIfExists(string, Action<MethodValidator>)메서드 존재 시 검증
NamingRequireNameStartsWith(string)이름 접두사
NamingRequireNameEndsWith(string)이름 접미사
NamingRequireNameMatching(string)정규식 패턴 매칭
DependencyRequireNoDependencyOn(string)특정 타입 의존 금지
NestedRequireNestedClass(string, Action<ClassValidator>?)중첩 클래스 필수
NestedRequireNestedClassIfExists(string, Action<ClassValidator>?)중첩 클래스 존재 시 검증
ImmutabilityRequireImmutable()불변성 종합 검증
CompositionApply(IArchRule<TType>)커스텀 규칙 적용
카테고리메서드설명
VisibilityRequireVisibility(Visibility)접근 제한자
ModifierRequireStatic(), RequireNotStatic()static 여부
ModifierRequireExtensionMethod()확장 메서드 여부
ModifierRequireVirtual(), RequireNotVirtual()virtual 여부
ReturnRequireReturnType(Type)반환 타입 검증
ReturnRequireReturnTypeOfDeclaringClass()선언 클래스 반환
ReturnRequireReturnTypeOfDeclaringTopLevelClass()최상위 클래스 반환
ReturnRequireReturnTypeContaining(string)반환 타입 이름 포함
ParameterRequireParameterCount(int)매개변수 개수
ParameterRequireParameterCountAtLeast(int)최소 매개변수 개수
ParameterRequireFirstParameterTypeContaining(string)첫 번째 매개변수 타입
ParameterRequireAnyParameterTypeContaining(string)임의 매개변수 타입
타입용도예시
IArchRule<TType>커스텀 규칙 인터페이스ImmutabilityRule : IArchRule<Class>
DelegateArchRule<TType>람다 기반 인라인 규칙인프라 접미사 금지, 인프라 네임스페이스 의존 금지
CompositeArchRule<TType>여러 규칙 AND 합성ImmutabilityRule + 네이밍 + 의존성 = ValueObject 핵심 규칙

API 요약에서 사용 가능한 검증 도구를 확인했습니다. 이제 가이드 문서에 정의된 97개 규칙 각각의 자동 검증 가능 여부를 매트릭스로 정리합니다.

검증 가능 상태 범례:

기호상태설명
직접 지원ClassValidator / InterfaceValidator / MethodValidator 기존 API로 검증
🔧커스텀 규칙IArchRule<T> 또는 DelegateArchRule<T>로 구현 가능
⚠️ArchUnitNET 필터ArchRuleDefinition 필터 + Should() 체인으로 검증
검증 불가사유 명시
규칙출처검증 가능사용 API / 불가 사유
public sealed 클래스05aRequirePublic() + RequireSealed()
불변성 (6가지 차원)05aRequireImmutable() (ImmutabilityRule)
모든 생성자 private05aRequireAllPrivateConstructors()
Create() 팩토리 (public static, Fin<T> 반환)05aRequireMethod("Create", m => m.RequireStatic().RequireReturnType(typeof(Fin<>)))
Validate() 메서드 (public static, Validation<,> 반환)05aRequireMethod("Validate", m => m.RequireStatic().RequireReturnType(typeof(Validation<,>)))
IValueObject 인터페이스 구현05a⚠️ArchUnitNET 필터: .ImplementInterface(typeof(IValueObject))
IEquatable<> 구현05aRequireImplements(typeof(IEquatable<>))
SimpleValueObject<T> 또는 ValueObject 상속05aRequireInherits(typeof(SimpleValueObject<>))
중첩 DomainErrors 클래스 규칙08bRequireNestedClassIfExists("DomainErrors", ...)
implicit operator 정의05a🔧DelegateArchRule: op_Implicit 메서드 존재 확인
ValidationRules<T> 사용05a소스 코드 분석 필요 (IL에서 호출 패턴 추적 불가)
CreateFromValidation() 패턴 사용05a소스 코드 분석 필요
인프라 접미사 금지 (Dto, ViewModel 등)04🔧DelegateArchRule: 금지 접미사 패턴 매칭
인프라 네임스페이스 의존 금지04🔧DelegateArchRule: 의존성 네임스페이스 검사
규칙출처검증 가능사용 API / 불가 사유
public sealed 클래스06bRequirePublic() + RequireSealed()
Not static06bRequireNotStatic()
AggregateRoot<TId> 상속06bRequireInherits(typeof(AggregateRoot<>))
Entity<TId> 상속 (일반 Entity)06bRequireInherits(typeof(Entity<>))
[GenerateEntityId] 어트리뷰트06bRequireAttribute("GenerateEntityId")
모든 생성자 private06bRequireAllPrivateConstructors()
매개변수 없는 private 생성자 (ORM)06bRequirePrivateAnyParameterlessConstructor()
Create() 팩토리 (선언 클래스 반환)06bRequireMethod("Create", m => m.RequireStatic().RequireReturnTypeOfDeclaringClass())
CreateFromValidated() 팩토리06bRequireMethod("CreateFromValidated", m => m.RequireStatic().RequireReturnTypeOfDeclaringClass())
Create()에서 AddDomainEvent() 호출06b소스 코드 분석 필요 (메서드 본문 검증 불가)
가변 컬렉션 직접 노출 금지06b🔧DelegateArchRule: public 프로퍼티의 반환 타입에서 List<> 등 탐지
IConcurrencyAware 구현 (선택적)06cRequireImplements(typeof(IConcurrencyAware))
인프라 접미사 금지04🔧DelegateArchRule: 금지 접미사 패턴 매칭
인프라 네임스페이스 의존 금지04🔧DelegateArchRule: 의존성 네임스페이스 검사
규칙출처검증 가능사용 API / 불가 사유
sealed record07RequireSealed() + RequireRecord()
이름이 “Event”로 끝남07RequireNameEndsWith("Event")
DomainEvent 기반 클래스 상속07RequireInherits(typeof(DomainEvent))
AggregateRoot 내부에 중첩 정의07🔧DelegateArchRule: 타입의 DeclaringType 검사
과거 시제 이름 (Created, Shipped 등)07의미론적 분석 필요 (자연어 시제 판별 불가)

참고: 아래 규칙 중 “Stateless (인스턴스 필드 없음)“과 “Public 메서드 Fin 반환”은 순수 패턴(기본)에 적용됩니다. Evans Ch.9 Repository 패턴에서는 Repository 인터페이스 참조 필드가 허용되고, 반환 타입이 FinT<IO, T>입니다. 프로젝트에서 Repository 패턴을 사용하는 경우 해당 규칙을 조정하세요. 상세: 09-domain-services.md

규칙출처검증 가능사용 API / 불가 사유
public sealed 클래스09RequirePublic() + RequireSealed()
IDomainService 구현09⚠️ArchUnitNET 필터: .ImplementInterface(typeof(IDomainService))
Stateless (인스턴스 필드 없음)09RequireNoInstanceFields() (순수 패턴에 적용)
IObservablePort 의존 금지09RequireNoDependencyOn("IObservablePort")
Public 메서드 Fin 반환09RequireAllMethods(filter, m => m.RequireReturnTypeContaining("Fin")) (순수 패턴에 적용; Evans 패턴은 FinT 반환)
Record 금지09RequireNotRecord()
순수 함수, I/O 없음09런타임 동작 검증 (정적 분석 한계)
규칙출처검증 가능사용 API / 불가 사유
public sealed 클래스10RequirePublic() + RequireSealed()
Specification<T> 상속10RequireInherits(typeof(Specification<>))
Domain 레이어에 위치10⚠️ArchUnitNET: .Should().ResideInNamespaceMatching()
ToExpression() 오버라이드10🔧DelegateArchRule: 메서드 존재 및 virtual override 확인
규칙출처검증 가능사용 API / 불가 사유
중첩 DomainErrors 클래스 (internal sealed)08bRequireNestedClassIfExists("DomainErrors", n => n.RequireInternal().RequireSealed())
DomainErrors 메서드 (public static, Error 반환)08b.RequireAllMethods(m => m.RequireStatic().RequireReturnType(typeof(Error)))
DomainError.For<T>() 팩토리 패턴 사용08a소스 코드 분석 필요 (메서드 본문의 호출 패턴)
에러 코드 형식 (DomainErrors.Type.Name)08a런타임 검증 필요 (단위 테스트로 검증)
Custom 에러 타입이 sealed record08b🔧DelegateArchRule: 특정 네임스페이스의 Error 파생 타입 검사
규칙출처검증 가능사용 API / 불가 사유
Command 클래스 sealed11RequireSealed()
Command 내부 Request (sealed record, ICommandRequest)11RequireNestedClass("Request", n => n.RequireSealed().RequireRecord().RequireImplementsGenericInterface("ICommandRequest"))
Command 내부 Response (sealed record)11RequireNestedClass("Response", n => n.RequireSealed().RequireRecord())
Command 내부 Usecase (sealed, ICommandUsecase)11RequireNestedClass("Usecase", n => n.RequireSealed().RequireImplementsGenericInterface("ICommandUsecase"))
Query 클래스 sealed11RequireSealed()
Query 내부 Request (sealed record, IQueryRequest)11RequireNestedClass("Request", n => n.RequireSealed().RequireRecord().RequireImplementsGenericInterface("IQueryRequest"))
Query 내부 Response (sealed record)11RequireNestedClass("Response", n => n.RequireSealed().RequireRecord())
Query 내부 Usecase (sealed, IQueryUsecase)11RequireNestedClass("Usecase", n => n.RequireSealed().RequireImplementsGenericInterface("IQueryUsecase"))
Request/Response는 원시 타입 프로퍼티만 허용11RequireOnlyPrimitiveProperties()
Usecase는 ValueTask<FinResponse<T>> 반환11인터페이스가 강제하므로 별도 검증 불필요 (컴파일러 보장)
FinT<IO, T> LINQ 체인 사용11소스 코드 분석 필요
규칙출처검증 가능사용 API / 불가 사유
Query Usecase가 IRepository에 의존 금지11⚠️ArchUnitNET: .Should().NotDependOnAnyTypesThat().HaveNameEndingWith("Repository")
Command 이름이 “Command”로 끝남11⚠️ArchUnitNET 필터: .HaveNameEndingWith("Command")
Query 이름이 “Query”로 끝남11⚠️ArchUnitNET 필터: .HaveNameEndingWith("Query")
규칙출처검증 가능사용 API / 불가 사유
Validator가 AbstractValidator 상속14aRequireImplementsGenericInterface("AbstractValidator")
Sealed 클래스14aRequireSealed()
Usecase 내부에 중첩 (선택적)11RequireNestedClassIfExists("Validator", ...)
규칙출처검증 가능사용 API / 불가 사유
ApplicationError.For<T>() 팩토리 패턴 사용08b소스 코드 분석 필요
에러 코드 형식 (ApplicationErrors.Usecase.Name)08b런타임 검증 필요
Shared Application DTO (sealed record, primitive)17RequireSealed() + RequireRecord() + RequireOnlyPrimitiveProperties()
규칙출처검증 가능사용 API / 불가 사유
Repository 네이밍 (I 접두사)12RequireNameStartsWith("I") (InterfaceValidator)
Repository가 IObservablePort 구현12RequireImplements(typeof(IObservablePort))
Repository 메서드가 FinT 반환12RequireAllMethods(m => m.RequireReturnTypeContaining("FinT"))
Domain Port는 Domain 레이어에 위치12⚠️ArchUnitNET: .Should().ResideInNamespaceMatching()
Application Port는 Application 레이어에 위치12⚠️ArchUnitNET: .Should().ResideInNamespaceMatching()
규칙출처검증 가능사용 API / 불가 사유
[GenerateObservablePort] 어트리뷰트13RequireAttribute("GenerateObservablePort")
메서드가 virtual13RequireAllMethods(m => m.RequireVirtual())
RequestCategory 프로퍼티 존재13RequireProperty("RequestCategory")
Not sealed (Observable 상속 허용)13RequireNotSealed()
AdapterError.For<T>() 팩토리 사용08c소스 코드 분석 필요
규칙출처검증 가능사용 API / 불가 사유
Mapper는 internal static 클래스13RequireInternal() + RequireStatic()
ToModel() 확장 메서드13RequireMethod("ToModel", m => m.RequireStatic().RequireExtensionMethod())
ToDomain() 확장 메서드13RequireMethod("ToDomain", m => m.RequireStatic().RequireExtensionMethod())
Model은 public, not sealed, POCO13RequirePublic() + RequireNotSealed() + RequireOnlyPrimitiveProperties()
EF Core Configuration (FluentAPI)13소스 코드 분석 필요
규칙출처검증 가능사용 API / 불가 사유
Endpoint는 sealed13RequireSealed()
중첩 Request (sealed record, primitive)13RequireNestedClassIfExists("Request", ...)
중첩 Response (sealed record, primitive)13RequireNestedClassIfExists("Response", ...)
FastEndpoints 상속13제네릭 타입 매칭 복잡 (다양한 Endpoint 기반 클래스)
규칙출처검증 가능사용 API / 불가 사유
등록 메서드 네이밍 (RegisterAdapter{Category})14a확장 메서드 네이밍은 정적 분석 가능하나, 관례 수준
미들웨어 등록 순서14a런타임 동작 검증 (코드 실행 순서)
OptionsConfigurator<T> 패턴 사용14a소스 코드 분석 필요
규칙출처검증 가능사용 API / 불가 사유
AdapterError.For<T>() 팩토리 패턴 사용08c소스 코드 분석 필요
에러 코드 형식 (AdapterErrors.Adapter.Name)08c런타임 검증 필요
규칙출처검증 가능사용 API / 불가 사유
테스트 프로젝트 폴더가 소스 구조를 미러링15a파일/디렉토리 구조 검증 (어셈블리 메타데이터 범위 밖)
테스트 네이밍: {Method}_{ShouldBehavior}_{Condition}15a테스트 메서드 이름은 IL에 있지만, 의미론적 패턴 검증 어려움
AAA (Arrange-Act-Assert) 패턴15a소스 코드 분석 필요 (코드 구조/주석 검증 불가)
xunit.runner.json 병렬 설정15a설정 파일 검증 (JSON 파일 파싱 필요)
Shouldly assertion 사용15a소스 코드 분석 필요 (특정 라이브러리 호출 추적)
규칙출처검증 가능사용 API / 불가 사유
Signal 접두사 (Logging, Tracing, Metrics)18b🔧DelegateArchRule: 클래스 이름 패턴 매칭
Component 접미사 (Logger, Span, Metric)18b🔧DelegateArchRule: 클래스 이름 패턴 매칭
Logger 메서드 네이밍 (Log{Context}{Phase}{Status})18b소스 코드 분석 필요 (LoggerMessage 어트리뷰트 파싱)
[LoggerMessage] 어트리뷰트 사용18b메서드 수준 어트리뷰트 검증은 가능하나 partial 메서드 제약
규칙출처검증 가능사용 API / 불가 사유
Domain → Application 의존 금지01⚠️ArchUnitNET: Types().Should().NotDependOnAnyTypesThat()
Domain → Adapter 의존 금지01⚠️ArchUnitNET: Types().Should().NotDependOnAnyTypesThat()
Application → Adapter 의존 금지01⚠️ArchUnitNET: Types().Should().NotDependOnAnyTypesThat()
Adapter 간 교차 의존 금지01⚠️ArchUnitNET: Types().Should().NotDependOnAnyTypesThat()
규칙출처검증 가능사용 API / 불가 사유
AssemblyReference.cs 존재01파일 존재 확인 (어셈블리 메타데이터 범위 밖)
Using.cs 존재01파일 존재 확인
csproj 의존성 방향01설정 파일 검증 (MSBuild XML 파싱 필요)
네임스페이스 패턴 준수01⚠️ArchUnitNET: .Should().ResideInNamespaceMatching()

커버리지 매트릭스에서 24%의 규칙이 자동 검증 불가로 분류되었습니다. 이 규칙들이 왜 검증 불가한지, 어떤 대안으로 보완할 수 있는지 분석합니다.

IL(Intermediate Language) 수준에서는 메서드 본문의 로직 흐름을 추적할 수 없습니다. ArchUnitNET은 어셈블리 메타데이터(타입, 메서드 시그니처, 의존성)를 분석하지만, 메서드 내부에서 어떤 패턴을 사용하는지는 판별할 수 없습니다.

검증 불가 규칙대안
ValidationRules<T> 사용 여부코드 리뷰, Roslyn Analyzer
DomainError.For<T>() 팩토리 패턴 사용단위 테스트에서 에러 코드 검증
Create()에서 AddDomainEvent() 호출단위 테스트에서 이벤트 발행 검증
AAA 패턴, Shouldly 사용코드 리뷰, Roslyn Analyzer
FinT<IO, T> LINQ 체인 사용컴파일러가 타입 안전성 보장
[LoggerMessage] 어트리뷰트 사용로그 스냅샷 테스트로 간접 검증

어셈블리 메타데이터에는 파일 시스템 구조 정보가 포함되지 않습니다.

검증 불가 규칙대안
테스트 폴더가 소스 구조를 미러링빌드 스크립트, CI 검증
AssemblyReference.cs 존재빌드 스크립트, CI 검증
Using.cs 존재빌드 스크립트, CI 검증

csproj, JSON, xunit.runner.json 등의 설정 파일은 어셈블리 메타데이터 범위 밖입니다.

검증 불가 규칙대안
csproj 의존성 방향MSBuild 타겟, CI 검증
xunit.runner.json 병렬 설정CI 검증
EF Core FluentAPI 설정통합 테스트에서 마이그레이션 검증

정적 분석으로는 코드 실행 순서나 런타임 동작을 검증할 수 없습니다.

검증 불가 규칙대안
Domain Service의 순수 함수/I/O 없음코드 리뷰, 의존성 분석으로 간접 추론
미들웨어 등록 순서통합 테스트
에러 코드 형식 일관성단위 테스트의 ShouldFailWithErrorCode()

커스텀 규칙에서 타입 정보가 부족할 때

섹션 제목: “커스텀 규칙에서 타입 정보가 부족할 때”

원인: DelegateArchRule<Class>target 파라미터는 ArchUnitNET의 Class 타입으로, .NET Reflection의 Type과 다릅니다.

해결: target.Dependencies, target.Members, target.Name, target.FullName 등 ArchUnitNET이 제공하는 속성을 사용하세요. 필요한 경우 Architecture 파라미터에서 추가 타입을 조회할 수 있습니다.

ArchUnitNET 필터에서 하위 네임스페이스가 포함되지 않을 때

섹션 제목: “ArchUnitNET 필터에서 하위 네임스페이스가 포함되지 않을 때”

원인: ResideInNamespace()는 정확한 네임스페이스만 매칭합니다.

해결: ResideInNamespaceMatching($@"{BaseNamespace}\..*")으로 정규식 기반 매칭을 사용하세요.

RequireAllMethods()에서 Object 상속 메서드가 포함될 때

섹션 제목: “RequireAllMethods()에서 Object 상속 메서드가 포함될 때”

원인: Equals, GetHashCode, ToStringSystem.Object에서 상속된 메서드가 검증 대상에 포함됩니다.

해결: 필터 오버로드를 사용하세요:

@class.RequireAllMethods(
m => m.Visibility == Visibility.Public && m.MethodForm == MethodForm.Normal,
method => method.RequireReturnTypeContaining("Fin"));

Q1. 커버리지 76%의 의미는 무엇인가요?

섹션 제목: “Q1. 커버리지 76%의 의미는 무엇인가요?”

가이드에 정의된 97개 구현 규칙 중 74개가 ArchitectureRules 프레임워크로 자동 검증 가능합니다. 나머지 24%는 소스 코드 분석, 파일 구조 검증, 런타임 동작 등 정적 분석의 한계를 넘어서는 규칙이며, 단위 테스트, 코드 리뷰, CI 검증 등으로 보완해야 합니다.

Q2. ✅ 직접 지원과 🔧 커스텀 규칙의 차이는 무엇인가요?

섹션 제목: “Q2. ✅ 직접 지원과 🔧 커스텀 규칙의 차이는 무엇인가요?”

✅ 직접 지원은 ClassValidator.RequireSealed()처럼 기존 API를 호출하면 되는 것이고, 🔧 커스텀 규칙은 DelegateArchRule<T> 또는 IArchRule<T> 구현을 직접 작성해야 하는 것입니다. 커스텀 규칙은 프로젝트별로 작성하며 재사용 가능합니다.

Q3. ⚠️ ArchUnitNET 필터와 ✅ 직접 지원은 어떻게 다른가요?

섹션 제목: “Q3. ⚠️ ArchUnitNET 필터와 ✅ 직접 지원은 어떻게 다른가요?”

⚠️ ArchUnitNET 필터는 ArchRuleDefinition.Types().Should().NotDependOnAnyTypesThat() 같은 ArchUnitNET 자체 DSL을 사용하는 것이고, ✅ 직접 지원은 ValidateAllClasses() 이후 ClassValidator 콜백에서 사용하는 Functorium 자체 API입니다. 둘 다 테스트 코드에서 사용하지만 API 레이어가 다릅니다.

Q4. 검증 불가 규칙은 어떻게 보완하나요?

섹션 제목: “Q4. 검증 불가 규칙은 어떻게 보완하나요?”
카테고리보완 방법
소스 코드 분석Roslyn Analyzer, 코드 리뷰
파일/디렉토리 구조CI 빌드 스크립트, dotnet new 템플릿
설정 파일CI 검증 스크립트
런타임 동작단위 테스트, 통합 테스트

Q5. 새 규칙을 추가할 때 이 문서를 어떻게 활용하나요?

섹션 제목: “Q5. 새 규칙을 추가할 때 이 문서를 어떻게 활용하나요?”
  1. 가이드 문서에 새 규칙을 정의합니다
  2. 이 매트릭스에서 해당 규칙의 검증 가능 여부를 판별합니다
  3. ✅/🔧/⚠️이면 아키텍처 테스트 클래스에 추가합니다
  4. ❌이면 대안(단위 테스트, CI 등)을 선택합니다
  5. 이 문서의 매트릭스를 업데이트합니다

Q6. CompositeArchRule은 언제 사용하나요?

섹션 제목: “Q6. CompositeArchRule은 언제 사용하나요?”

여러 규칙을 AND로 합성하여 재사용할 때 사용합니다. 예를 들어, ValueObject의 핵심 규칙(불변성 + 네이밍 + 의존성)을 하나의 CompositeArchRule로 합성하면, 여러 테스트에서 일관되게 적용할 수 있습니다.

private static readonly CompositeArchRule<Class> s_valueObjectCoreRule = new(
new ImmutabilityRule(),
s_domainNamingRule,
s_noInfrastructureDependencyRule);

Q7. SingleHost 예제에는 어떤 아키텍처 테스트가 있나요?

섹션 제목: “Q7. SingleHost 예제에는 어떤 아키텍처 테스트가 있나요?”

Tests.Hosts/01-SingleHost/Tests/LayeredArch.Tests.Unit/Architecture/에 13개 테스트 클래스가 구현되어 있습니다. 16-testing-library.md의 “SingleHost 아키텍처 테스트 인벤토리”를 참조하세요.