데이터 흐름 내에서 nil 값 처리 및 오류 방어를 위한 if/else문의 과도한 사용은 코드를 복잡하게 만듭니다. Ruby는 .try(...), presence, & 연산자 등을 제공하지만, 본문에서는 dry-monads 라이브러리의 모나드를 활용하는 새로운 접근 방식을 제시합니다.
모나드(Monads) 개요
모나드는 카테고리 이론에서 유래한 개념이지만, 프로그래밍에서는 함수형 프로그래밍 관점에서 일관된 값 반환 구조를 의미합니다. 이는 작업의 성공 또는 실패 정보를 선택적 페이로드와 함께 전달하며, 이를 통해 개별 구성 요소의 결과를 지속적으로 확인할 필요 없이 함수들을 체인으로 연결할 수 있습니다.
Maybe 모나드
dry-monads의 Maybe 모나드는 Some(성공) 또는 None(nil 처리) 값을 반환합니다. 초기 SendPackage 예제를 Maybe로 리팩터링하면 if/unless/else 표현식을 제거하고 코드를 간결하게 만들 수 있습니다. bind는 Some일 때 블록을 실행하고, fmap은 반환 값을 Maybe로 감싸는 역할을 합니다. 그러나 중첩된 작업은 가독성을 저해하고 오류 원인에 대한 정보를 제공하지 못하는 단점이 있습니다.
Result 모나드
Result 모나드는 Success 또는 Failure 값을 반환하며, 각 값은 페이로드(성공 값 또는 오류 메시지)를 담을 수 있습니다. 이를 통해 오류 발생 시 구체적인 원인을 전달할 수 있으며, success? 및 failure? 메서드로 결과 유형을 확인하고 success 또는 failure 메서드로 페이로드를 접근합니다.
Do-notation
dry-monads 1.0부터 도입된 do-notation은 yield 키워드를 사용하여 모나드 중첩을 제거하고 코드를 순차적으로 보이게 합니다. yield는 전달된 메서드가 Success(value)를 반환하면 해당 value를 반환하고, Failure를 반환하면 즉시 호출을 중단하고 Failure를 반환합니다.
Try 모나드
Try 모나드는 외부 함수에서 발생하는 예외를 처리하는 데 사용됩니다. 특정 예외 유형을 지정하여 처리하는 것이 권장되며, Value(예외 없음) 또는 Error(예외 발생)를 반환합니다. .to_result 메서드를 사용하여 Result 도메인으로 쉽게 변환할 수 있습니다.
Railway Oriented Programming (ROP)
Scott Wlaschin이 소개한 ROP는 프로그램이 따를 수 있는 성공 및 실패 경로의 존재를 가정합니다. 모나드를 통해 각 단계의 성공/실패 여부에 따라 적절한 경로로 전환되며, 최종 결과 처리는 최상위 호출에서 한 번에 이루어집니다. 이는 철도의 선로와 스위치에 비유될 수 있으며, 프로세스 구성 요소를 쉽게 조합하고 관리할 수 있도록 돕습니다. Ruby 2.7+의 패턴 매칭을 활용하면 case문을 통해 다양한 결과 유형을 깔끔하게 처리할 수 있습니다.