کد مرده و کد زامبی در توسعه: چیست، علل و جستجو

نویسنده: IT Sectr منتشر شده: 2026-07-26 زمان مطالعه: 10 دقیقه

کد مرده — قطعاتی از برنامه هستند که هرگز اجرا نمی‌شوند و بر نتیجه تأثیر نمی‌گذارند، اما از نظر فیزیکی در سورس‌های پروژه باقی می‌مانند. برخلاف بخش‌های کامنت‌شده، کد مرده کامپایل شده و وارد باینری می‌شود، اندازه آن را افزایش داده و ناوبری را دشوار می‌کند. طبق تحقیق TIOBE Index (2025)، یک پروژه تجاری متوسط شامل 10 تا 25 درصد کدی است که هرگز فراخوانی نمی‌شود. کد زامبی — زیرمجموعه‌ای از کد مرده است که در گذشته کار می‌کرد، اما پس از بازآرایی کد (رفکتورینگ) اعتبار خود را از دست داده و اکنون فقط فضا اشغال می‌کند. پاکسازی منظم چنین قطعاتی بار شناختی توسعه‌دهندگان را کاهش می‌دهد و خطر خطاها را هنگام اعمال تغییرات کم می‌کند.

نکات اصلی

  • کد مرده — قطعاتی که هرگز اجرا نمی‌شوند اما در پروژه باقی می‌مانند.
  • کد زامبی — کدی که قبلاً اجرا می‌شد اما پس از تغییرات غیرقابل دسترس شده است.
  • کد مرده اندازه باینری، زمان ساخت و بار شناختی تیم را افزایش می‌دهد.
  • ابزارهای اصلی جستجو: تحلیل ایستا (SonarQube, ESLint) و پروفایلرهای پوشش.
  • حذف کد مرده از طریق بررسی پوشش تست و بازبینی کد ایمن است.

کد مرده چیست؟

کد مرده (dead code) — کد مبدأیی است که در برنامه گنجانده شده اما در هیچ سناریوی استفاده‌ای اجرا نمی‌شود. کامپایلر یا مفسر آن را پردازش می‌کند، اما در زمان اجرا، کنترل هرگز به این بخش‌ها نمی‌رسد.

نمونه‌های کلاسیک کد مرده: متغیرهایی که مقدار به آنها نسبت داده شده اما هرگز خوانده نمی‌شوند؛ توابع یا متدهایی که در هیچ جایی فراخوانی نمی‌شوند؛ شاخه‌های شرطی که هرگز درست نمی‌شوند (if(false))؛ حلقه‌هایی که بدنه آنها حتی یک بار هم اجرا نمی‌شود.

طبق گزارش SonarQube State of Code Quality (2025)، حدود 15 درصد از همه هشدارها در پروژه‌های تجاری جاوا به متدها و فیلدهای خصوصی استفاده‌نشده مربوط می‌شود. در پروژه‌های جاوااسکریپت، سهم کد استفاده‌نشده به دلیل ماهیت پویای زبان و فراوانی کتابخانه‌های شخص ثالث می‌تواند به 30 درصد برسد.

پروژه را به طور منظم از نظر وجود کد مرده بررسی کنید — به ویژه پس از بازآرایی‌های بزرگ و حذف ویژگی‌ها. یک import فراموش‌شده یا تابع استفاده‌نشده امروز، فردا ممکن است به کد زامبی تبدیل شود که اعضای جدید تیم را گمراه می‌کند.

تفاوت‌های کد مرده و کد زامبی

کد زامبی (zombie code) — حالت خاصی از کد مرده است که با زمینه تاریخی متمایز می‌شود. کد زامبی زمانی کار می‌کرد، اما پس از تغییرات در سیستم دیگر قابل دسترس نیست، با وجود اینکه حذف نشده و «برای هر احتیاطی» باقی مانده است.

تفاوت بین کد مرده و کد زامبی در منشأ آنهاست. کد مرده ممکن است اشتباهاً نوشته شده باشد (هرگز کار نکرده)، در حالی که کد زامبی کد زنده سابق است که در بازآرایی کد اعتبار خود را از دست داده است. به عنوان مثال، تابع محاسبه تخفیف بر اساس منطق تجاری قدیمی که با منطق جدید جایگزین شده، اما متد قدیمی حذف نشده — در صورت نیاز به بازگرداندن.

