발표자는 Deprecation 문제 해결을 위한 RubyDepre
Gem의 구현 과정과 주요 도전 과제를 상세히 설명합니다.
1. RubyDepre
Gem 소개 및 영감
- Pharo 언어의 DepreWriter: Smalltalk 기반의 객체 지향 언어인 Pharo에는 런타임에 Deprecated 코드를 자동 리팩토링하는
DepreWriter
도구가 존재합니다. 이는 Deprecated 메서드 호출 시 예외를 발생시키고, 해당 호출 지점을 변환한 후 실행을 계속하는 방식으로 동작합니다. - 동적 타입 언어의 한계 극복: Pharo의 접근 방식은 동적 타입 언어에서 정적 분석만으로는 정확한 수정 범위를 파악하기 어려운 문제(예: 동일한 이름의 메서드가 여러 라이브러리에 존재)를 런타임 정보를 활용하여 해결합니다. 발표자는 이 아이디어를 Ruby에 적용하고자 했습니다.
2. RubyDepre
Gem 구현 상세
- 변환 규칙 정의:
deprewrite
메서드를 통해 Deprecated 메서드 이름과from
(기존 코드 패턴),to
(변환될 코드 패턴) 규칙을 정의합니다. Synvert
Gem 활용: 내부적으로Synvert
Gem을 사용하여 AST(추상 구문 트리) 기반의 코드 변환을 수행합니다. 특히Prism
파서를 통해 코드의CallNode
를 식별하고,node_mutation_ruby
를 활용하여 변환합니다.- 메서드 호출 인터셉션:
alias_method
와define_method
를 사용하여 Deprecated 메서드 호출을 가로챕니다. 가로챈 호출 내에서caller
정보를 통해 호출자의 소스 파일을 읽고,Prism
으로 AST를 분석하여 정확한 호출 노드를 찾습니다.from
규칙은 특정 호출 패턴만 변환하도록 정밀하게 대상을 지정하는 데 사용됩니다. - 코드 재구성: 변환된 코드와 원본 코드의 앞뒤 부분을 결합하여 수정된 소스 파일을 생성합니다.
3. 런타임 코드 변환의 안전성 및 출력 모드
- 안전성 문제: 런타임에 실제 동작 중인 코드를 직접 수정하는 것은 Ruby 환경에서 안전하지 않을 수 있습니다 (예: 코드 재실행으로 인한 부작용, 상수 재정의 문제).
- 사용 환경 및 출력 모드: 따라서
RubyDepre
는 주로 테스트 및 로컬 환경에서의 사용을 권장하며, 세 가지 출력 모드를 제공합니다.- 로그 모드: Deprecation 해소 방법을 로그로 출력합니다.
- Diff 모드: 수정 사항을
.diff
패치 파일로 생성하여 사용자가 수동으로 적용할 수 있도록 합니다. - 직접 파일 수정 모드: 위험하지만, 실제 파일을 직접 수정합니다 (데모에서 시연).
4. Ruby 에코시스템에서의 수용 가능성
- 가장 큰 과제:
RubyDepre
가 언어 내장 기능이 아닌 서드파티 Gem이라는 점이 수용에 가장 큰 걸림돌입니다. - 이상적인 시나리오: Pharo처럼 언어에 내장된다면 라이브러리 개발자가 변환 규칙을 포함하여 배포하고, 사용자는 코드 실행만으로 Deprecation을 해소할 수 있어 매우 편리할 것입니다.
- 차선책: 라이브러리 개발자가 사용하지 않더라도, 사용자 스스로 자신의 코드베이스 내 Deprecation을 해결하기 위한 도구로 활용할 수 있습니다. 이는 라이브러리 메서드에 몽키 패치로
deprewrite
규칙을 적용하는 방식이 될 수 있습니다.