성능 문제점
이전의 Rails 복수화 시스템은 각 복수화 검사마다 불필요한 연산을 수행했습니다. 정규식 패턴은 한 번 컴파일되었지만, 시스템은 여전히 각 패턴을 개별적으로 반복하며 확인해야 했습니다. 또한, Uncountables 클래스가 Array를 상속받아 불필요한 오버헤드를 발생시켰습니다. 셀 수 없는 단어인지 확인하는 과정은 각 패턴을 반복하고, 여러 개별 정규식 매치를 수행하며, 복잡한 배열 상속 구조를 유지하는 것을 의미했습니다.
Rails 최적화 접근 방식
이번 최적화는 세 가지 주요 개선 사항을 도입했습니다.
Regexp.union()을 활용한 정규식 캐싱- 이전: 각 단어에 대해
/#{Regexp.escape(word)}/i와 같은 개별 정규식을 생성하여 매치 여부를 확인했습니다. 이는 각 검사마다 여러 번의 정규식 컴파일 및 매치를 유발했습니다. - 이후:
Regexp.union(@members.map { |w| /#{Regexp.escape(w)}/i })를 사용하여 모든 셀 수 없는 단어 패턴을 하나의 캐시된 정규식으로 결합했습니다. 이 단일 정규식을 통해 매치 여부를 한 번에 효율적으로 확인할 수 있게 되었습니다.
- 이전: 각 단어에 대해
-
상속 대신 컴포지션(Composition) 사용
Uncountables클래스는 더 이상Array를 상속받지 않습니다. 대신@members라는 내부 배열을 사용하여 컴포지션을 구현하고, 필요한 메서드(<<,concat,each,clear,to_a)는Forwardable모듈을 통해 위임합니다. 이는 불필요한 배열 상속 구조의 복잡성을 제거하고 오버헤드를 줄입니다. - 영어 굴절을 위한 빠른 경로(Fast Path)
영어 굴절을 위한 전용 캐시를 도입하여 인스턴스 조회를 줄였습니다.
instance메서드에서:en로케일의 경우@__en_instance__를 캐시하여 반복적인 인스턴스 생성을 방지합니다.
성능 결과
이 최적화는 모든 복수화 유형에서 상당한 개선을 가져왔습니다.
- 일반(regular): 18% 더 빨라짐
- 불규칙(irregular): 128% 더 빨라짐
- 셀 수 없는(uncountable): 304% 더 빨라짐 (4배)
특히 셀 수 없는 단어는 초당 1.487M에서 6.008M 반복으로 증가하여 가장 극적인 개선을 보였습니다.
이 최적화가 중요한 경우
이 최적화는 다음과 같은 애플리케이션에 특히 유용합니다.
- 뷰(views) 및 헬퍼(helpers)에서 단어를 자주 복수화하는 경우
- 텍스트 굴절이 포함된 대규모 데이터셋을 처리하는 경우
- 반복문 내에서 Rails의 내장 복수화 기능을 사용하는 경우
- 복수화가 필요한 사용자 생성 콘텐츠를 처리하는 경우
기술 심층 분석 및 이점
Regexp.union() 메서드는 루비 정규식 엔진이 효율적으로 처리할 수 있는 최적화된 교체 패턴을 생성하여, 이전처럼 각 정규식을 개별적으로 확인하는 대신 단일 통합 정규식으로 모든 셀 수 없는 단어를 처리합니다. 이는 CPU 오버헤드와 반복 작업으로 인한 성능 오버헤드를 줄이고, 불필요한 Array 상속을 제거하여 구조적 복잡성도 낮춥니다. 텍스트 처리가 많은 Rails 애플리케이션은 이러한 효율성 향상으로부터 가장 큰 이점을 얻을 것입니다.