الكود الجاهز المطول.
يحشو مساعدو الذكاء الاصطناعي المنطق البسيط بتعليقات تعيد قول كل سطر، وشرح خطوة بخطوة، وسلالم دفاعية من فحوص null، وتعبيرات مطولة حيث يكفي أسلوب لغوي مألوف أو دالة مساعدة موجودة — فيتضخم عدد السطور دون إضافة أي سلوك.
##العلامات والأعراض
يكتشف المراجع الكود الجاهز المطول عندما يكون ملف الفروقات (diff) أطول بكثير مما تتطلبه المشكلة: حيث يتم شرح كل سطر بتعليق يعيد صياغته ببساطة، وتلتف التعبيرات البسيطة بسلالم شروط دفاعية لفحص null/undefined، ويظهر نفس شكل الكود مرتين أو ثلاث مرات بدلاً من تجميعه في دالة مساعدة واحدة. العلامة الفاضحة هي النسبة المرتفعة للتعليقات مقابل المنطق والسطور مقابل السلوك، بالإضافة إلى كتل كان يمكن كتابتها في ثلاثة سطور نموذجية.
// دالة للحصول على الاسم الكامل للمستخدم
function getFullName(user: User): string {
// فحص ما إذا كان المستخدم معرفاً
if (user === null || user === undefined) {
// إرجاع سلسلة نصية فارغة في حال عدم تقديم مستخدم
return "";
}
// الحصول على الاسم الأول، القيمة الافتراضية سلسلة فارغة
const firstName = user.firstName ? user.firstName : "";
// الحصول على الاسم الأخير، القيمة الافتراضية سلسلة فارغة
const lastName = user.lastName ? user.lastName : "";
// دمج الاسم الأول والأخير بمسافة
const fullName = firstName + " " + lastName;
// إزالة المسافات الفارغة وإرجاع النتيجة
return fullName.trim();
}
ثلاثة سطور من السلوك الفعلي مدفونة في نحو 12 سطراً من الشكليات. علامات أخرى: منشئات أو أغلفة فارغة تكتفي بالتمرير، وشكليات try { ... } catch (e) { throw e }، وx ? x : fallback حيث يكفي ??، وأداة تحقق مكتوبة يدوياً للبريد الإلكتروني أو الروابط بجوار وحدة التحقق الموجودة أصلاً في المشروع. وعندما يُنسخ الشكل المطول نفسه أيضاً باسم getDisplayName وgetLabel وgetInitials، وكل منها يعيد كتابة منطق تغطيه أداة formatName() بالفعل، يكون الإسهاب قد تحول إلى الكود المكرر — راجع التكرار بدلاً من الاستخراج.
##أسباب المشكلة
لماذا تنتجها النماذج؟
- انحياز الإطناب للرمز التالي. يتم تدريب نماذج اللغة الكبيرة على كميات هائلة من الدروس البرمجية، وإجابات Stack Overflow، وأكواد المبتدئين حيث التعليقات التفصيلية والمظاهر التوضيحية هي القاعدة العامة. التكملة الأكثر احتمالاً هي الأكثر شرحاً وتفصيلاً، وليست الأكثر إيجازاً.
- عملية RLHF تكافئ "المظهر الدقيق والمفصل". يدفع ضبط الفائدة والإطناب النماذج نحو مخرجات تبدو كاملة وتوضح نفسها بنفسها — تعليقات على كل سطر، وفحوصات دفاعية في كل مكان — وهو ما يكافئه المقيمون والمستخدمون حتى في حال عدم إضافة أي قيمة حقيقية.
- بلا سياق للمستودع لا توجد إعادة استخدام. من دون قاعدة الكود المحيطة في السياق، لا يمكن للنموذج أن يعرف أن أداة
formatName()أوvalidateEmail()موجودة بالفعل، فيعيد اشتقاق منطقها في مكانه. ويطابق هذا نمطين في تقرير OX Security: الإفراط في التخصيص (Over-Specification — "حلول شديدة التخصيص وأحادية الاستخدام لا يمكن تكييفها لأغراض أخرى"، في 80–90% من كود الذكاء الاصطناعي) وتجنب إعادة الهيكلة (Avoidance of Refactors، 80–90%). - توليد لا دمج. يُخرج الوكلاء كوداً جديداً مع كل أمر ونادراً ما يعودون لتكثيفه. وجد تحليل GitClear لعام 2025 لـ 211 مليون سطر معدّل أن الأسطر المرتبطة بإعادة الهيكلة ("المنقولة") انخفضت من 25% من الأسطر المعدلة في 2021 إلى أقل من 10% في 2024، بينما ارتفعت الأسطر المنسوخة والملصقة من 8.3% إلى 12.3% وتجاوزت الأسطر المنقولة لأول مرة في 2024؛ ونمت الكتل التي تضم خمسة أسطر مكررة أو أكثر نحو ثمانية أضعاف خلال 2024.
- الافتراض المتمثل في التعليق على كل شيء. وجدت Ox Security ظاهرة "التعليقات في كل مكان" بنسبة 90-100% في الكود المولد بالذكاء الاصطناعي.
لماذا يسبب ضرراً؟
- قابلية الصيانة: مساحة أكبر للقراءة والتعديل؛ والتعليقات الزائدة تفقد تزامنها مع الكود وتصبح مضللة فعلاً (رائحة التعليقات عند فاولر).
- الصحة والأمان: بمجرد نسخ كتلة مطولة، يجب إصلاح الخطأ أو الثغرة في N مكاناً — وهو نمط Bugs Déjà-Vu لدى OX (70–80%)، الذي يجعل "الأخطاء المتطابقة تظهر مراراً في أنحاء قاعدة الكود، فتتطلب الإصلاح نفسه عدة مرات".
- عبء المراجعة: تخفي الفروقات الكبيرة ذات المؤشرات الضعيفة التغييرات الحقيقية وتسبب إرهاق المراجعين، مما يؤدي إلى تسلل المشكلات الحقيقية دون ملاحظتها.
- تراكم الديون التقنية: كل نسخة شبه مكررة تجعل الاستخراج *التالي* أصعب، مما يرسخ المشكلة التي لا يستطيع النموذج رؤيتها عبر الملفات.
##المعالجة
تكتيكات المراجعة وصياغة الأوامر
- فرض إعادة الاستخدام قبل التوليد: "ابحث في قاعدة الكود عن دوال مساعدة موجودة (مثل
formatName، وvalidate*) وأعد استخدامها؛ ولا تعيد كتابتها". وفر الأدوات المساعدة ذات الصلة في السياق. - حدد ميزانية للمخرجات: "حافظ على هذا الكود تحت ~15 سطراً؛ ولا تضع تعليقات تعيد صياغة الكود — ضع فقط تعليقات توضح *السبب*".
- أجبر النموذج على تشغيل الأدوات: اطلب منه تشغيل
eslint/ruffوفحص التكرارjscpd، واطلب منه كتابة تقرير بالانتهاكات وإصلاحها قبل الإرجاع. - اطلب أصغر فرق ممكن وخطوة صريحة لإزالة التكرار: "إذا تكررت أي كتلة، فاستخرج دالة مشتركة واحدة واستدعها" (استخراج الدالة).
- ادمج أثناء المراجعة: عندما ترى النسخة شبه المطابقة الثالثة، طبّق استخراج الدالة أو رفع التابع (Pull Up Method) أو دمج الأجزاء الشرطية المكررة؛ وحيث يكتفي التعليق بشرح ما يفعله تعبير ما، طبّق استخراج المتغير أو إعادة تسمية التابع (Rename Method) ليحمل الكود نفسه الشرح ويمكن حذف التعليق.
إعادة الهيكلة (قبل ← بعد)
// بعد: إزالة التعليقات (الكود واضح بذاته)، وتقليص الشكليات،
// وإعادة استخدام الأداة الموجودة formatName() بدلاً من إعادة اشتقاق منطقها في مكانه
import { formatName } from "@/utils/format";
export const getFullName = (user?: User): string =>
formatName(user?.firstName, user?.lastName);
واحذف النسخ المكررة تماماً — إذا كانت getDisplayName/getLabel تفعل الشيء نفسه، فوجّه مستدعيها إلى دالة واحدة واحذف النسخ (تضمين التابع (Inline Method))؛ وما يبقى بلا مستدعين هو الكود الميت ويُحذف أيضاً. استبدل أداة التحقق المكتوبة يدوياً باستيراد الوحدة الموجودة بدلاً من الاحتفاظ بنسخة موازية.
قاعدة ذهبية: تعامل مع أي كتلة ذكاء اصطناعي تتجاوز فيها التعليقات سطور المنطق، أو حيث يمكنك تحديد دالة مساعدة تجاهلها النموذج، كمرشح للحذف وإعادة الاستخدام — فأسرع حل للكود الجاهز المطول هو عادةً كود *أقل*، وليس أكثر.
##أدوات الكشف
- ESLint (core) no-useless-catch — عبارات catch غير الضرورية (طقس الالتقاط ثم إعادة الرمي: catch (e) { throw e })
- ESLint (core) no-unneeded-ternary — العوامل الثلاثية حيث يوجد بديل أبسط (مع defaultAssignment: false تلتقط x ? x : fallback)
- typescript-eslint @typescript-eslint/prefer-nullish-coalescing — تفضيل ?? على || وعلى العوامل الثلاثية ذات فحص null الصريح
- ESLint (core) no-useless-constructor — منشئ فارغ مكرر / كود جاهز ممرر
- ESLint (core) max-lines-per-function — طول الدالة المتضخم/المطول (مؤشر جزئي)
- jscpd --min-tokens / --threshold — كشف النسخ/اللصق، حين تُنسخ الكتل المطوّلة وتُلصق (حد --min-tokens / --threshold)
- SonarQube / SonarCloud typescript:S4144 — يجب ألا تمتلك الدوال والأساليب تطبيقات متطابقة
- ESLint (eslint-plugin-sonarjs) sonarjs/no-identical-functions — يجب ألا تمتلك الدوال تطبيقات متطابقة