Lobsters

Interactive refactoring in gopls

gopls의 대화형 리팩터링

gopls가 사용자 입력을 받아 여러 단계로 진행하는 리팩터링을 지원합니다. Go 팀은 이를 특정 편집기에 묶이지 않는 LSP 표준 제안으로 설계했으며, 구조체 태그 수정과 인터페이스 메서드 생성 등을 지원합니다. gopls v0.24.0과 VS Code용 Go 확장 v0.56.0에서 사용할 수 있습니다.

에디터 노트

대화형 입력이 LSP 표준으로 자리 잡으면 리팩터링의 선택지를 서버가 정하고 편집기가 공통 방식으로 보여주는 구조를 만들 수 있습니다. 태그 종류와 이름 규칙을 사용자가 지정하고, 인터페이스 이름을 검색해 메서드를 생성하는 예시는 입력이 실제 변환 결과를 바꾸는 작업에 잘 맞습니다. 다만 발표 시점에 완성된 지원 범위는 gopls와 VS Code 확장에 한정되며, 선언 이동은 미리보기이고 Neovim과 Emacs 통합은 개념 검증 단계입니다. Lobsters 댓글에서 Neovim과 Helix 지원 시점을 묻는 이유도 표준 제안이 곧 모든 편집기에서 동작한다는 뜻은 아니기 때문입니다. 각 클라이언트의 구현과 제안의 표준화가 남은 조건입니다.

AI 요약

LSP(Language Server Protocol)의 코드 변환 기능은 대개 사용자가 작업을 실행하면 서버가 바로 편집 내용을 계산하는 방식입니다. 이 구조에서는 서버가 커서 위치와 문법 정보만으로 사용자의 의도를 판단해야 합니다. 예를 들어 구조체 태그를 추가할 때 태그 종류와 이름 규칙을 물을 수 없어 기본값을 쓰거나 기능을 제공하지 못했습니다. Go 팀은 사용자가 입력할 항목을 서버가 요청하는 대화형 리팩터링 기능을 제안했습니다. Dart 팀과 협력해 특정 언어나 편집기에 한정되지 않는 LSP 표준으로 설계했으며, 제안은 microsoft/language-server-protocol#1164에서 논의 중입니다.

입력을 받아 변환하는 코드 액션

구조체 태그 추가 기능은 원하는 태그 종류를 입력받고, camelCase, snake_case, PascalCase 중 이름 규칙을 고르게 합니다. 예를 들어 ID 필드에 json과 db 태그를 snake_case로 추가할 수 있습니다. 태그 삭제 기능도 삭제할 키를 지정하므로 db 태그만 지우고 json 태그는 남길 수 있습니다. 이전처럼 모든 태그를 한꺼번에 지우지 않아도 됩니다.

인터페이스 구현 기능은 구체 타입에서 코드 액션을 실행한 뒤 인터페이스 이름을 입력받습니다. 입력 중 gopls가 워크스페이스와 표준 라이브러리의 타입 이름을 검색해 자동 완성합니다. 인터페이스에 타입 매개변수가 있으면 각 매개변수에 넣을 구체 타입도 묻습니다. 그런 다음 적절한 리시버와 인스턴스화한 메서드 시그니처를 갖춘 메서드 스텁을 생성합니다.

선언 이동 기능은 현재 미리보기 구현입니다. 사용자가 기존 Go 파일이나 새 파일 경로를 고르면 gopls가 선언을 옮기고 워크스페이스의 참조와 import를 갱신합니다. 이동 대상 선언이 쓰는 비공개 헬퍼나 메서드도 함께 옮기지만, 관계없는 심볼은 원래 파일에 남깁니다. 예시에서는 Foo와 그 메서드 Print, Foo만 사용하는 비공개 상수 bar를 다른 패키지로 옮기고, 별개인 Baz 함수는 남깁니다. 이 기능은 향후 gopls 릴리스에 들어갈 예정입니다.

지원 버전과 확장 방향

gopls v0.24.0과 공식 VS Code용 Go 확장 v0.56.0에서 대화형 리팩터링을 지원합니다. 구조체 태그와 인터페이스 구현 기능은 gopls v0.23.0부터 사용할 수 있으며, Neovim과 Emacs용 클라이언트 통합도 개념 검증 단계에서 다뤘습니다. gopls v0.24.0에는 패키지 수준 변수 이름이 dragonSlayer일 때 실행되는 Slay the dragon 코드 액션도 포함됩니다. 편집기 클라이언트 구현을 시험하는 자체 완결형 예제로 마련한 기능입니다.

앞으로는 함수 시그니처 변경, 이름 충돌이나 모호한 참조가 생겼을 때 선택지를 묻는 충돌 해결 기능을 계획하고 있습니다. 함수 매개변수를 추가하거나 순서를 바꾸려면 기존 호출 위치에 넣을 기본 인수 표현식 같은 정보가 필요합니다. 대화형 입력을 활용하면 선언과 모든 호출 위치를 함께 고칠 수 있습니다. LSP 명령 계층에서 동작하므로 코드 편집 밖의 작업에도 적용할 수 있으며, CPU·메모리 프로파일링 옵션을 설정해 테스트나 벤치마크를 실행하는 사례도 제시합니다.

Lobsters 반응

  • @eduard — 이걸 테스트해 볼 생각에 정말 기대됩니다! 특히 인터페이스를 구현하는 메서드를 추가하는 기능이 제게 아주 유용해 보입니다. Neovim에서 이미 쓸 수 있는지 아는 분 있나요? Neovim의 LSP 구현이 이 기능을 지원하나요?
  • @natfu — 코드를 선택해 함수나 메서드로 추출하거나 필요한 기본 메서드를 자동으로 구현하는 기능은 늘 멋졌습니다. 제가 처음 본 곳은 Eclipse나 IntelliJ였던 것 같네요. 상상할 수 있는 편의 기능이 많습니다. 일부는 이미 있기도 하죠. 사용되지 않는 코드 찾기, 대규모 심볼 이름 변경, 파일 경로 변경에 따른 import와 빌드 도구 갱신, 문맥을 고려한 이름 변경 같은 것들입니다. 이런 기능이 여러 언어에서 공통 도구 모음이 되거나 그렇게 될 수도 있다는 점이 반갑습니다!
  • @gavinmorrow — Go를 쓰지는 않지만 이런 기능을 다른 언어에서도 볼 수 있으면 정말 좋겠습니다! 저는 Helix를 쓰는데, 표준이 확정되면 편집기가 지원하길 바랍니다. 지원을 추가하려면 얼마나 작업해야 할지도 궁금합니다.

원문: Go Blog / 번역·요약: Trawling