개발에서 데드 코드와 좀비 코드: 정의, 원인 및 검색 방법

저자: IT Sectr 게시일: 2026-07-26 읽는 시간: 10 분

데드 코드는 프로그램에서 절대 실행되지 않고 결과에 영향을 미치지 않지만 프로젝트의 소스 파일에 물리적으로 남아 있는 조각들입니다. 주석 처리된 부분과 달리 데드 코드는 컴파일되어 바이너리에 포함되며, 크기를 증가시키고 탐색을 복잡하게 만듭니다. TIOBE Index (2025) 연구에 따르면, 평균 상용 프로젝트에는 10~25%의 호출되지 않는 코드가 포함되어 있습니다. 좀비 코드는 데드 코드의 하위 유형으로, 과거에는 작동했지만 리팩토링 후 관련성을 잃고 이제 공간만 차지하고 있습니다. 이러한 조각들을 정기적으로 정리하면 개발자의 인지 부하를 줄이고 변경 시 오류 위험을 낮출 수 있습니다.

핵심 내용

  • 데드 코드 — 절대 실행되지 않지만 프로젝트에 남아 있는 조각.
  • 좀비 코드 — 이전에는 실행되었지만 변경 후 도달할 수 없게 된 코드.
  • 데드 코드는 바이너리 크기, 빌드 시간 및 팀의 인지 부하를 증가시킵니다.
  • 주요 검색 도구: 정적 분석(SonarQube, ESLint) 및 커버리지 프로파일러.
  • 테스트 커버리지 확인과 코드 리뷰를 통해 데드 코드를 안전하게 제거하세요.

데드 코드란?

데드 코드(dead code)는 프로그램에 포함되어 있지만 어떤 사용 시나리오에서도 절대 실행되지 않는 소스 코드입니다. 컴파일러나 인터프리터가 이를 처리하지만, 런타임에서는 제어가 이러한 부분에 도달하지 않습니다.

데드 코드의 전형적인 예: 값이 할당되었지만 절대 읽히지 않는 변수, 어디에서도 호출되지 않는 함수나 메서드, 절대 참이 되지 않는 조건 분기(if(false)), 본문이 한 번도 실행되지 않는 루프.

SonarQube State of Code Quality (2025) 보고서에 따르면, 상용 Java 프로젝트의 모든 경고 중 약 15%가 사용되지 않는 private 메서드와 필드와 관련되어 있습니다. JavaScript 프로젝트에서는 언어의 동적 특성과 타사 라이브러리의 풍부함으로 인해 사용되지 않는 코드의 비율이 30%에 달할 수 있습니다.

특히 대규모 리팩토링 및 기능 제거 후에는 프로젝트에 데드 코드가 있는지 정기적으로 확인하세요. 오늘의 잊혀진 import나 사용되지 않는 함수가 내일은 팀의 새 구성원을 혼란시키는 좀비 코드로 변할 수 있습니다.

데드 코드와 좀비 코드의 차이점

좀비 코드(zombie code)는 역사적 맥락에서 구별되는 데드 코드의 특수한 경우입니다. 좀비 코드는 한때 작동했지만 시스템 변경 후 도달할 수 없게 되었으며, 그럼에도 불구하고 삭제되지 않고 «만약을 위해» 남겨졌습니다.

데드 코드와 좀비 코드의 차이는 기원에 있습니다. 데드 코드는 잘못 작성되었을 수 있으며(한 번도 작동한 적 없음), 반면 좀비 코드는 리팩토링 후 관련성을 잃은 이전의 살아있는 코드입니다. 예를 들어, 새로운 비즈니스 로직으로 대체된 이전 할인 계산 함수이지만, 이전 메서드는 삭제되지 않았습니다 — 다시 필요할 경우를 대비하여.