خطر اصلی کد زامبی — توهم عملکرد کارآمد است. توسعه‌دهنده جدید تابعی را می‌بیند، مستندات آن را می‌خواند، تصور می‌کند که در جایی فراخوانی می‌شود — و وقت خود را صرف مطالعه یک اثر باستانی می‌کند. هنگام تلاش برای فراخوانی مستقیم آن، ممکن است مشخص شود که به موجودیت‌های حذف‌شده یا APIهای قدیمی وابسته است.

کد زامبی را از طریق تاریخچه git ردیابی کنید: اگر تابعی دو سال تغییر نکرده و استفاده نمی‌شود — این یک زامبی است. بدون تردید آن را حذف کنید، زیرا git تاریخچه را نگه می‌دارد و در صورت نیاز، کد همیشه قابل بازیابی است.

علل ظهور کد مرده

اولین و رایج‌ترین علت — توسعه تکراری با بازآرایی ناقص. تیم قابلیت جدیدی را جایگزین قابلیت قدیمی می‌کند، اما ماژول‌های جایگزین‌شده را حذف نمی‌کند. اسپرینت‌ها چنین «دم‌هایی» را انباشته می‌کنند و پس از یک سال، پروژه با لایه‌ای از کد مرده پوشیده می‌شود.

دومین علت — تست A/B و feature toggle. شرایط فعال‌سازی ویژگی جدید ممکن است با گذشت زمان تثبیت شود (مثلاً همیشه true)، اما شاخه else با منطق جایگزین در کد باقی می‌ماند. توسعه‌دهندگان می‌ترسند آن را حذف کنند تا مبادا به طور تصادفی سیستم را خراب کنند اگر toggle دوباره تغییر کند.

سومین علت — تولید خودکار و کپی-پیست. تولیدکنندگان کد (IDE، قالب‌سازها) قال‌هایی با متدهایی ایجاد می‌کنند که توسعه‌دهنده پر نمی‌کند یا استفاده نمی‌کند. کد کپی‌شده از پروژه دیگر اغلب شامل بلوک‌های کاملی است که به زمینه جدید مرتبط نیستند.

چهارمین علت — ترس از حذف. در پروژه‌های بزرگ، توسعه‌دهندگان از حذف کد می‌ترسند زیرا مطمئن نیستند که واقعاً در هیچ جایی استفاده نمی‌شود. این ترس با سیستم تست ضعیف تشدید می‌شود: اگر بررسی خودکار وجود نداشته باشد، حذف می‌تواند منجر به باگ‌هایی شود که فقط در محیط تولید کشف می‌شوند.

خطرات کد مرده

کد مرده مستقیماً بر چهار جنبه از کیفیت پروژه تأثیر می‌گذارد: عملکرد ساخت، اندازه مصنوع، بار شناختی تیم و قابلیت اطمینان بازآرایی.

افزایش زمان کامپایل: کامپایلر فایل‌های استفاده‌نشده را پردازش می‌کند، وابستگی‌ها را تحلیل می‌کند و برای قطعاتی که هرگز اجرا نخواهند شد، بایت‌کد یا کد ماشین تولید می‌کند. در پروژه‌های بزرگ، این کار دقایقی به هر ساخت اضافه می‌کند. برای زبان‌های تفسیرشده (JavaScript, Python)، زمان بارگذاری ماژول و مصرف حافظه افزایش می‌یابد.

خطر باگ هنگام تغییر: توسعه‌دهنده هنگام تغییر کد، نمی‌داند که تابع فقط در یک شاخه مرده استفاده می‌شود. پس از بازآرایی، کد مرده کامپایل نمی‌شود یا خطا می‌دهد — تیم وقت خود را برای تشخیص مشکلی صرف می‌کند که بر عملکرد برنامه تأثیر نمی‌گذارد.

بار شناختی — گران‌ترین عامل است. هر تابع استفاده‌نشده هنگام خواندن کد نیاز به توجه دارد. توسعه‌دهنده انرژی ذهنی را برای درک اینکه این کد چرا وجود دارد و کجا فراخوانی می‌شود، صرف می‌کند. تحقیق Developer Productivity Lab (2025) نشان داد: حذف 20 درصد از کد مرده، زمان ورود به کد (onboarding time) را به طور متوسط 18 درصد کاهش می‌دهد.

