تست و بازبینی کدی که خودتان ننوشته‌اید

⏱ زمان مطالعه: حدود ۵ دقیقه

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

چرا این چک‌لیست را جدی بگیرید

کد تولیدشده معمولاً از نظر ظاهری تمیز به نظر می‌رسد؛ نام متغیرها خوانا هستند، تورفتگی درست است، حتی گاهی کامنت هم دارد. همین ظاهر مرتب باعث می‌شود بازبینی سطحی انجام شود و نکات مهم‌تر نادیده گرفته شوند. بازبینی دفاعی یعنی به‌جای اعتماد به ظاهر کد، پنج نقطهٔ مشخص را هر بار، بدون استثنا، بررسی کنید — چه کد را یک مدل نوشته باشد، چه یک همکار تازه‌کار.

تست و بازبینی کدی که خودتان ننوشته‌اید

چک‌لیست بازبینی: پنج نقطهٔ کلیدی

۱. ورودی‌های کاربر

هر جایی که کاربر می‌تواند متن، عدد، فایل یا URL وارد کند، باید پیش از استفاده اعتبارسنجی شود. سؤال‌هایی که باید از خودتان بپرسید:

  • آیا طول، نوع و فرمت ورودی بررسی می‌شود؟
  • آیا ورودی مستقیم داخل query پایگاه‌داده یا یک دستور سیستم‌عامل قرار می‌گیرد؟
  • آیا خروجی که از ورودی کاربر ساخته می‌شود، پیش از نمایش در صفحه escape می‌شود؟

۲. دسترسی به فایل

کدی که فایل می‌خواند، می‌نویسد یا حذف می‌کند باید مسیر را محدود کند. نکات قابل بررسی:

  • آیا مسیر فایل مستقیماً از ورودی کاربر ساخته می‌شود؟
  • آیا محدودیتی برای این‌که فقط داخل یک پوشهٔ مشخص عمل شود وجود دارد؟
  • آیا حجم و نوع فایل آپلودشده بررسی می‌شود؟

۳. رمزها و کلیدها در کد

یکی از رایج‌ترین اشتباهات کد تولیدشده، قرار دادن API key، رمز پایگاه‌داده یا توکن مستقیماً داخل فایل کد است. پیش از commit کردن یا انتشار:

  • جستجو کنید که آیا رشته‌ای شبیه کلید یا رمز داخل فایل‌ها باقی مانده است.
  • مطمئن شوید مقادیر حساس از طریق متغیرهای محیطی (environment variables) خوانده می‌شوند، نه hard-code شده باشند.
  • بررسی کنید فایل‌های تنظیمات حساس در .gitignore قرار دارند.

۴. وابستگی‌های ناشناخته

هر کتابخانه‌ای که به پروژه اضافه می‌شود، بخشی از سطح ریسک شما می‌شود. پیش از پذیرفتن یک dependency جدید:

  • ببینید آیا این کتابخانه شناخته‌شده و به‌روز است یا مدت‌هاست نگهداری نشده.
  • بررسی کنید آیا واقعاً به آن نیاز دارید یا همان کار با کد ساده‌تر قابل انجام است.
  • نسخهٔ دقیق را قفل کنید تا یک بروزرسانی غیرمنتظره رفتار برنامه را عوض نکند.

۵. خطاهای بی‌صدا

کد تولیدشده گاهی خطاها را می‌گیرد اما هیچ کاری با آن‌ها نمی‌کند: یک catch خالی، شرطی که همیشه true برمی‌گرداند، یا لاگی که هیچ‌جا خوانده نمی‌شود. این نوع خطا خطرناک‌تر از یک crash آشکار است، چون تا مدت‌ها کسی متوجه‌اش نمی‌شود:

try {
  saveUserData(data);
} catch (e) {
  // خالی — خطا بی‌صدا بلعیده می‌شود
}

نسخهٔ بهتر، حتی به‌شکل ساده، خطا را قابل مشاهده نگه می‌دارد:

