kalee's 공부방

함수 삭제와 인자 형식 변경을 따라가며 의미상 참조, 문자열 사용, 추론 타입, 동작 검증을 어떤 도구에 맡길지 살펴봅니다. 2026년 11월 13일 확인한 공식 문서와 10월 10일의 작은 SvelteKit 개인 실험을 구별하고, 초기화·언어 경계·셸 동기화·진단 지연과 최종 검사 증거를 짚습니다.

Show Notes

함수 삭제와 인자 형식 변경을 따라가며 의미상 참조, 문자열 사용, 추론 타입, 동작 검증을 어떤 도구에 맡길지 살펴봅니다. 2026년 11월 13일 확인한 공식 문서와 10월 10일의 작은 SvelteKit 개인 실험을 구별하고, 초기화·언어 경계·셸 동기화·진단 지연과 최종 검사 증거를 짚습니다.

전체 대본 보기

참고 자료

이 에피소드의 음성은 TTS로 합성되었습니다.

What is kalee's 공부방?

kalee 가 공부하고자 하는 내용들을 두서없이 업로드하는 팟캐스트

진행자: 함수 하나를 지우려는데, 참조 검색에서는 쓰는 곳이 없다고 나옵니다. 그런데 문자열 검색에는 테스트 파일이 걸려요. 이때 어느 쪽 말을 믿어야 할까요? 오늘은 LSP와 grep 중 하나를 고르는 대신, 삭제해도 된다는 판단에 어떤 증거가 필요한지 따져보겠습니다.

전문가: 먼저 시점을 고정하죠. 오늘은 2026년 11월 13일에 확인한 공식 문서와, 10월 10일에 나온 Scott Spence의 개인 실험 글을 바탕으로 이야기합니다. 특정 환경에서 생긴 문제를 모든 언어 서버의 법칙으로 만들지는 않겠습니다.

진행자: LSP부터 풀어볼게요. 코드에서 이름을 찾는 기능이라고만 이해하면 부족한가요?

전문가: Language Server Protocol, 언어 서버와 개발 도구가 대화하는 규약입니다. 언어를 분석하는 서버에 정의 위치나 타입 같은 정보를 물어볼 수 있게 하는 거죠. 다만 규약이 있다고 모든 서버가 모든 기능을 지원하는 건 아닙니다. 오늘은 통신 구조보다, 그 답을 작업에 어떻게 쓸지에 집중하겠습니다.

진행자: 그럼 grep은 같은 일을 더 단순하게 하는 도구인가요?

전문가: 질문 자체가 다릅니다. grep은 주어진 패턴과 맞는 내용을 파일에서 찾고, 기본적으로 일치하는 행을 보여줍니다. 반면 의미상 참조를 묻는 건, 이 위치의 이름이 가리키는 대상을 어디서 쓰느냐는 질문이에요. 철자가 같은지와 같은 대상을 가리키는지는 구별해야 합니다.

진행자: 예시를 하나 정하죠. 날짜 범위를 계산하는 함수가 있고, 기간과 현재 시각을 인자로 따로 받습니다. 이것을 옵션 객체 하나를 받도록 바꾸려 해요. 실제 저장소에서 해봤다는 이야기가 아니라, 작업 순서를 생각해 보는 가상 사례입니다.

전문가: 제가 먼저 권할 일은 수정 대상을 고정하는 겁니다. 어느 파일의 어느 함수인지 확인하고, 그 심볼의 참조를 언어 서버에 물어보세요. 결과에 나온 위치를 읽어 실제 호출인지, 가져오기인지 나눕니다. 같은 이름을 가진 다른 함수까지 무턱대고 바꾸지 않으려는 순서예요.

진행자: 거기 나온 위치를 모두 바꾸면 끝나는 것 아닌가요?

전문가: 바로 그 결론을 조심해야 합니다. Scott의 글에는 함수의 테스트 대역이 TypeScript의 심볼 참조로 잡히지 않았지만 텍스트 검색으로 발견된 사례가 나옵니다. 실제 함수를 직접 부르지 않는 대역도, 인자 형식이 바뀌면 손봐야 할 수 있다는 이야기예요. 모든 테스트 대역이 빠진다는 뜻은 아닙니다.

