원시 타입 대신 도메인 타입을 사용해야 하는 이유

by DD
1개월 전
조회수 12

원시 타입(Primitive Type) 사용의 문제점: 단순 타입은 코드의 의미를 담지 못해, 오류 발생 가능성이 높음

도메인 타입(Domain Type) 도입: ShopId, CustomerId와 같이 의미를 명확히 하는 타입을 정의하여 타입 안전성(Type Safety)을 강화

구현 방법: Rust, Go, TypeScript에서 구체적인 구현 예시를 제시하고, Deref 트레이트(trait)를 활용하여 편의성을 높임

커뮤니티 반응: 원시 타입의 한계를 지적하며, 코드의 명확성(Clarity)유지 보수성(Maintainability) 향상에 대한 기대감을 표명

원시 타입의 문제점: 의미 손실

게시물은 원시 타입(Primitive Type)이 코드의 의미를 충분히 표현하지 못해 발생하는 문제점을 지적한다. 특히, `String`, `int`, `float`와 같은 기본 타입은 도메인 지식(Domain Knowledge)을 담지 못하므로, 개발자가 실수로 잘못된 값을 할당하거나, 변수의 의미를 혼동하여 예기치 않은 버그(Unexpected Bugs)를 발생시킬 수 있다고 강조한다. 예를 들어, `ShopId`와 `CustomerId`가 모두 `String` 타입으로 정의되어 있다면, 컴파일러는 두 변수의 의미적 차이를 구분하지 못한다.

새로운 타입 정의를 통한 해결책

저자는 도메인 타입(Domain Type)을 정의하여 이러한 문제를 해결할 것을 제안한다. Rust의 `struct ShopId(String)`와 같이, 의미를 가지는 새로운 타입을 정의함으로써, 컴파일러가 타입 레벨(Type Level)에서 데이터의 의미를 이해하도록 한다. 이 방식을 통해, `ShopId` 대신 `CustomerId`를 사용하는 실수를 컴파일 타임에 감지할 수 있으며, 코드의 가독성(Readability)유지 보수성(Maintainability)을 향상시킬 수 있다. 또한, 유효성 검사(Validation)를 생성자에 추가하여, 잘못된 데이터가 시스템에 유입되는 것을 방지할 수 있다.

언어별 구현 방식 비교

게시물은 Rust, Go, TypeScript에서 도메인 타입을 구현하는 방법을 제시한다. Rust에서는 `struct`와 `Deref` 트레이트를 사용하여, 새로운 타입의 메서드 접근성을 확보하고, Go에서는 타입 정의를 통해, TypeScript에서는 브랜드 타입(Branded Types)을 사용하여 타입 안전성을 확보한다. 특히, TypeScript의 브랜드 타입(Branded Types)은 런타임 오버헤드 없이 컴파일 타임에 타입 검사를 수행할 수 있다는 장점이 있다. 각 언어별 구현 방식은 언어의 특징(Language Features)에 따라 차이를 보이며, 개발자는 자신의 프로젝트에 적합한 방식을 선택할 수 있다.

커뮤니티의 반응: 타입 안전성에 대한 공감대

댓글에서는 게시물의 내용에 공감하며, 원시 타입(Primitive Type) 사용의 위험성에 대한 인식을 공유한다. 특히, 원시 타입(Primitive Type)에 대한 집착(Primitive Obsession)은 코드의 복잡성을 증가시키고, 버그 발생 가능성을 높인다는 점을 지적한다. 또한, 타입 시스템(Type System)을 활용하여 코드의 안전성을 높이는 방법에 대한 논의가 이루어지며, 코드의 명확성(Clarity)유지 보수성(Maintainability)을 향상시키는 데 기여할 수 있다는 긍정적인 평가가 나온다.

Everything Should Be Typed: Scalar Types Are Not Enough