Issue 01중국 AI
AC POST
중국 AI 목록
掘金2026년 9월 19일 23:02중국어 → 한국어

Knip으로 AI 코딩이 남긴 중복 코드 정리

Knip으로 두 프로젝트를 정리하고 Git 기록을 확인한 결과, 빠른 구현과 페이지 재구성에서 비롯된 중복 코드가 lint를 피해 남아 있었다.

중국어 원문을 AI로 번역했습니다. 고유명사와 수치는 원문 표기를 우선하며, 중요한 판단에는 아래 출처 원문을 함께 확인하세요.

최근 나는 Knip을 두 개의 기존 프로젝트에 돌려서 적지 않은 불필요한 코드와 사용하지 않는 파일을 정리했다. 정리를 끝낸 뒤에는 다시 agent에게 Git 기록을 뒤져서 이런 것들이 어떻게 남게 되었는지 살펴보게 했다.

결과는 익숙했다. 어떤 것은 “이 요구사항을 빨리 구현해 보자”의 잔재였고, 어떤 것은 “이 페이지를 리팩터링하자” 이후의 임시 파일이었다. 새 기능은 이미 쓰이고 있는데 옛 코드는 아직 남아 있었다.

우리는 이미 agent coding에 익숙해졌다. 몇 마디짜리 작은 요구사항이 마지막에는 수십 개 파일, 수천 줄짜리 PR이 된다. 기능이 돌아가는 것만 보이면 바로 다음 요구사항으로 넘어간다. 그 변경 안에서 얼마나 많은 부분이 필요한 것이고, 얼마나 많은 부분이 임시 방편이며, 얼마나 많은 부분이 이후 구현으로 대체되었는지는 쉽게 지나치게 된다.

이번 정리에서 내가 비교적 신경 쓰였던 것은, 이미 쓸모없어졌는데도 계속 저장소에 남아 있는 이런 것들이었다.

왜 lint는 일찍 발견하지 못했을까?

TypeScript 프로젝트를 예로 들면, 엄격한 쪽의 lint는 사용하지 않는 변수, 매개변수, import를 검사할 수 있다. 그렇지만 파일 안의 참조가 모두 성립한다고 해서 그 파일이 여전히 프로젝트에서 사용되고 있다는 뜻은 아니다.

단순화한 예를 하나 들어 보자. 원래 라우트가 옛 페이지를 가리키고, 옛 페이지가 옛 컴포넌트를 참조하며, 옛 컴포넌트가 다시 몇 개의 유틸리티 함수를 호출한다. 리팩터링 후 라우트는 새 페이지로 바뀌었지만 옛 페이지는 삭제되지 않았다.

옛 페이지 안의 import는 여전히 사용되고 있고, 옛 컴포넌트 안의 함수에도 호출하는 쪽이 있다. 이 파일들 내부에서 보면 모든 것이 정상이다. 하지만 애플리케이션 진입점에서 보면 이미 어느 경로도 이 옛 구현에 도달할 수 없다.

흔한 미사용 변수 규칙으로는 여기까지 검사하지 못한다. 그것들은 국소적인 문제를 해결하는 것이고, 코드 전체가 여전히 프로젝트에 필요한지는 파일 사이의 참조를 따라 계속 찾아가야 한다.

프로젝트에 기본적인 lint조차 없다면, 이 두 종류의 불필요한 코드는 함께 남게 된다.

Knip은 한 겹 더 본다

Knip 공식 문서가 제시하는 핵심 역량은 JavaScript와 TypeScript 프로젝트에서 사용하지 않는 파일, export, 의존성을 찾는 것이다.

그것은 진입 파일에서 출발하여 참조 관계를 따라 프로젝트를 분석하고, package.json과 프레임워크, 도구 플러그인을 결합해 더 많은 진입점을 식별한다. 검사 범위에 포함되었지만 진입점에서 도달할 수 없는 파일은 사용하지 않는 것으로 보고될 수 있다.

앞의 예에 대입해 보면, 옛 페이지, 옛 컴포넌트, 유틸리티 함수 사이에 여전히 참조가 있더라도 Knip은 이 전체 체인이 이미 애플리케이션 진입점과 끊겨 있다는 것을 발견할 기회를 가진다.

npm을 예로 들면, 공식이 제시한 연동 명령은 다음과 같다.

npm init @knip/config npm run knip

위는 연동 예시이며, 구체적인 환경 요구사항과 설정은 공식 문서를 기준으로 한다.

보고서를 받은 뒤에는 agent에게 참조 관계에 맞춰 정리하게 할 수 있다. Knip 자체도 자동 수정을 지원한다. --fix는 일부 사용하지 않는 export와 의존성을 처리할 수 있고, 파일 삭제는 --allow-remove-files를 추가해야 한다.

여기에는 경계가 하나 있다. Knip은 먼저 프로젝트에 어떤 진입점이 있는지 알아야 한다. 런타임에 조합되는 로딩 경로, 프레임워크가 자동으로 발견하는 파일은 설정을 보충해야 할 수 있고, 외부에 배포하는 라이브러리라면 저장소 내에서 아무도 호출하지 않는 공용 API를 그냥 삭제해서도 안 된다. 이런 상황은 공식 문제 처리 문서에 설명되어 있다.

Git을 뒤지는 것이 몇 줄을 삭제했는지 보는 것보다 더 흥미롭다

내가 agent에게 계속 출처를 추적하게 한 것은, 이 코드가 원래부터 불필요했던 것인지, 아니면 나중에야 쓸모없어진 것인지 알고 싶었기 때문이다.

이 두 프로젝트에서는 요구사항을 빠르게 구현하고 페이지를 리팩터링한 과정을 적지 않게 추적할 수 있었다. 임시 구현이 남았고, 대체된 파일이 남았다. 당시의 요구사항만 보면 일은 이미 끝난 상태다. 한참 뒤에 저장소를 다시 보면, 그 안에는 여러 차례 변경의 잔재가 쌓여 있다.

옛 코드에는 정상적인 이름, 타입, 디렉터리 구조가 있어서 검색할 때 그대로 나타난다. 다음번에 agent가 관련 기능을 수정할 때, 그것을 현재 구현의 참고로 삼아 이미 낡은 방식에 따라 계속 작성할 수 있다. 저장소가 어수선할수록 어느 코드가 아직 유효한지 가려내는 데 더 품이 든다.

이는 내가 이전에 쓴 문서 드리프트 문제와 어느 정도 비슷하다. 지난 내용이 아직 남아 있으면, 이후의 판단이 잘못된 전제 위에 세워질 수 있다.

Knip은 물론 비즈니스 아키텍처가 합리적인지 판단하지 못한다. 모든 코드를 누군가 호출하더라도 프로젝트는 여전히 똥산이 될 수 있다. 아키텍처는 여전히 경험 있는 엔지니어가 받쳐 줘야 한다.

하지만 이미 아무도 쓰지 않는 파일, export, 의존성은 먼저 치울 수 있다. 이번에 두 프로젝트에서 돌려 본 효과는, Knip을 똑같이 AI Coding을 대량으로 사용하는 사람들에게 추천할 만하다고 느끼게 했다.