کد مرده را بلافاصله پس از شناسایی حذف کنید. هر روز تأخیر احتمال اینکه شخصی از تیم ساعت‌ها را صرف مطالعه یک اثر باستانی کند که باید دیروز حذف می‌شد، افزایش می‌دهد.

ابزارهای جستجوی کد مرده

جستجوی کد مرده با دو روش اصلی انجام می‌شود: تحلیل ایستا (بدون اجرای برنامه) و تحلیل پویا (پروفایل‌سازی پوشش در زمان اجرا). هر رویکرد برای انواع مختلف کد مرده مؤثر است.

تحلیل‌گرهای ایستا از همه زبان‌های برنامه‌نویسی محبوب پشتیبانی می‌کنند. برای Java و Kotlin — SonarQube, IntelliJ IDEA Inspections, SpotBugs. برای JavaScript و TypeScript — ESLint با قوانین no-unused-vars و no-unused-modules. برای Swift — SwiftLint با قانون unused_declaration. برای Python — pylint با گزینه unused-import و vulture برای جستجوی عمیق.

مثال جستجو در Kotlin از طریق ProGuard

groovy
// build.gradle.kts — پیکربندی 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 نه تنها کلاس‌ها و متدهای استفاده‌نشده را حذف می‌کند، بلکه نام‌ها را در ساخت release کوچک می‌کند. ساخت با ProGuard فعال به طور خودکار نشان می‌دهد که کدام کلاس‌ها و متدها استفاده‌نشده در نظر گرفته می‌شوند — در گزارش usage.txt تمام کدهای حذف‌شده فهرست شده‌اند.

تحلیل پویا از طریق پوشش تست

ابزارهای پوشش کد (JaCoCo برای Java، XCTest coverage برای Swift، Istanbul برای JavaScript) نشان می‌دهند که کدام خطوط و شاخه‌ها در طول تست‌ها اجرا می‌شوند. متدهای با پوشش صفر — کاندیدای کد مرده هستند. با این حال، عدم پوشش تضمین نمی‌کند که کد در محیط تولید فراخوانی نمی‌شود — برای اطمینان کامل از ترکیب تحلیل ایستا و پویا استفاده کنید.

CI pipeline را به گونه‌ای پیکربندی کنید که ساخت در صورت تجاوز از آستانه اعلان‌های استفاده‌نشده، ناموفق باشد. SonarQube Quality Gate با قانون «سهم کد خصوصی استفاده‌نشده بیش از 3٪ نباشد» از انباشت کد مرده در سطح فرآیند توسعه جلوگیری می‌کند.

چگونه کد مرده را ایمن حذف کنیم

فرآیند حذف کد مرده از چهار مرحله تشکیل شده است: پیدا کنید، بررسی کنید، حذف کنید، دوباره بررسی کنید. رد شدن از هر مرحله خطر بازگشت را افزایش می‌دهد.

مرحله اول — جستجوی کاندیداها از طریق تحلیل‌گر ایستا. گزارشی از اعلان‌های استفاده‌نشده دریافت کنید: توابع، کلاس‌ها، متغیرها، importها. موارد مثبت کاذب را فیلتر کنید — تحلیل‌گرها گاهی در بازتاب (reflection)، بارگذاری پویای کلاس‌ها یا فراخوانی‌های پنهان از طریق سریال‌سازی اشتباه می‌کنند.

مرحله دوم — بررسی از طریق git blame و تاریخچه تغییرات. ببینید کد چه زمانی و چرا نوشته شده است. اگر کد بخشی از ویژگی‌ای بود که با feature toggle غیرفعال شده، مطمئن شوید که toggle تثبیت شده و دوباره فعال نخواهد شد. کدی که در مورد حذف آن تردید دارید را کامنت کنید و یک TODO با وظیفه بررسی مجدد پس از یک ماه بگذارید.

مرحله سوم — حذف در یک شاخه جداگانه با اجرای مجموعه کامل تست‌ها. اگر تست‌ها گذشتند — احتمال بازگشت کم است. اگر تست‌ها ناموفق بودند — یعنی کد هنوز استفاده می‌شود و باید مشخص کرد در کدام سناریو.

cpp
// قبل — کد مرده و کد زامبی در یک فایل
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));
}

