تجنب إعادة الهيكلة.
يقوم مساعدو الذكاء الاصطناعي بتكديس كود جديد شبه مكرر بجوار ما هو موجود بالفعل بدلاً من إعادة تنظيمه، مما يؤدي إلى زيادة تكرار الأكواد واختفاء إعادة الهيكلة — العمل التطويري الذي يحافظ على صحة قاعدة الكود — بصمت.
##Signs and Symptoms
يرى المراجع ملف فروقات (diff) يتكون بالكامل تقريباً من إضافات. لقد قام النموذج بحل المشكلة عن طريق إضافة دالة أو فرع أو ملف جديد بدلاً من تعديل النموذج المجرد الذي كان ينبغي أن يستوعب التغيير. العلامات المميزة:
- النسخ واللصق مع تعديلات طفيفة: دالة جديدة متطابقة بنسبة 90% مع دالة موجودة مسبقاً، وتختلف فقط في قيمة حرفية، أو اسم حقل، أو جملة
ifإضافية واحدة. - نسخ متوازية شبه متطابقة: مثل وجود
formatUserCsv، وformatAdminCsv، وformatGuestCsvوكلها تكتب نفس الدورة يدوياً بدلاً من كتابة دالة واحدة ذات معاملات. - تشتت الفروع بدلاً من الاستخراج: تكبر الدالة الطويلة وتكتسب جملة
else ifأخرى بدلاً من قيام النموذج باستخراج جدول استراتيجية/بحث (strategy/lookup table). - إعادة الاختراع: كتابة دالة
deepClone/debounceأو محلل تاريخ يدوياً بينما يستورد المستودع بالفعل مكتبات مثل lodash أو date-fns (تطلق عليها Ox Security اسم "الأسلوب التقليدي Vanilla Style"). - الإفراط في التخصيص: دالة مساعدة محددة للغاية ومخصصة للاستخدام الفردي بينما توجد دالة عامة في ملف مجاور.
- "أخطاء مكررة مألوفة (Bugs déjà-vu)": يجب تطبيق نفس الإصلاح في ثلاث نسخ مكررة لأن التكرار لم يتم دمج وتلخيصه أبداً.
// موجود في المستودع مسبقاً:
function priceWithTax(items: Item[]) {
const subtotal = items.reduce((s, i) => s + i.price * i.qty, 0);
return subtotal * 1.2; // 20% VAT
}
// ما يضيفه النموذج لحالة "الخصم" الجديدة —
// نسخة ثانية كاملة بدلاً من معامل إضافي:
function priceWithTaxDiscounted(items: Item[], discount: number) {
const subtotal = items.reduce((s, i) => s + i.price * i.qty, 0); // مكرر
return subtotal * (1 - discount) * 1.2; // منطق ضريبة القيمة المضافة مكرر
}
الرائحة هيكلية، وبالتالي فهي تظهر بوضوح عبر التغيير بأكمله، وليس عبر جزء واحد منه: الكثير من الإضافات الخضراء، وتغيير قليل جداً في الكود الحالي، مع عمل مكتشف التكرار بكثافة على السطور الجديدة.
##Reasons for the Problem
لماذا تنتجها النماذج؟
- انحياز الإضافة للرمز التالي. يكمل نموذج اللغة الكبيرة الأمر الموجه أمامه. إن إصدار كتلة جديدة قائمة بذاتها هو التكملة الأكثر احتمالاً محلياً والأقل خطورة؛ بينما يتطلب تعديل نموذج مجرد بعيد الاحتفاظ بالوحدة البرمجية بأكملها في سياق العمل والتنبؤ بتعديل متناسق عالمياً، وهو أمر أصعب ولا يجد مكافأة في الأمر الموجه الفوري.
- سياق مستودع ضعيف. نادراً ما يقوم مساعدو البرمجة بتحميل قاعدة الكود بأكملها. إذا لم يتمكن النموذج من رؤية الدالة المساعدة أو المكتبة أو الكلاس الأساسي الحالي، فلن يتمكن من إعادة استخدامه — وبالتالي يقوم بإعادة بنائه. يصف تقرير Ox Security هذا بتأثير "جيش من المطورين المبتدئين": الكثير من الكود البرمجي الذي يعمل محلياً، مع غياب الذاكرة المعمارية للنظام.
- إعادة الهيكلة محفوفة بالمخاطر وغير مجزية للنموذج. تؤثر إعادة التنظيم على كود لم يُطلب من النموذج تغييره، ويمكن أن تكسر المستدعين والاختبارات. يعمل مساعد التملق البرمجي ("اجعل الكود يعمل فقط") على تقليل نطاق التأثير من خلال عدم لمس الكود الذي يعمل بالفعل — وهو بالضبط السلوك الذي قيّمته Ox كـ "تجنب لإعادة الهيكلة" في 80-90% من الأكواد المولدة بالذكاء الاصطناعي، و"الإفراط في التخصيص" (الاستخدام الأحادي بدلاً من القابل لإعادة الاستخدام) في 80-90% أخرى.
- تاريخ انتهاء التدريب (Training-data staleness). قد لا يعرف النموذج أن المستودع قد اعتمد وحدة مساعدة أو قام بترقية مكتبة بعد تاريخ انتهاء تدريبه، لذا يقوم بكتابة ما هو موجود بالفعل يدوياً.
- التوليد رخيص، بينما الحذف مخيف. لا يكلف توليد 40 سطراً جديداً النموذج شيئاً؛ بينما إقناعه بحذف ودمج 40 سطراً موجوداً يواجه غريزته في الحفاظ على المتاح.
لماذا يسبب ضرراً؟
- تضاعف التكرار. وجد تحليل GitClear لعام 2025 لـ 211 مليون سطر متغير أن السطور المنسوخة/الملصقة ارتفعت من ~8.3% (2021) إلى 12.3% (2024) — وهو العام الأول الذي تجاوز فيه التكرار الكود "المنقول" (المعاد هيكلته) — بينما انخفضت السطور المعاد هيكلتها من ~25% إلى أقل من 10%، أي ما يقرب من 60% انخفاض. وقفزت كتل التكرار المكونة من 5 سطور أو أكثر بمعدل ~8 أضعاف في عام 2024.
- قابليته الصيانة والصحة. كل نسخة مستنسخة هي مكان يمكن فيه نسيان إصلاح مستقبلي — "أخطاء مكررة مألوفة (Bugs déjà-vu)"، حيث يتكرر نفس العيب ويجب معالجته N من المرات (تظهر إحصائيات Ox أن 70-80% من أكواد الذكاء الاصطناعي تنتهك مبادئ إعادة الاستخدام بهذه الطريقة).
- تراكم الديون التقنية. إعادة الهيكلة هي العمل الذي يبقي الفوضى منخفضة؛ وإلغاؤها يعني إنشاء الديون دون سدادها أبداً. وتنمو قاعدة الكود بشكل أسرع من تحسنها.
- عبء المراجعة. يجب على المراجعين الآن مقارنة الكتل شبه المتطابقة بالعين للتأكد من أنها متطابقة عن قصد، وهو تحول في عبء العمل الإدراكي تصفه مناقشة Stack Overflow حول "روائح الكود لوكلاء الذكاء الاصطناعي" — حيث ينتقل العمل من الكتابة إلى المراجعة والدمج.
##Treatment
تكتيكات المراجعة وصياغة الأوامر
- وجه النموذج إلى ما هو موجود. "قبل إضافة كود، ابحث في المستودع عن دالة مساعدة/أداة/كلاس أساسي حالي وأعد استخدامه؛ وإذا لم يكن أي منها مناسباً، فقم بتعميم الأقرب". الصق الوحدة البرمجية ذات الصلة في السياق حتى يتمكن من رؤية النموذج المجرد.
- قيّد شكل ملف الفروقات (diff). "يفضل تعديل الدوال الحالية بدلاً من إضافة دوال جديدة. وإذا كان مسارا كود يشتركان في المنطق، فاستخرج دالة مشتركة (Extract Function) بدلاً من تكرار الكود".
- أجبره على تشغيل الأدوات. اطلب من المساعد تشغيل مكتشف التكرار (jscpd / PMD CPD) وأداة الفحص، وحل أي نتائج تشير إلى كتل مكررة جديدة قبل إعلان الانتهاء — فهذا يحول الرائحة غير المرئية إلى بوابة فحص فاشلة.
- اطلب إعادة الهيكلة صراحة كخطوة ثانية. التوليد والدمج مهمتان مختلفتان؛ قم بأداء خطوة "اجعل الكود يعمل"، ثم خطوة منفصلة "الآن نظف هذا وأزل التكرار"، وهو ما تتعامل معه النماذج بشكل أفضل بكثير عند الطلب المباشر.
- أضف بوابة جودة في خادم التكامل المستمر (CI) حتى لا يرتفع التكرار دون ملاحظته (مثل حد السطور المكررة في Sonar، أو
jscpd --threshold).
إعادة الهيكلة الفعلية — حدد الحركات الكلاسيكية: استخراج الدالة (Extract Function)، وجعل الدالة ذات معاملات (Parameterize Function)، واستبدال الشروط بالتعددية أو جدول البحث (Replace Conditional with Polymorphism or a lookup table) للتخلص من الكود المكرر (Duplicate Code).
// قبل: دالتان شبه متطابقتين (تم تجنب إعادة الهيكلة)
function priceWithTax(items: Item[]) {
const subtotal = items.reduce((s, i) => s + i.price * i.qty, 0);
return subtotal * 1.2;
}
function priceWithTaxDiscounted(items: Item[], discount: number) {
const subtotal = items.reduce((s, i) => s + i.price * i.qty, 0);
return subtotal * (1 - discount) * 1.2;
}
// بعد: استخراج الدالة (Extract Function) + جعل الدالة ذات معاملات
const VAT = 1.2;
const subtotalOf = (items: Item[]) =>
items.reduce((s, i) => s + i.price * i.qty, 0);
function priceWithTax(items: Item[], discount = 0) {
return subtotalOf(items) * (1 - discount) * VAT;
}
مصدر واحد للحقيقة للمجموع الفرعي وضريبة القيمة المضافة: أي تغيير مستقبلي لقاعدة الضريبة هو تعديل في سطر واحد بدلاً من البحث والترقيع في N من الأماكن.
##Detected by
- jscpd duplication above --threshold / --min-tokens — كشف النسخ/اللصق
- PMD Copy/Paste Detector (minimum-tokens duplication) — CPD
- SonarQube duplicated_lines_density / quality-gate duplicated-blocks condition — التكرار
- ESLint (eslint-plugin-sonarjs) sonarjs/no-identical-functions — no-identical-functions
- ESLint (eslint-plugin-sonarjs) sonarjs/no-duplicate-string — no-duplicate-string