진행자: 그러면 테스트 대역 쪽도 따로 봐야겠네요. 함수 이름만이 아니라, 그걸 가져오는 모듈 경로도 찾아봐야겠고요.

전문가: 네. 이 사례에서는 함수 이름, 모듈 경로, 대역 설정을 텍스트 검색의 후보로 삼는 게 좋겠습니다. 결과를 전부 호출이라고 세지는 말고요. 주석이나 문서인지, 테스트 설정인지, 실제 코드인지 읽어서 분류하세요. 의미상 참조와 문자열 흔적은 서로 다른 목록으로 남기는 편이 판단하기 쉽습니다.

진행자: 함수를 바꾸는 게 아니라 지우는 작업이면, 조금 더 엄격해야 할까요?

전문가: 저라면 참조가 안 나왔다는 사실과 사용되지 않는다는 결론 사이에 확인 단계를 두겠습니다. 서버가 프로젝트를 제대로 읽었는지, 사용하는 언어를 다 다루는지, 지금 파일 내용과 같은 상태를 보고 있는지요. 그 조건이 불명확하면 빈 결과만으로 삭제하지 않는 게 좋겠습니다.

진행자: 서버가 켜져 있다는 것과 준비가 끝났다는 것이 다를 수 있다는 얘기군요. 이건 글에서 실제로 관찰된 문제인가요?

전문가: 그렇습니다. 작성자는 새 세션의 첫 참조 조회가 일부만 돌려주다가, 뒤의 조회에서는 더 많은 참조를 돌려주는 현상을 보고했습니다. 그는 프로젝트 로딩과 연결해 설명했고, TypeScript 서버 설정을 바꾼 뒤 자기 프로젝트에서는 개선됐다고 했습니다. 이 회차에서 그 실험을 독립 재현한 것은 아닙니다.

전문가: 그래서 그 설정을 지금 누구나 넣어야 한다거나, 첫 응답은 언제나 틀리다고 말할 근거는 없습니다. 가져올 교훈은 준비 상태를 확인하지 않은 적은 결과를 곧바로 완전한 목록으로 취급하지 말자는 겁니다. 현재 사용하는 도구와 서버의 버전, 프로젝트 로딩 상태를 확인하는 쪽이 먼저겠죠.

진행자: 그럼 참조가 적게 나오면 몇 초 기다렸다가 다시 묻는 식으로 해결하면 될까요?

전문가: 그것만으로는 부족합니다. 같은 글에서 TypeScript 파일 쪽으로 물은 참조에는 Svelte 컴포넌트의 호출자가 빠졌고, Svelte 서버 쪽에서 물었을 때는 컴포넌트들이 포함됐습니다. 이건 단순 대기 시간과 다른, 언어와 서버의 경계 문제였어요. 숫자가 늘기를 기다리는 것과 지원 범위를 넓히는 일은 다릅니다.

진행자: 프로젝트가 TypeScript를 쓴다고 해서 모든 파일을 TypeScript 서버가 같은 범위로 볼 거라고 가정하면 안 되겠네요.

전문가: 공식 프로토콜 개요도 서버별로 지원 기능이 다르고, 실제 도구 통합은 구현자에게 맡긴다고 설명합니다. 그래서 이 예에서는 컴포넌트 확장자와 연결된 서버를 확인하고, 텍스트 검색으로 경계 밖의 사용 후보를 살펴보자는 겁니다. 검색 행 수에서 참조 수를 빼서 누락 개수라고 계산하지도 마세요. 세는 대상이 다릅니다.

진행자: 또 한 가지요. 에이전트가 파일을 직접 편집할 때도 있고, 셸 명령으로 코드를 생성하거나 바꿀 때도 있잖아요. 같은 파일이면 서버도 같은 내용을 보지 않나요?

전문가: 항상 그렇다고 가정할 수는 없습니다. 공식 개요는 문서를 연 뒤에는 도구 메모리에 있는 내용을 서버와 동기화해야 한다고 설명합니다. 디스크에 파일이 바뀌었다는 사실과, 서버가 분석하는 문서가 갱신됐다는 사실은 별도로 확인해야 하는 거죠.

