원문 캡처 · paul.blasuc.ci
원문 캡처 · paul.blasuc.ci

F#의 Result가 서로 다른 라이브러리의 오류 유형을 결합하기 번거롭다는 문제를 해결하기 위해 IFault 인터페이스와 Report 합타입을 쓰는 Fault/Report 접근법이 제안됐다. 블로그 글은 이를 기존 Result의 대체 확정안이 아니라 오류 모델링을 개선할 수 있는 설계 제안으로 소개한다.

F# 4.1에서 도입된 Result는 성공과 실패를 Ok와 Error로 표현한다. 글은 이 타입이 FSharp.Core에 포함돼 널리 쓰이고 유연하다는 점을 장점으로 꼽는다. 반면 오류 유형을 일관되게 설계하도록 돕는 기준이 없고, 오류를 문자열로 표현하면 호출자가 오류에 따라 프로그램 방식으로 대응하기 어렵다고 지적한다.

또 다른 문제는 여러 라이브러리의 Result를 함께 사용할 때 생긴다. 예를 들어 각 라이브러리가 서로 다른 오류 타입을 반환하면 하나의 처리 흐름에서 타입이 맞지 않아 오류를 다시 매핑하거나, 두 오류를 모두 담는 새 타입을 만들어야 한다. 글은 이런 작업이 반복되면 오류를 문자열로 바꾸는 지름길을 택하게 될 수 있다고 주장한다.

제안된 설계는 모든 실패 타입이 사람이 읽을 수 있는 메시지와 선택적 원인 오류를 제공하도록 IFault 계약을 둔다. Report<'Pass, 'Fail>은 성공을 Pass, 실패를 Fail로 나타내며, 제네릭 제약으로 실패 타입이 IFault를 구현하도록 한다. 구체적인 오류 타입을 유지해 실패를 빠짐없이 처리할 수도 있고, 공통 인터페이스인 IFault로 일반화해 서로 다른 라이브러리의 오류를 함께 다룰 수도 있다는 설명이다. 특정 오류 타입만 별도로 처리하고 나머지는 일반적으로 처리하는 FailAs 활성 패턴도 제시한다.

2024년 12월 30일에 갱신된 글은 이 접근법이 모든 오류 처리에서 빠짐없는 처리를 대체하는 것은 아니라고 덧붙였다. 특히 핵심 도메인 로직에서는 오류를 구체적으로 처리해야 하며, IFault 사용은 보통 실제 오류 타입과 관계없이 같은 방식으로 처리하는 애플리케이션의 가장자리 같은 상황을 위한 것이라고 설명한다. 오류에 string을 쓰는 것은 피해야 하며, 이 점은 Result를 쓸 때도 품질 점검 대상이라고 강조했다.

글은 현재 FSharp.Core.Result가 생태계 전반에 널리 퍼져 있어 전체 생태계를 바꾸는 노력은 현실적으로 가치가 크지 않을 수 있다고 본다. FaultReport에 관한 설계와 추가 자료는 gist에서 볼 수 있다. 글은 2024 F# Advent Calendar의 일부다.