좀비 코드의 주요 위험은 작동하는 기능의 환상입니다. 새 개발자가 함수를 보고 문서를 읽고 어딘가에서 호출된다고 가정하여 아티팩트를 연구하는 데 시간을 낭비합니다. 직접 호출하려고 시도하면 삭제된 엔티티나 오래된 API에 의존하고 있음이 드러날 수 있습니다.

git 기록을 통해 좀비 코드를 추적하세요: 함수가 2년 동안 변경되지 않았고 사용되지 않는다면 좀비입니다. 망설임 없이 제거하세요. git이 기록을 보관하고 있으며 필요시 코드는 언제든지 복원할 수 있습니다.

데드 코드가 나타나는 원인

첫 번째이자 가장 흔한 원인은 불완전한 리팩토링을 동반한 반복 개발입니다. 팀은 이전 기능을 대체하는 새 기능을 추가하지만 대체된 모듈을 제거하지 않습니다. 스프린트는 이러한 «꼬리»를 축적하며, 1년 후 프로젝트는 데드 코드 층으로 뒤덮입니다.

두 번째 원인은 A/B 테스트 및 피처 토글입니다. 새 기능 활성화 조건은 시간이 지남에 따라 고정될 수 있지만(예: 항상 true), 대체 로직이 있는 else 분기는 코드에 남아 있습니다. 개발자는 토글이 다시 전환될 경우 실수로 시스템을 손상시킬까 두려워 삭제를 주저합니다.

세 번째 원인은 자동 생성 및 복사-붙여넣기입니다. 코드 생성기(IDE, 템플릿 엔진)는 개발자가 채우지 않거나 사용하지 않는 메서드가 포함된 템플릿을 만듭니다. 다른 프로젝트에서 복사된 코드는 새 컨텍스트와 관련 없는 전체 블록을 포함하는 경우가 많습니다.

네 번째 원인은 삭제에 대한 두려움입니다. 대규모 프로젝트에서 개발자는 코드가 정말 어디에서도 사용되지 않는다는 확신이 없어 삭제를 두려워합니다. 이러한 두려움은 약한 테스트 시스템으로 인해 악화됩니다: 자동 검사가 없으면 삭제로 인해 프로덕션에서만 발견되는 버그가 발생할 수 있습니다.

데드 코드의 위험성

데드 코드는 프로젝트 품질의 네 가지 측면에 직접 영향을 미칩니다: 빌드 성능, 아티팩트 크기, 팀의 인지 부하, 리팩토링의 신뢰성.

컴파일 시간 증가: 컴파일러는 사용되지 않는 파일을 처리하고, 종속성을 분석하며, 절대 실행되지 않는 조각에 대한 바이트 코드나 기계 코드를 생성합니다. 대규모 프로젝트에서는 각 빌드에 몇 분이 추가됩니다. 인터프리터 언어(JavaScript, Python)의 경우 모듈 로드 시간과 메모리 소비가 증가합니다.

수정 시 버그 위험: 개발자는 코드를 변경하면서 함수가 데드 분기에서만 사용된다는 것을 의심하지 않습니다. 리팩토링 후 데드 코드가 컴파일되지 않거나 오류를 생성하여 팀은 애플리케이션 작동에 영향을 미치지 않는 문제 진단에 시간을 낭비합니다.

인지 부하는 가장 비용이 많이 드는 요소입니다. 사용되지 않는 각 함수는 코드를 읽을 때 주의가 필요합니다. 개발자는 이 코드가 왜 존재하고 어디에서 호출되는지 이해하는 데 정신적 에너지를 소비합니다. Developer Productivity Lab(2025)의 연구에 따르면: 데드 코드의 20%를 제거하면 온보딩 시간이 평균 18% 감소합니다.

데드 코드를 발견하면 즉시 제거하세요. 하루 지연될 때마다 팀원이 어제 제거되었어야 할 아티팩트 연구에 시간을 낭비할 가능성이 높아집니다.

데드 코드 검색 도구

