본문으로 건너뛰기

494: 원시 타입 집착(Primitive Obsession)과 도메인 모델링

494: Primitive Obsession

작성자
thoughtbot Youtube
발행일
2026년 02월 25일
https://www.youtube.com/watch?v=Px3l8a4VyAk

핵심 요약

  • 1 원시 타입 집착(Primitive Obsession)은 데이터의 의미를 타입 시스템이 아닌 프로그래머의 암시적 지식에 의존하게 만드는 안티 패턴입니다.
  • 2 단순한 배열이나 정수 대신 전용 도메인 객체를 생성하여 캡슐화하면 로직의 파편화를 방지하고 코드의 가독성과 재사용성을 높일 수 있습니다.
  • 3 PostgreSQL의 재귀 쿼리와 구체화(Materialization) 기법을 활용하면 복잡한 그래프 구조의 데이터를 정규화된 상태로 효율적으로 관리할 수 있습니다.

도입

이번 에피소드에서는 소프트웨어 개발에서 흔히 발생하는 '원시 타입 집착'이라는 개념을 중심으로, 복잡한 데이터 구조를 효과적으로 모델링하는 방법을 다룹니다. Joel Kenville과 Sally Hall은 하청 관계와 같은 복잡한 그래프 형태의 데이터를 PostgreSQL에서 처리하는 실무적인 고민에서 시작하여, Ruby on Rails 환경에서 도메인 언어를 반영한 객체 지향적 설계가 왜 중요한지 심도 있게 논의합니다. 특히 기본 데이터 타입에 과도하게 의존할 때 발생하는 유지보수의 어려움과 이를 해결하기 위한 구체적인 전략들을 제시합니다.

1. 그래프 데이터의 관계형 데이터베이스 모델링

  • 복잡한 관계 처리: 하청 업체 간의 관계와 같은 계층 구조는 단순한 1:N 관계를 넘어 그래프(Graph) 구조로 이해해야 합니다.
  • PostgreSQL 활용: 인접 리스트(Adjacency List)를 사용하여 관계를 정의하고, 재귀적 CTE(Common Table Expression)를 통해 성능 저하 없이 자손 노드들을 조회할 수 있습니다.
  • 구체화(Materialization): 조회 성능을 극대화하기 위해 ‘닫힘 테이블(Closure Table)’과 같은 비정규화된 데이터를 별도 관리하되, 원본 데이터를 단일 진실 공급원(Single Source of Truth)으로 유지하는 것이 중요합니다.

2. 원시 타입 집착(Primitive Obsession)의 이해

  • 정의: 비즈니스 개념(예: 장바구니, 세율, 시간 범위)을 표현할 때 전용 객체 대신 배열, 문자열, 정수와 같은 기본 타입을 과도하게 사용하는 현상입니다.
  • 문제점: 데이터에 대한 추가적인 의미가 프로그래머의 머릿속에만 존재하게 되어, 로직이 여러 곳으로 흩어지고 데이터 불일치가 발생할 위험이 커집니다.
  • 암시적 문맥의 위험: 예를 들어 nil이 단순히 ‘값 없음’이 아니라 ‘게스트 사용자’나 ‘에러’를 의미하게 될 때, 코드는 읽기 어렵고 오류에 취약해집니다.

3. 도메인 객체를 통한 해결 전략

  • 캡슐화와 추상화: 단순한 배열 대신 ShoppingCart 객체를 생성하면, 세금 계산이나 소계 산출과 같은 로직을 데이터와 함께 묶어 관리할 수 있습니다.
  • 점진적 개선: 처음부터 복잡한 클래스를 만들기보다 Ruby의 StructData 클래스를 활용하여 가볍게 시작한 뒤, 로직이 복잡해짐에 따라 정식 클래스로 전환하는 방식을 권장합니다.
  • 타입 시스템의 활용: 단위(Unit)와 차원(Dimension)을 명시하는 타입을 사용하면, 서로 다른 성격의 숫자(예: 거리와 시간)를 실수로 더하는 등의 논리적 오류를 사전에 차단할 수 있습니다.

4. Ruby on Rails에서의 실천 사례

  • 성공 사례: Rails의 ActiveSupport::Duration이나 Ruby의 Time 클래스는 내부적으로는 원시 값을 다루지만 외부에는 풍부한 도메인 인터페이스를 제공하는 훌륭한 예시입니다.
  • 코드 스멜(Code Smell): 맵(Map)이나 리듀스(Reduce) 블록이 지나치게 길어진다면, 해당 로직을 원시 타입이 아닌 도메인 객체의 메서드로 추출해야 한다는 신호일 수 있습니다.
  • 트레이드오프: 객체 생성에 따른 메모리 사용량 증가와 간접 참조 비용이 발생할 수 있으나, 대부분의 비즈니스 애플리케이션에서는 가독성과 유지보수성의 이점이 이를 압도합니다.

결론

결론적으로 원시 타입 집착에서 벗어나는 것은 단순히 코드를 깔끔하게 만드는 것을 넘어, 시스템의 유지보수성과 확장성을 결정짓는 핵심적인 설계 원칙입니다. 도메인 모델의 의미를 명확히 담은 전용 객체를 도입함으로써 버그를 줄이고 개발자 간의 의사소통을 원활하게 할 수 있습니다. 이는 Ruby가 지향하는 인간 중심적인 프로그래밍 철학, 즉 코드가 비즈니스 도메인을 직접적으로 설명해야 한다는 원칙과도 맞닿아 있으며, 성능과 가독성 사이의 균형을 맞추는 성숙한 개발자의 자세를 시사합니다.

댓글0

댓글 작성

댓글 삭제 시 비밀번호가 필요합니다.

이미 계정이 있으신가요? 로그인 후 댓글을 작성하세요.

0/1000
정중하고 건설적인 댓글을 작성해 주세요.