RBS와 Steep 문서화 기능 및 내부 API 개선 방안

[EN] API for docs / Soutaro Matsumoto @soutaro

작성자
RubyKaigi
발행일
2025년 05월 27일

핵심 요약

  • 1 Steep은 LSP를 통해 RBS 파일에 정의된 주석 기반의 문서화 기능(호버, 자동 완성, 시그니처 도움말)을 제공합니다.
  • 2 현재 문서화 시스템은 타입 체커와 긴밀히 결합되어 주석 변경 시 불필요한 전체 타입 검사가 발생하며, 이를 해결하기 위해 '인덱스' API 도입이 제안되었습니다.
  • 3 메서드 오버로드 식별의 복잡성을 해결하기 위해 정규화된 메서드 타입을 식별자로 사용하는 방안이 제시되었으며, 이는 시스템 분리와 재활용성을 높일 것으로 기대됩니다.

도입

발표자는 Ruby의 타입 선언 언어인 RBS와 정적 타입 체커인 Steep의 개발자로서, Steep이 제공하는 문서화 기능과 그 내부 구현에 대해 설명합니다. 특히, RBS 파일에 작성된 주석이 IDE에서 어떻게 호버, 자동 완성, 시그니처 도움말과 같은 형태로 사용자에게 제공되는지를 다루며, 현재 시스템의 한계점과 이를 극복하기 위한 새로운 내부 API 설계 아이디어를 제시합니다. 이 발표는 RBS와 Steep의 최신 업데이트 소식과 함께 문서화 시스템의 기술적 깊이를 탐구합니다.

Steep의 문서화 기능은 프로그래머가 Ruby 프로그램 컴포넌트(클래스, 모듈, 메서드 등)의 문서를 쉽게 읽을 수 있도록 돕습니다. 주요 기능은 다음과 같습니다.

Steep의 문서화 기능

  • 호버(Hover): 소스 코드의 클래스 이름이나 메서드 호출 위에 커서를 올리면 관련 문서가 표시됩니다.
  • 자동 완성(Completion): 메서드 이름을 입력할 때 가능한 메서드 목록과 함께 첫 번째 항목의 문서가 나타납니다.
  • 시그니처 도움말(Signature Help): 메서드 인수를 작성할 때 가능한 파라미터 목록과 메서드 문서가 제공됩니다. 이러한 문서의 출처는 RBS 파일 내에 마크다운 형식으로 작성된 주석이며, Language Server Protocol(LSP)을 통해 편집기에 전달됩니다.

내부 구현 아키텍처

Steep의 문서화 기능은 내부 API 위에 구축됩니다. 1. AST와 주석: RBS 파일은 RBS::AST 객체로 파싱되며, 각 선언(클래스, 메서드, 속성)은 RBS::Comment 객체를 포함하는 comment 속성을 가집니다. RBS::Comment는 주석의 문자열 내용을 저장합니다. 2. 파서(rbs_parse): get_comment 함수를 통해 def 토큰과 같은 현재 토큰의 라인 번호를 기준으로 주석을 찾아 RBS::Comment 객체를 생성하고 AST 객체에 연결합니다. 3. 환경(Environment): RBS gem은 파싱된 RBS 파일을 RBS::Environment 객체에 저장하며, 이는 RBS::Definition 객체로 변환되어 메서드, 변수, 상속 관계 등을 관리합니다. 각 Method 객체는 주석 객체 배열을 가집니다. 4. 타입 체커: Steep의 타입 체커는 Ruby 프로그램의 각 노드에 타입을 할당하고, 상수나 메서드 호출과 관련된 타입을 기반으로 Environment에서 해당 문서(주석)를 찾아냅니다. LSP 서버는 편집기의 요청에 따라 이 정보를 JSON 형식의 마크다운 문서로 변환하여 반환합니다.

현재 시스템의 문제점

현재 시스템은 문서화 시스템과 타입 체커가 긴밀히 결합되어 있습니다. RBS 파일에서 주석만 변경되어도 내부 오버로드 데이터 구조가 업데이트될 수 있어, 불필요하게 전체 타입 검사를 다시 실행해야 하는 문제가 발생합니다. 이는 타입 검사 결과에는 영향을 주지 않음에도 불구하고 성능 저하를 야기합니다.

해결책: 문서화 인덱스(Index) API 도입

이 문제를 해결하기 위해 문서화 시스템과 타입 체커 사이에 명확한 경계를 설정하는 ‘인덱스’ API 도입이 제안됩니다. * 동작 방식: Steep이 RBS 파일을 로드할 때, 인덱스는 문서화를 등록합니다. 주석만 변경되면 인덱스만 업데이트되고 타입 체커는 실행되지 않습니다. LSP 서버는 식별자를 통해 인덱스에서 문서를 조회합니다. * 장점: * 문서화 시스템과 타입 체커의 결합도 감소. * 서버 재시작 후 인덱스 재활용 가능 (식별자가 직렬화 가능하다면). * 인덱스 분산 가능성.

메서드 오버로드 식별자 설계

인덱스 API의 핵심 과제는 메서드 오버로드를 안정적으로 식별하는 것입니다. * 기존 방식의 한계: String#hash와 같은 표기법은 오버로드가 여러 개일 때 특정 오버로드를 지칭하기 어렵습니다. 파일명/라인 번호는 주석 수정 시 변경될 수 있고, 오버로드 인덱스는 파일 로딩 순서에 따라 불안정하며 가독성이 떨어집니다. * 제안된 해결책: 정규화된 메서드 타입을 식별자로 사용합니다. * 메서드 이름 뒤에 전체 메서드 시그니처(타입)를 붙여 어떤 오버로드인지 명확히 합니다. * 메서드 타입이 변경되면 식별자가 무효화되지만, 이는 타입 검사가 필요한 상황이므로 문제가 없습니다. * JVM의 메서드 디스크립터와 유사한 접근 방식입니다. * 정규화: 파라미터 이름은 제외하고, 키워드 인수는 정렬하여 일관성을 유지합니다. * 이렇게 정규화된 메서드 타입은 안정적이고 구현에 독립적이며, 파일 저장, 로드, 비교가 용이한 문자열 형태의 식별자가 됩니다.

향후 확장 가능성

이 인덱스는 “Go to Definition”이나 “Go to Reference”와 같은 기능 구현을 위해 정의 및 참조 위치를 저장하는 데도 활용될 수 있습니다. 또한, RDoc이나 YARD와 같은 다른 문서화 도구와의 연동 가능성도 논의될 수 있습니다.

결론

발표는 Steep의 현재 문서화 기능과 그 기반이 되는 RBS의 내부 구조를 상세히 설명하며, 주석 변경 시 발생하는 불필요한 타입 검사 문제를 명확히 지적했습니다. 이에 대한 해결책으로 '문서화 인덱스' API의 도입과 정규화된 메서드 타입을 활용한 안정적인 오버로드 식별자 설계가 제시되었습니다. 이 제안은 문서화 시스템과 타입 체커의 독립성을 확보하고, 성능을 개선하며, 향후 다양한 개발 도구와의 연동 가능성을 열어줄 것으로 기대됩니다. 비록 아직 구현 단계는 아니지만, 이 설계 아이디어는 Ruby 타입 시스템의 발전 방향을 제시하는 중요한 논의가 될 것입니다.

댓글 0

댓글 작성

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

아직 댓글이 없습니다

첫 번째 댓글을 작성해보세요!