데드 코드 검색은 두 가지 주요 방법으로 수행됩니다: 정적 분석(프로그램 실행 없이) 및 동적 분석(런타임에서 커버리지 프로파일링). 각 접근 방식은 다른 유형의 데드 코드에 효과적입니다.

정적 분석기는 모든 인기 있는 프로그래밍 언어를 지원합니다. Java 및 Kotlin — SonarQube, IntelliJ IDEA Inspections, SpotBugs. JavaScript 및 TypeScript — 규칙 no-unused-vars 및 no-unused-modules가 있는 ESLint. Swift — 규칙 unused_declaration이 있는 SwiftLint. Python — 옵션 unused-import가 있는 pylint 및 심층 검색을 위한 vulture.

ProGuard를 통한 Kotlin 검색 예시

groovy
// build.gradle.kts - Android용 ProGuard 구성
android {
    buildTypes {
        release {
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
}

// proguard-rules.pro - 필요한 클래스만 유지
-keep class com.example.app.** { *; }
-assumenosideeffects class Timber {
    static <methods>;
}

ProGuard는 사용되지 않는 클래스와 메서드를 제거할 뿐만 아니라 릴리스 빌드에서 이름을 축소합니다. ProGuard가 활성화된 빌드는 자동으로 어떤 클래스와 메서드가 사용되지 않는 것으로 간주되는지 보여줍니다 — usage.txt 보고서에 제거된 모든 코드가 나열됩니다.

테스트 커버리지를 통한 동적 분석

코드 커버리지 도구(Java용 JaCoCo, Swift용 XCTest coverage, JavaScript용 Istanbul)는 테스트 중에 어떤 라인과 분기가 실행되는지 보여줍니다. 커버리지가 0인 메서드는 데드 코드 후보입니다. 그러나 커버리지 부족이 코드가 프로덕션에서 호출되지 않음을 보장하지는 않습니다 — 완전한 확신을 위해 정적 및 동적 분석의 조합을 사용하세요.

사용되지 않는 선언 임계값을 초과할 때 빌드가 실패하도록 CI 파이프라인을 구성하세요. «사용되지 않는 private 코드 비율이 3% 이하» 규칙의 SonarQube Quality Gate는 개발 프로세스 수준에서 데드 코드 축적을 방지합니다.

데드 코드를 안전하게 제거하는 방법

데드 코드 제거 프로세스는 네 단계로 구성됩니다: 찾기, 확인, 제거, 다시 확인. 단계를 건너뛰면 회귀 위험이 증가합니다.

첫 번째 단계 — 정적 분석기를 통한 후보 검색. 사용되지 않는 선언(함수, 클래스, 변수, import)에 대한 보고서를 받습니다. 거짓 긍정을 필터링하세요 — 분석기는 리플렉션, 동적 클래스 로딩 또는 직렬화를 통한 숨겨진 호출에서 실수하는 경우가 있습니다.

두 번째 단계 — git blame 및 변경 내역을 통한 확인. 코드가 언제, 왜 작성되었는지 확인합니다. 코드가 피처 토글로 비활성화된 기능의 일부였다면 토글이 고정되어 있고 다시 켜지지 않을 것인지 확인하세요. 삭제를 주저하는 코드는 주석 처리하고 한 달 후 재확인을 위한 TODO 티켓을 남깁니다.

세 번째 단계 — 전체 테스트 스위트를 실행하는 별도 브랜치에서 제거. 테스트가 통과하면 회귀 가능성이 낮습니다. 테스트가 실패하면 코드가 여전히 사용 중이며 어떤 시나리오에서 호출되는지 이해해야 합니다.

cpp
// before - 동일 파일의 데드 코드 및 좀비 코드
int calculateV1(int price) { // 어디에서도 호출되지 않음
    int tax = price * 0.18;
    return price + tax;
}

int calculateV2(int price, double rate) {
    return static_cast<int>(price * (1 + rate));
}

// after - 데드 코드 제거됨, 좀비 코드 정리됨
int calculatePrice(int price, double rate) {
    return static_cast<int>(price * (1 + rate));
}

네 번째 단계 — 변경 사항에 대한 코드 리뷰. 리뷰어는 코드가 실제로 데드인지 확인해야 합니다. 리뷰어가 확신하지 못하면 코드에 주석을 남기고 완전한 분석이 끝날 때까지 제거를 연기하세요. 브랜치 병합 후 git 리포지토리에서 좀비 코드가 번성하지 않도록 브랜치를 삭제하세요.

규칙 도입: 어떤 풀 리퀘스트도 새로운 데드 코드를 포함해서는 안 됩니다. 사용되지 않는 변수나 import가 있을 때 커밋을 차단하는 린터를 프리커밋 훅에 추가하세요. 예방이 항상 정리보다 저렴합니다.

자주 묻는 질문

데드 코드가 컴파일 오류를 일으킬 수 있나요?

네, 데드 코드에 구문 오류가 있거나 삭제된 유형을 참조하는 경우입니다. 최신 컴파일러는 여전히 데드 분기를 확인하므로 if(false) 블록의 오류는 빌드 실패를 초래합니다. 이는 보호 장치입니다: 코드가 컴파일러가 확인하지 않을 정도로 데드가 되어서는 안 됩니다.

팀의 신입에게 좀비 코드는 얼마나 위험한가요?

좀비 코드는 오해를 불러일으킵니다: 새 개발자가 문서가 있는 함수를 보고 사용된다고 가정합니다. 그는 작동하지 않는 코드를 연구하는 데 시간을 낭비하고 실수로 오래된 엔티티에 새 로직을 연결하여 추적하기 어려운 버그를 만들 수 있습니다.

JavaScript 프로젝트에서 데드 코드를 찾으려면?

ESLint를 no-unused-vars 및 no-unused-modules 규칙과 함께 사용하고, knip 유틸리티를 사용하세요 — 프로젝트 전체의 exports와 imports를 분석하여 사용되지 않는 파일, 함수 및 종속성을 찾아냅니다. 대규모 모노리포지토리의 경우 knip이 가장 완전한 그림을 보여줍니다.

릴리스 전에 데드 코드를 제거해야 하나요?

릴리스 에 제거하는 것이 좋지만 막바지에는 하지 마세요. 데드 코드 제거는 스프린트에서 별도로 계획되는 기술 작업입니다. 릴리스 직전 제거는 코드가 생각만큼 데드가 아닌 것으로 판명될 경우 불안정성을 초래할 수 있습니다.

컴파일러가 자동으로 데드 코드를 제거하는 데 도움이 되나요?

네, 최신 컴파일러와 미니파이어(ProGuard, R8, Terser, Closure Compiler)는 Dead Code Elimination 수준에서 도달할 수 없는 코드를 제거합니다. 그러나 이것이 소스 정리의 필요성을 없애지는 않습니다: 컴파일러는 바이너리에서 코드를 제거하지만 리포지토리에서는 제거하지 않습니다 — 개발자는 코드를 읽을 때 계속 걸려 넘어집니다.

요약

  • 데드 코드 — 절대 실행되지 않지만 프로젝트에 남아 있는 사용되지 않는 조각.
  • 좀비 코드 — 이전에는 작동했지만 리팩토링 후 관련성을 잃은 데드 코드의 하위 유형.
  • 주요 발생 원인: 반복 개발, 피처 토글, 자동 생성 및 삭제에 대한 두려움.
  • 데드 코드는 빌드 시간, 바이너리 크기 및 팀의 인지 부하를 증가시킵니다.
  • 검색 도구: SonarQube, ESLint, SwiftLint, pylint, vulture, knip, ProGuard, JaCoCo.
  • 안전한 제거: 검색, git 분석, 브랜치에서 제거, 테스트 실행 및 코드 리뷰 포함.
  • 데드 코드 예방: CI의 린터, 코드 리뷰에서 사용되지 않는 코드 경고 및 리팩토링 문화.

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기