Pyre의 경험을 바탕으로 설계된 차세대 Python 언어 서버 Pyrefly
Pyrefly는 Pyre의 후속작으로, 빠른 속도와 향상된 리팩토링(Refactoring) 및 타입 추론(Type Inference) 기능을 제공하는 Python 언어 서버임
Pyre의 CLI 중심 아키텍처(CLI-first Architecture)가 IDE 환경에서 성능 저하를 유발, Pyrefly는 유연한 아키텍처(Flexible Architecture)를 통해 이를 해결
OCaml에서 Rust로의 전환은 크로스 플랫폼(Cross-Platform) 지원을 강화하고, 개발자 커뮤니티 성장을 가속화함
사운드니스(Soundness)와 사용성(Usability) 간의 트레이드오프(Trade-off)를 통해 개발자 경험을 개선하고, 순환 종속성(Cyclic Dependencies) 캐싱을 지원하여 성능을 향상시킴
언어 서버(Language Server) 아키텍처의 진화
Pyre는 원래 CI(Continuous Integration) 환경에서 사용되는 CLI 도구로 설계되어 처리량(Throughput)에 중점을 두었다. 하지만 IDE 통합 시 지연 시간(Latency) 문제가 발생하여 사용자 경험을 저하시켰다. Pyrefly는 언어 서버 우선 아키텍처(Language-server-first Architecture)를 채택하여 CLI와 IDE 환경 모두에서 최적의 성능을 제공하도록 설계되었다. 특히, 구문 오류(Syntax Error) 발생 시에도 지속적으로 작동할 수 있도록 Ruff 파서(Parser)를 사용한다.
OCaml에서 Rust로의 전환: 플랫폼 종속성 극복
Pyre는 OCaml로 구현되었으며, 초기 개발에는 OCaml의 멀티 프로세싱(Multi-processing) 및 공유 메모리(Shared Memory) 라이브러리를 활용했다. 하지만 OCaml 5 이전에는 글로벌 락(Global Lock)으로 인해 병렬 처리가 제한적이었다. Rust로 전환하면서 크로스 플랫폼(Cross-Platform) 지원이 강화되었고, 개발 환경의 통일성을 확보했다. 또한, Rust 생태계는 더 많은 기여자를 유치하여 Pyrefly의 개발 속도를 높이는 데 기여했다.
AST 변환(AST Lowering)의 위험성
Pyre는 초기 개발 과정에서 AST 변환(AST Transformation)을 통해 코드의 의미론적 유사성을 활용하여 반복 작업을 줄였다. 하지만 이 과정에서 AST 변환(AST Transformation)으로 인해 진단 정보의 품질이 저하되어 언어 서버 기능 지원에 어려움이 있었다. Pyrefly는 AST 변환을 최소화하여 리팩토링(Refactoring) 및 참조 찾기(Find-references)와 같은 언어 서버 기능의 정확성을 높였다.
사운드니스(Soundness)와 사용성(Usability)의 균형
Pyre는 보안에 중점을 두어 사운드니스(Soundness)를 우선시했기 때문에, 속성 접근에 대한 엄격한 타입 검사를 수행했다. 이는 사용자에게 불편함을 초래하여, Pyrefly는 사용성(Usability)을 개선하기 위해 타입 검사 규칙을 완화했다. 예를 들어, Pyrefly는 타입 좁히기(Type Narrowing)를 허용하여 개발자의 코드 작성 편의성을 높였다. 이는 사운드니스와 사용성 사이의 트레이드오프(Trade-off)를 보여주는 사례이다.
순환 종속성(Cyclic Dependencies) 캐싱
Pyre는 빠른 증분 타입 검사를 위해 엄격한 순차적 구조를 사용했다. 이로 인해 순환 종속성(Cyclic Dependencies)을 가진 코드의 캐싱이 불가능하여 성능 병목 현상이 발생했다. Pyrefly는 순환 종속성(Cyclic Dependencies)을 허용하는 아키텍처를 도입하여, 캐싱 효율성을 높이고, 데코레이터(Decorator)와 같은 복잡한 코드 패턴의 성능을 향상시켰다. 이는 Pyrefly의 핵심적인 아키텍처 개선 사항 중 하나이다.