전문가: Scott은 이미 조회했던 파일에 셸로 행을 덧붙인 뒤, 참조 조회가 그 변경을 놓치는 경우를 보고했습니다. 새 파일이 늦게 보이는 경우도 따로 적었고요. 셸 수정은 언제나 실패한다는 뜻이 아니라, 자신의 구성에서 관찰한 동기화 문제입니다.

진행자: 우리의 가상 함수 변경에서도 셸로 호출자를 일괄 바꿨다면, 오래된 참조 목록을 보고 다 고쳤다고 하면 안 되겠네요.

전문가: 네. 우선 디스크의 변경과 도구가 보는 문서 상태를 맞추는 절차를 확인하겠습니다. 변경 전후의 검색 결과를 읽고, 프로젝트가 정한 검사도 돌리겠어요. 오래된 결과를 여러 번 받아 놓고 안정적으로 같은 답이 나왔다고 안심하지는 않겠습니다.

진행자: 여기까지 들으면 텍스트 검색을 반드시 해야 하니까, 아예 grep만 쓰자는 결론도 나올 것 같은데요. 그 개인 실험 글도 검색이 더 나았다고 하지 않나요?

전문가: 그 글의 사용처 질문에서는 grep 조건이 정확했고 더 빠르고 저렴했다고 보고합니다. 하지만 작은 SvelteKit 저장소, 한 모델, 조건마다 세 번이라는 제한을 작성자가 직접 밝혔어요. 큰 코드베이스나 다른 언어에도 그대로 적용되는 성능 순위로 읽으면 안 됩니다.

전문가: 비교 조건도 중요합니다. LSP와 grep을 함께 쓰는 조건에는, 언어 서버 결과를 검색으로 다시 확인하라는 규칙이 있었습니다. 그러니 추가 검색이 절차에 들어 있어요. 병용 조건이 더 많은 일을 했다는 결과를, 언어 서버 자체의 비용만으로 설명하면 곤란합니다.

진행자: 이름은 grep 조건인데 실제로는 문자열 검색 말고도 했다는 부분이 있죠?

전문가: 맞아요. 타입 질문에서는 선언 파일을 읽었고, 한 실행에서는 TypeScript 컴파일러에 질의하는 스크립트까지 만들었습니다. 컴파일러의 도움을 받은 답을, grep이 타입을 추론했다고 표현하면 안 되죠. 이 비교는 허용된 도구 묶음과 지시 규칙을 포함한 작업 흐름의 비교에 가깝습니다.

전문가: 그리고 글 후반의 세 조건 비교에 대해 작성자는 실제 리팩터링은 시험하지 않았다고 명시합니다. 앞부분에는 별도의 수정 프롬프트가 있지만, 뒤의 탐색 질문 결과만으로 변경 후 동작까지 검증됐다고 말할 수는 없어요. 우리가 삭제와 인자 변경 이야기를 따로 하는 이유도 여기에 있습니다.

진행자: 그렇다면 추론된 반환 타입이 궁금할 때는 어떤 질문을 던져야 할까요? 함수 선언에 타입이 적혀 있지 않은 경우요.

전문가: 그럴 때는 hover, 심볼 위치의 타입 정보를 조회하는 기능을 쓸 만합니다. Scott의 실험에서도 타입을 바로 얻은 사례가 있었어요. 텍스트에서 관련 선언을 찾는 일과, 분석기가 해석한 타입을 묻는 일을 구별하면 됩니다. 다만 서버가 어떤 프로젝트와 라이브러리 버전을 보고 있는지도 함께 확인하는 게 좋겠습니다.

진행자: 처음에는 선언을 찾고, 지금 질문이 정확한 타입으로 바뀌었으니 분석기에 묻는 거네요. 한 도구를 끝까지 고집할 이유가 없어 보입니다.

전문가: 또 빠뜨리기 쉬운 것이 자동 진단입니다. Claude Code 공식 문서는 편집 뒤 들어오는 오류와 경고, 그리고 명시적으로 호출하는 코드 탐색 도구를 나눠 설명합니다. 탐색 도구를 호출하지 않았더라도 진단을 받았을 수 있으니, 호출 횟수만 세어 언어 서버를 안 썼다고 결론 내릴 수는 없습니다.