try {
  saveUserData(data);
} catch (e) {
  logger.error("saveUserData failed", e);
  throw e;
}
نقطهٔ بازبینی سؤال کلیدی ریسک در صورت نادیده گرفتن
ورودی کاربر آیا پیش از استفاده بررسی می‌شود؟ داده‌های خراب، خطای غیرمنتظره
دسترسی فایل آیا مسیر محدود شده است؟ خواندن یا نوشتن فایل خارج از محدودهٔ مجاز
رمز در کد آیا مقدار حساس hard-code شده؟ افشای اطلاعات در صورت انتشار عمومی کد
وابستگی ناشناخته آیا نگهداری‌شده و ضروری است؟ باگ یا رفتار غیرمنتظره در بروزرسانی‌های آینده
خطای بی‌صدا آیا هر خطا جایی ثبت یا مدیریت می‌شود؟ مشکلاتی که ماه‌ها بدون توجه باقی می‌مانند

تست نوشتن برای کدی که خودتان ننوشته‌اید

وقتی منطق داخلی یک تابع را کامل نمی‌شناسید، بهترین راه این است که از رفتار بیرونی آن شروع کنید، نه از جزئیات پیاده‌سازی:

  • ابتدا مشخص کنید ورودی‌های معمول و ورودی‌های مرزی (خالی، خیلی بزرگ، نوع اشتباه) چه خروجی‌ای باید تولید کنند.
  • برای هرکدام یک تست کوتاه بنویسید، حتی پیش از این‌که کد را کامل خوانده باشید.
  • وقتی تستی fail می‌شود، آن نقطه دقیقاً جایی است که باید کد را با دقت بیشتری بخوانید.
  • پس از اطمینان از رفتار درست، تست‌ها را نگه دارید؛ آن‌ها مستندی هستند که در آینده از تغییرات ناخواسته جلوگیری می‌کنند.

یک نمونهٔ ساده

فرض کنید تابعی به نام parseAmount دریافت کرده‌اید که قرار است رشتهٔ مبلغ را به عدد تبدیل کند. پیش از خواندن پیاده‌سازی داخلی‌اش، چند تست کوتاه برای رفتار مورد انتظار بنویسید:

test("عدد معمولی را درست تبدیل می‌کند", () => {
  expect(parseAmount("1200")).toBe(1200);
});

test("ورودی خالی را رد می‌کند یا صفر برمی‌گرداند", () => {
  expect(parseAmount("")).toBe(0);
});

test("ورودی غیرعددی خطا می‌دهد", () => {
  expect(() => parseAmount("abc")).toThrow();
});

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

هدف بازبینی، پیدا کردن بهانه برای رد کردن کد نیست؛ هدف این است که پیش از رسیدن به کاربر، جایی که باید دقیق‌تر نگاه کنید را مشخص کنید.

اگر این چک‌لیست را به یک عادت تیمی تبدیل کنید — مثلاً بخشی از فرایند pull request — بازبینی دیگر یک مانع کند نیست، بلکه بخشی طبیعی از تحویل کد می‌شود. برای دیدی گسترده‌تر دربارهٔ امنیت در پروژه‌های ساخته‌شده با هوش مصنوعی، نقشهٔ راه امنیت هوش مصنوعی نقطهٔ شروع خوبی است.

جمع‌بندی

  • پنج نقطهٔ کلیدی بازبینی: ورودی کاربر، دسترسی فایل، رمزهای در کد، وابستگی‌های ناشناخته و خطاهای بی‌صدا.
  • برای کدی که خودتان ننوشته‌اید، تست‌نویسی را از رفتار بیرونی شروع کنید، نه از جزئیات داخلی.
  • هیچ رمز یا کلیدی نباید مستقیم داخل کد باقی بماند؛ همیشه از متغیرهای محیطی استفاده کنید.
  • خطاهای بی‌صدا از crash آشکار خطرناک‌ترند، چون دیرتر کشف می‌شوند.
  • تبدیل این چک‌لیست به بخشی از فرایند pull request، بازبینی را عادت می‌کند نه یک وظیفهٔ فراموش‌شده.
(0 رأی)

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *