Robocop의 진화: 플러그인, LSP 통합, AST 변화를 통한 미래 지향적 개발

[JA] RuboCop: Modularity and AST Insights / Koichi ITO @koic

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

핵심 요약

  • 1 Robocop은 비공식적인 몽키 패치 방식의 플러그인 시스템을 공식적인 LintRoller 기반의 방식으로 전환하여 유지보수성과 확장성을 개선했습니다.
  • 2 Ruby LSP와 Robocop 내장 LSP 런타임이 어댑터를 통해 통합되어 코드 재사용성을 높이고 중복 파싱을 줄여 성능 향상을 도모합니다.
  • 3 Ruby 3.4 이상 버전에서 Robocop의 기본 파서가 Parser Gem에서 Prism (prism_translation_parser)으로 변경되어 최신 Ruby 문법 지원 및 유지보수성이 강화되었습니다.

도입

본 발표는 Ruby 개발에 널리 사용되는 코드 린터 및 포맷터인 Robocop의 최근 1년간의 주요 변화와 미래 방향성을 다룹니다. 특히, Robocop의 플러그인 시스템 개선, Ruby LSP와의 통합, 그리고 추상 구문 트리(AST) 파서의 변화에 초점을 맞춥니다. 이는 Robocop이 직면했던 기술적 한계를 극복하고, 더욱 견고하며 확장 가능한 형태로 발전하려는 노력을 보여줍니다. 발표자는 Robocop 커미터로서 이러한 변화의 배경과 기술적 세부 사항을 공유하며, Ruby 생태계 전반에 미칠 영향에 대해 논의합니다.

Robocop 플러그인 시스템의 진화

  • 기존 문제점: Robocop은 Ruby 스타일 가이드를 구현한 도구로, 사용자 정의 스타일을 지원하기 위해 enforced_stylesupported_styles 같은 설정을 제공합니다. 그러나 기존의 플러그인 확장 방식은 inject와 같은 비공식적인 몽키 패치를 사용했으며, 이는 코드 재사용성 저해, 버그 발생률 증가, 유지보수 난이도 상승 등의 문제를 야기했습니다.
  • LintRoller 도입: 이러한 문제를 해결하기 위해 LintRoller라는 중간 계층이 도입되었습니다. LintRoller는 플러그인과 Robocop(또는 Standard Ruby) 같은 런너 사이의 통신을 담당하며, Rails와 애플리케이션 서버 사이의 Rack과 유사한 역할을 수행합니다.
  • 새로운 플러그인 개발 방식: 플러그인 개발자는 LintRoller::Plugin을 상속받는 플러그인 클래스를 생성하고, aboutrules 메서드를 구현하여 플러그인 정보와 설정 파일 경로를 제공합니다. 또한, gemspec의 메타데이터(default_lint_roller_plugin)를 통해 Robocop이 플러그인 클래스를 인지하도록 합니다.
  • 사용자 설정 변경: .rubocop.yml 파일에서 기존의 require 대신 plugins 키워드를 사용하여 플러그인을 로드하도록 변경되었습니다. 이는 사용자에게 더 명확하고 공식적인 플러그인 로딩 방식을 제공합니다.

Ruby LSP 및 Robocop LSP 통합

  • LSP의 중요성 증가: Rails 7.1 이후 개발 컨테이너에서 Ruby LSP가 기본으로 활성화되는 등 LSP(Language Server Protocol)의 중요성이 커지고 있습니다. Ruby LSP는 Robocop의 기능을 활용하기 위해 독자적인 확장을 시도해왔습니다.
  • 구현 재사용: Robocop은 이미 내장 LSP 기능을 가지고 있었으며, Ruby LSP는 이 Robocop LSP 런타임을 어댑터 패턴을 통해 재사용하도록 구현되었습니다. 이는 중복 구현을 방지하고, Robocop의 LSP 기능을 Ruby LSP 생태계에서 활용할 수 있게 합니다.
  • 성능 및 재사용성: 이 통합을 통해 Ruby LSP가 한 번 파싱한 소스 코드를 Robocop이 다시 파싱할 필요 없이 재사용할 수 있게 되어 전체적인 성능 향상과 자원 효율성을 기대할 수 있습니다. 현재 이 기능은 실험 단계에 있습니다.

AST 및 파서의 변화: Parser Gem에서 Prism으로

  • Parser Gem의 한계: Robocop은 오랫동안 parser_gem을 Ruby 코드의 추상 구문 트리(AST) 파서로 사용해왔습니다. 그러나 parser_gem은 Ruby 3.4의 블록 파라미터와 같은 최신 문법을 지원하지 못하고, 유지보수가 사실상 중단된 상태입니다.
  • Prism으로의 전환: 이러한 문제로 인해 Robocop은 prism_translation_parser를 통해 Prism을 새로운 기본 파서로 채택했습니다. Robocop 1.62부터 선택적으로 Prism을 사용할 수 있었으며, Robocop 1.75 이상에서는 Ruby 3.4+ 환경에서 Prism이 기본 파서로 동작합니다.
  • 유지보수성 및 미래 지향: Prism은 Ruby 자체에서 개발 및 유지보수되고 있어 최신 Ruby 문법을 빠르게 지원하며, parser_gem에 비해 훨씬 안정적인 유지보수를 기대할 수 있습니다. 이는 Robocop의 장기적인 안정성과 발전 가능성을 높입니다.
  • AST/CST 논의: 파서 변경은 기존 커스텀 Cop 개발자들에게 AST 패턴 매칭 방식 변경 등 상당한 영향을 미칠 수 있습니다. AST와 CST(Concrete Syntax Tree) 중 어떤 것이 더 적합한지에 대한 논의가 있으며, 현재로서는 기존 AST 인터페이스를 유지하면서 내부적으로 Prism을 활용하는 방식이 채택되었습니다. 이는 기존 생태계에 미치는 영향을 최소화하면서 점진적인 전환을 목표로 합니다.

결론

Robocop은 지난 한 해 동안 플러그인 시스템의 현대화, Ruby LSP와의 긴밀한 통합, 그리고 AST 파서의 근본적인 변화를 통해 큰 발전을 이루었습니다. 비공식적인 몽키 패치 방식에서 벗어나 `LintRoller` 기반의 공식 플러그인 시스템을 도입함으로써 유지보수성과 확장성을 크게 개선했습니다. 또한, Ruby LSP와 Robocop 내장 LSP 런타임의 재사용 가능한 통합은 Ruby 개발 환경의 효율성을 높일 것입니다. 가장 중요한 변화 중 하나는 Ruby 3.4 이상에서 `parser_gem`을 대체하여 `Prism`을 기본 AST 파서로 채택한 것으로, 이는 Robocop이 최신 Ruby 문법을 안정적으로 지원하고 장기적인 유지보수성을 확보하는 데 필수적인 조치입니다. 이러한 변화들은 Robocop이 Ruby 생태계에서 핵심 도구로서의 역할을 더욱 공고히 하고, 미래의 Ruby 개발 환경에 기여할 기반을 마련합니다.

댓글 0

댓글 작성

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

아직 댓글이 없습니다

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