진행자: 반대로 편집 직후 오류 메시지가 없으면, 문제가 없다고 봐도 될까요?

전문가: 그것도 조심해야 해요. Scott은 짧은 세션에서 편집이 마지막 동작일 때 오류가 보고되지 않은 사례, 더 긴 세션에서는 뒤늦게 진단이 들어온 사례를 적었습니다. 이 관찰을 모든 버전의 고정 지연으로 볼 수는 없지만, 조용하다는 것만으로 검사가 끝났다고 판단하지 말라는 경고는 됩니다.

진행자: 이제 날짜 함수의 인자도 바꾸고 호출자와 테스트 대역도 고쳤다고 합시다. 마지막 완료 판단은 어떻게 하시겠어요?

전문가: 저라면 저장소에서 정한 타입 검사와 빌드를 실행하고, 이번 변경이 영향을 주는 동작 테스트를 확인하겠습니다. 타입이 맞는지, 산출물을 만들 수 있는지, 기대한 날짜 범위가 나오는지는 나눠서 묻겠어요. 이 예에서 우리가 실제 명령을 실행했다는 말은 아니고, 변경을 끝낼 때 확보할 증거를 제안하는 겁니다.

전문가: 검사 범위도 적어야 합니다. TypeScript 공식 문서는 명령행에 입력 파일을 직접 지정하면 프로젝트 설정 파일을 무시한다고 설명합니다. 파일 하나가 통과한 것과, 저장소가 정한 설정으로 프로젝트를 검사한 것은 같은 말이 아니에요. 실행한 명령과 대상, 결과를 함께 남겨야 합니다.

진행자: 그럼 타입 검사 통과도 동작 보증은 아니군요. 예를 들어 같은 타입의 날짜 값 두 개를 잘못된 자리에 넣는 상황이라면, 타입만 맞는다는 답으로는 업무상 의미를 판단하기 어렵겠어요.

전문가: 맞습니다. 그런 가상 오류를 염두에 두고, 경계 날짜나 빠진 옵션처럼 이번 변경의 의미를 확인하는 테스트를 고르자는 겁니다. 반대로 테스트가 통과해도 실행하지 않은 조건까지 무조건 안전하다고 말하지는 않겠어요. 최종 보고는 성공이라는 한 단어보다, 어떤 범위에서 무엇이 통과했는지가 중요합니다.

진행자: 실무에서 에이전트에게 지시한다면 이렇게 말하고 싶어요. 대상 심볼의 참조를 확인하고, 문자열과 모듈 경로에서 놓친 사용 후보를 찾아라. 정확한 타입은 분석기에 묻고, 변경 후에는 정해진 검사 결과를 가져와라. 지원하지 않는 언어나 실행하지 못한 검사가 있으면 따로 적어라.

전문가: 좋습니다. 다만 모든 작은 수정에 모든 검색을 반복하라는 규칙으로 만들지는 맙시다. 삭제나 시그니처 변경처럼 누락이 위험한 작업에서, 아직 답하지 못한 질문이 무엇인지 보고 증거를 보태자는 제안이에요. 결과가 다르면 숫자로 승자를 가리지 말고, 같은 심볼인지, 같은 파일 상태인지, 같은 범위를 보는지부터 확인해 보세요.

진행자: 오늘의 결론은 도구 하나의 우승이 아닙니다. 이름의 흔적, 의미상 참조, 해석된 타입, 실행한 동작은 서로 다른 질문입니다. 그리고 결과가 없다는 말을 안전하다는 말로 바꾸기 전에, 준비 상태와 지원 범위, 동기화를 확인하자는 겁니다.

전문가: LSP를 쓰면 검색이 필요 없어지는 것도, 검색이 잘됐으니 언어 서버가 쓸모없어지는 것도 아닙니다. 여러분이 다음 함수를 지우려 할 때는 어떤 도구를 좋아하는가보다, 지금 삭제해도 된다고 말할 근거가 어디까지 확보됐는가를 물어보면 좋겠습니다.

진행자: 참고한 공식 문서와 개인 실험 글은 설명란에 연결해 두겠습니다. 개인 실험의 한계도 함께 읽어보시면 좋겠어요. 오늘은 여기까지입니다.