RBS와 Steep의 문서화 시스템 아키텍처 및 효율성 개선을 위한 인덱스 API 제안

[EN] API for docs / Soutaro Matsumoto @soutaro

3줄 요약

  • Steep은 RBS 기반으로 Ruby 코드의 문서화 기능을 제공하며, 편집기 내에서 실시간으로 문서 정보를 표시합니다.
  • 현재 문서 변경 시 불필요한 타입 검사가 발생하는 문제를 해결하기 위해, 문서 시스템과 타입 검사기 간의 명확한 인덱스 API 도입이 제안됩니다.
  • 이 API는 정규화된 메서드 타입을 식별자로 사용하여 효율성을 높이고, 향후 다른 도구들과의 통합 가능성을 제시합니다.

본 발표는 Ruby 프로그래밍 언어의 타입 선언 언어인 RBS와 이를 기반으로 하는 정적 타입 검사기 Steep의 문서화 기능에 초점을 맞춥니다. 발표자인 Sut은 RBS 커미터이자 Steep 개발자로서, Steep이 어떻게 Ruby 프로그램 요소(클래스, 모듈, 메서드, 타입 정의)에 대한 문서 정보를 제공하는지 설명합니다. 특히, 코드 편집기 환경에서 사용자의 인터랙션에 따라 실시간으로 문서가 표시되는 기능과 그 구현 방식을 상세히 다룹니다. 기존 RDoc이나 YARD와 같은 전통적인 문서화 도구와는 차별화된, 온디맨드 방식의 문서 제공 시스템을 소개하며, 이 시스템의 내부 아키텍처와 향후 개선 방향을 제시하는 것이 본 발표의 핵심 목표입니다.

Steep의 문서화 기능은 크게 ‘호버(Hover)’, ‘완성(Completion)’, ‘시그니처 도움말(Signature Help)’로 나뉩니다. 호버 기능은 사용자가 코드에 마우스를 올렸을 때 해당 요소의 문서를 표시하며, 완성 기능은 메서드 이름 등을 입력할 때 관련 문서와 함께 자동 완성 목록을 제공합니다. 시그니처 도움말은 메서드 인자를 작성할 때 가능한 파라미터 목록과 메서드 문서를 보여줍니다. 이 모든 문서 정보는 RBS 파일 내에 마크다운 형식으로 작성된 주석에서 가져옵니다.

이러한 기능의 구현은 Steep의 내부 API를 기반으로 합니다. RBS 파일은 내부 데이터 구조로 로드되며, 편집기는 언어 서버 프로토콜(Language Server Protocol)을 통해 Steep에 문서 요청을 보냅니다. Steep의 언어 서버는 이 요청을 받아 문서를 조회하고 마크다운 형식으로 포맷하여 편집기로 다시 전송합니다. 이는 RDoc이나 YARD처럼 HTML/PDF 형태의 정적 문서를 생성하는 방식과 달리, 사용자의 즉각적인 상호작용에 반응하여 동적으로 문서 조각을 생성하는 방식입니다.

Steep의 문서화 시스템은 RBS의 AST(Abstract Syntax Tree) 객체에 주석을 연결하고, 이를 환경(Environment) 객체 내의 정의(Definition)로 변환하여 관리합니다. 타입 검사기는 Ruby 프로그램의 각 노드에 타입을 할당하면서 관련된 문서 정보를 찾아냅니다. 예를 들어, 상수의 경우 해당 클래스 선언의 주석을, 메서드 호출의 경우 오버로드된 메서드의 주석을 식별합니다.

그러나 현재 시스템에는 한계가 있습니다. RBS 파일에서 주석만 변경해도 전체 타입 검사가 다시 실행되어 비효율적입니다. 주석 변경은 타입 검사 결과에 영향을 미치지 않기 때문입니다. 이 문제를 해결하기 위해, 발표자는 문서 시스템과 타입 검사기 사이에 ‘문서 인덱스 API’를 도입할 것을 제안합니다. 이 인덱스는 RBS 파일 로드 시 문서 정보를 등록하고, 주석만 변경될 경우 인덱스만 업데이트하며 타입 검사는 실행하지 않습니다. 언어 서버는 이 인덱스에서 식별자를 통해 문서를 조회합니다.

인덱스 API의 핵심은 ‘식별자’ 설계입니다. 클래스 문서는 클래스 이름으로 식별하기 쉽지만, 메서드 오버로드의 경우 복잡합니다. 파일명과 라인 번호는 주석 변경 시 불안정하며, 오버로드 인덱스는 파일 로딩 순서에 따라 달라질 수 있어 안정적이지 않습니다. 최종적으로 발표자는 ‘정규화된 메서드 타입’을 식별자로 사용할 것을 제안합니다. 이는 파라미터 이름 생략, 키워드 인자 정렬 등의 정규화 과정을 거친 RBS 메서드 타입 표기법을 의미합니다. 메서드 타입이 변경될 경우 식별자도 무효화되지만, 이는 어차피 타입 검사가 필요한 경우이므로 문제가 되지 않습니다. 이 방식은 JVM의 메서드 디스크립터와 유사하며, 안정적이고 가독성이 높으며 구현에 독립적이라는 장점을 가집니다. 이 인덱스 API를 통해 문서 시스템과 타입 검사기를 명확히 분리할 수 있습니다.

결론적으로, Steep의 문서화 기능은 개발자들이 Ruby 코드와 RBS 타입 정의 사이에서 문서 정보를 효율적으로 탐색할 수 있도록 돕습니다. 특히, 제안된 문서 인덱스 API는 현재 시스템의 비효율성을 해결하고, 문서 시스템과 타입 검사기 간의 명확한 경계를 설정하여 시스템의 안정성과 성능을 향상시킬 것입니다. 정규화된 메서드 타입을 식별자로 사용하는 방안은 오버로드된 메서드 문서화의 복잡성을 해결하는 핵심 열쇠로 작용합니다. 더 나아가, 이 인덱스 API는 RDoc, YARD, Ruby LSP와 같은 다른 Ruby 도구들과의 통합 가능성을 열어주며, 정의 및 참조 위치 저장 등 추가적인 활용 방안도 모색될 수 있습니다. 이는 Ruby 개발 생태계 전반의 문서화 및 개발 경험을 개선하는 데 기여할 잠재력을 가집니다.