Rust, 유효성 검사 대신 파싱? 타입 시스템 활용법

by DD
3개월 전
조회수 22

'Parse, Don't Validate'는 런타임 오류를 방지하기 위해 유효성 검사 대신 타입 시스템을 활용하는 Rust 디자인 패턴임

NonZeroF32NonEmptyVec과 같은 새로운 타입을 정의하여 불변성을 컴파일 타임에 보장하는 것이 핵심

과도한 추상화(Abstraction)로 인한 코드 복잡성 증가에 대한 우려와, 유효성 검사(Validation)의 실용성을 강조하는 반론도 제기됨

UI 디자인 시스템(UI Design System), JSON 파싱(JSON Parsing) 등 실제 사례를 통해 패턴의 유용성을 설명

'Parse, Don't Validate' 패턴의 핵심 원리

본 기사에서 제시된 'Parse, Don't Validate' 패턴은 런타임 시 발생할 수 있는 오류를 컴파일 타임에 감지하기 위해 타입 시스템(Type System)을 적극적으로 활용한다. 특히, 유효하지 않은 상태를 표현할 수 없도록 설계하여, NonZeroF32와 같이 0이 아닌 f32 값을 보장하는 새로운 타입을 정의한다. 이를 통해 런타임 오류를 사전에 방지하고, 코드의 안정성을 높이는 것을 목표로 한다.

타입 시스템을 활용한 불변성 보장

핵심은 불변성(Invariants)을 런타임이 아닌 컴파일 타임에 검증하는 것이다. 예를 들어, `NonZeroF32` 타입은 0으로 나눗셈하는 오류를 방지하기 위해 사용된다. 이 방식은 유효성 검사 함수를 사용하는 대신, 파싱(Parsing)을 통해 입력값을 검증하고, 유효한 값만 새로운 타입으로 변환한다. 이러한 접근 방식은 코드의 가독성을 높이고, 잠재적인 오류를 줄이는 데 기여한다.

코드 복잡성 증가에 대한 우려

일부 개발자들은 'Parse, Don't Validate' 패턴이 과도한 추상화(Abstraction)를 유발하여 코드의 복잡성을 증가시킬 수 있다고 지적한다. 특히, 여러 개의 새로운 타입을 생성하고, 각 타입에 대한 연산을 정의하는 과정은 코드의 양을 늘리고, 유지 보수를 어렵게 만들 수 있다. 또한, 유효성 검사(Validation)가 더 실용적인 경우도 존재하며, 모든 상황에 이 패턴을 적용하는 것이 최선은 아니라는 의견도 제시된다.

실제 사례 및 다른 언어와의 비교

기사에서는 Stringserde_json과 같은 실제 사례를 통해 'Parse, Don't Validate' 패턴의 유용성을 설명한다. 또한, 다른 언어, 특히 Idris와 같은 종속 타입(Dependent Typing)을 지원하는 언어와의 비교를 통해, Rust의 타입 시스템이 가진 강점을 강조한다. UI 디자인 시스템(UI Design System)에서 컴파일 타임에 레이아웃 제약 조건을 검증하는 사례는 이 패턴의 실용적인 적용을 보여준다.

트레이드오프(Trade-offs) 및 대안

본 패턴은 코드의 안전성을 높이지만, 코드의 양과 복잡성 증가라는 트레이드오프를 수반한다. 특히, `try_roots` 예시에서 볼 수 있듯이, 모든 경우에 이 패턴이 적합한 것은 아니다. 유효성 검사(Validation)가 더 간결하고 직관적인 해결책이 될 수 있으며, 상황에 따라 적절한 방법을 선택해야 한다. 또한, C++의 개념(Concepts)과 같은 다른 기술을 활용하여 비슷한 목표를 달성할 수도 있다.

Parse, Don't Validate and Type-Driven Design in Rust