--- kind: REFERENCE slug: make-the-unsafe-state-unrepresentable title: 위험한 조합은 정책이 아니라 생성자가 거부하게 만든다 topic: commit-ambiguity-as-a-result project: clean-architecture-backend-template status: 게시 전 sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 rootTreeNode: reference:make-the-unsafe-state-unrepresentable verifiedOn: # 이 기록은 이번 회차에 실행 확인을 하지 않았다 --- # 위험한 조합은 정책이 아니라 생성자가 거부하게 만든다 ## 목적 이 조합은 하면 안 된다는 규칙을 리뷰나 정책 코드에 두어, 정책 버그가 그 조합을 만들 수 있게 남겨 두는 것을 막는다. ## 규칙 1. 값이 존재할 수 없게 만든다 생성자가 거부하면 그 조합을 가진 값이 프로그램 안에 존재하지 않는다. 정책이 거부하면 정책을 지나치는 경로마다 같은 검사가 필요하다. 2. 검사는 값 타입 안에 둔다 두 필드의 조합이 의미상 불가능한 값 타입이 대상이다. 컴팩트 생성자 한 줄이면 되고 비용이 거의 없다. 3. 예외를 재구성할 때도 같은 팩토리를 지난다 컨텍스트를 다시 만드는 경로가 검사를 우회하면 방어가 반쪽이 된다. 안전 팩토리를 통해서만 재구성하게 해서 이중으로 막는다. 4. 조합이 다른 객체의 상태에 의존하면 자리가 다르다 그때는 생성자가 아니라 조립 지점의 시작 검증기가 맡는다. ## 적용 조건 두 필드의 조합이 의미상 불가능한 모든 값 타입 이 저장소의 예 : JpaFailureContext 가 completionUnknown 과 retryable 의 동시 참을 거부한다. PublishEvidence 가 두 조합을 거부한다. GrpcExecutionEvidence 가 스트림 증거를 가진 unary 호출을 거부한다. TransactionResult.Indeterminate 가 operationId 없는 조정 참조를 거부한다. ## 예외 유효성이 다른 객체의 상태나 실행 시점의 설정에 의존하면 생성자 검증으로 표현되지 않는다. 조립 지점의 시작 검증기가 그 자리다. ## 예시 completionUnknown 이면서 retryable 인 실패 컨텍스트는 만들 수 없다. 그 조합이 존재하면 재시도 정책이 커밋됐을 수도 있는 쓰기를 재시도한다. 조정 참조가 있는데 안정적인 operationId 가 없는 불확정 결과는 만들 수 없다. 조정할 대상을 지목할 수 없는 조정 참조이기 때문이다. ## 관계 - **모르는 것은 성공도 실패도 아닌 세 번째 결과여야 한다** 이 규칙이 지키려는 상태 어휘를 정의한다. - **completion-unknown은 자동으로도 수동으로도 재시도하지 않는다** 이 규칙으로 타입 수준에서 강제되는 결정이다. - **전송·업무·스트림 증거는 세 축이고 서로를 함의하지 않는다** 같은 규칙이 gRPC 쪽에서 적용된 결정이다.