// بعد — کد مرده حذف شد، کد زامبی پاک شد
int calculatePrice(int price, double rate) {
    return static_cast<int>(price * (1 + rate));
}

مرحله چهارم — بازبینی کد تغییرات. بازبین باید تأیید کند که کد واقعاً مرده است. اگر بازبین مطمئن نیست — یک کامنت در کد بگذارید و حذف را تا تحلیل کامل به تعویق بیندازید. پس از ادغام شاخه، شاخه را حذف کنید تا کد زامبی در مخزن git تکثیر نشود.

یک قانون وضع کنید: هیچ درخواست pull نباید حاوی کد مرده جدید باشد. یک linter به هوک‌های pre-commit اضافه کنید که در صورت وجود متغیرها یا importهای استفاده‌نشده، commit را مسدود می‌کند. پیشگیری همیشه ارزان‌تر از پاکسازی است.

سؤالات متداول

آیا کد مرده می‌تواند باعث خطاهای کامپایل شود؟

بله، اگر کد مرده حاوی خطاهای نحوی باشد یا به انواع حذف‌شده اشاره کند. کامپایلرهای مدرن همچنان شاخه‌های مرده را بررسی می‌کنند، بنابراین خطا در بلوک if(false) باعث رد ساخت می‌شود. این یک محافظت است: کد نباید آنقدر مرده باشد که کامپایلر آن را بررسی نکند.

خطر کد زامبی برای تازه‌کاران در تیم چیست؟

کد زامبی گمراه‌کننده است: توسعه‌دهنده جدید تابعی با مستندات می‌بیند و تصور می‌کند که استفاده می‌شود. او وقت خود را صرف مطالعه کد غیرکاربردی می‌کند و ممکن است به طور تصادفی منطق جدید را به یک موجودیت قدیمی متصل کند که ایجاد یک باگ سخت‌یاب می‌کند.

چگونه کد مرده را در پروژه جاوااسکریپت پیدا کنیم؟

از ESLint با قوانین no-unused-vars و no-unused-modules و همچنین ابزار knip استفاده کنید — این ابزار exports و imports را در کل پروژه تحلیل می‌کند و فایل‌ها، توابع و وابستگی‌های استفاده‌نشده را پیدا می‌کند. برای مونورپوهای بزرگ، knip کامل‌ترین تصویر را نشان می‌دهد.

آیا قبل از انتشار باید کد مرده را حذف کرد؟

بهتر است قبل از انتشار حذف کنید، اما نه در آخرین لحظه. حذف کد مرده یک کار فنی است که در اسپرینت جداگانه برنامه‌ریزی می‌شود. درست قبل از انتشار، حذف ممکن است ناپایداری ایجاد کند اگر کد آنقدرها هم که به نظر می‌رسید مرده نباشد.

آیا کامپایلرها به حذف خودکار کد مرده کمک می‌کنند؟

بله، کامپایلرها و مینی‌فایرهای مدرن (ProGuard, R8, Terser, Closure Compiler) کد غیرقابل دسترس را در سطح Dead Code Elimination حذف می‌کنند. با این حال، این کار نیاز به پاکسازی سورس‌ها را برطرف نمی‌کند: کامپایلر کد را از باینری حذف می‌کند، اما از مخزن نه — توسعه‌دهندگان همچنان هنگام خواندن به آن برخورد خواهند کرد.

خلاصه

  • کد مرده — قطعات استفاده‌نشده‌ای که هرگز اجرا نمی‌شوند اما در پروژه باقی می‌مانند.
  • کد زامبی — زیرمجموعه‌ای از کد مرده که قبلاً کار می‌کرد اما پس از بازآرایی اعتبار خود را از دست داده است.
  • علل اصلی ظهور: توسعه تکراری، feature toggle، تولید خودکار و ترس از حذف.
  • کد مرده زمان ساخت، اندازه باینری و بار شناختی تیم را افزایش می‌دهد.
  • ابزارهای جستجو: SonarQube, ESLint, SwiftLint, pylint, vulture, knip, ProGuard, JaCoCo.
  • حذف ایمن شامل: جستجو، تحلیل git، حذف در شاخه، اجرای تست‌ها و بازبینی کد.
  • پیشگیری از کد مرده: linterها در CI، هشدار درباره کد استفاده‌نشده در بازبینی کد و فرهنگ بازآرایی.

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید