إصلاح الكود المولَّد بالذكاء الاصطناعي
درس 12 من 12
12إصلاح الكود المولَّد بالذكاء الاصطناعي
الصورة الكبيرةالكود المولَّد يبدو واثقًا ونظيفًا، وهذا ما يجعل أخطاءه خطيرة. يعمل للمثال السعيد، ويسقط عند قائمة فارغة أو مدخل غريب أو مكتبة اسمها مخترع.
ماذا تشاهد في الرسم: دورة الإصلاح: الاختبار يكشف الخطأ ويثبت الإصلاح، والإصلاح أصغر تغيير يجعله ينجح.
خارطة هذا الجزء
المفاهيم بالترتيب، اضغط أيًّا منها للقفز إليه:
طريقان إلى نفس الفكرة
مثل وصفة طبخ من صديق كتبها بسرعة: تبدو صحيحة، لكنه نسي أن يقول «سخّن الفرن أولًا» وكتب مكوّنًا لا يباع في محلات بلدك. قبل أن تطبخ للضيوف، جرّبها مرة صغيرة وصحّح ما ينقص.
الأنماط الشائعة: هلوسة API (دالة أو وسيط غير موجود في الإصدار المثبّت)، هلوسة حزمة (اسم مكتبة غير موجود قد يسجّله مهاجم: slopsquatting)، الحالات الحدية (فارغ، صفر، None، Unicode، المناطق الزمنية)، الأمان (SQL بسلاسل نصية، أسرار في الكود، eval، تحقق مفقود)، الحالة المشتركة (قيم افتراضية قابلة للتغيير، متغيرات عامة)، والأخطاء المبتلعة (except: pass). المنهج: اختبار يعيد إنتاج الخطأ، ثم أصغر إصلاح، ثم تشغيل الكل. تحقق من الحزم في PyPI/npm قبل التثبيت، وثبّت الإصدارات.
قبل أن تبدأ
🧪الاختبارات
تكتب assert بسيطة أو pytest.
🔎المراجعة بالمساعد
الدرس السابق في هذا المسار.
الفكرة الجوهرية
1كود مولَّد بثلاثة أخطاء
هذه دالة «تحسب متوسط تقييمات منتج» كما ولّدها مساعد. تبدو سليمة. الاختبارات تكشف غير ذلك:
def average_rating(ratings, history=[]):
history.extend(ratings)
return round(sum(history) / len(history), 1)
def check(name, fn):
try:
print(name, "->", fn())
except Exception as e:
print(name, "-> CRASH", type(e).__name__)
check("first product", lambda: average_rating([4, 5]))
check("second product", lambda: average_rating([1, 1]))
check("no ratings", lambda: average_rating([]))المنتج الثاني متوسطه 1 لكنه ظهر 2.8 لأن history مشتركة بين كل الاستدعاءات. ومع تقييمات فارغة يجب أن يكون الرد واضحًا لا انهيارًا عشوائيًا.
2أصغر إصلاح
لا تعيد كتابة كل شيء. احذف الحالة المشتركة، وقرّر سلوك القائمة الفارغة صراحة، ثم أعد تشغيل نفس الاختبارات:
def average_rating(ratings):
if not ratings:
return None
return round(sum(ratings) / len(ratings), 1)
assert average_rating([4, 5]) == 4.5
assert average_rating([1, 1]) == 1.0
assert average_rating([]) is None
print("all tests pass")3الدوال والحزم المخترعة
قبل pip install أو npm install لاسم اقترحه المساعد: ابحث عنه في PyPI أو npm، وانظر للمستودع وعدد التنزيلات وتاريخ آخر إصدار. وقبل استدعاء دالة غير مألوفة، افتح توثيق الإصدار المثبّت أو جرّب help().
import importlib.util
import json
suggested = ["json", "requests_magic_retry", "pathlib"]
for name in suggested:
found = importlib.util.find_spec(name) is not None
print(f"{name:22} {'installed' if found else 'NOT FOUND, check PyPI first'}")
print("dumps has 'indent':", "indent" in json.dumps.__code__.co_varnames)requirements.txt أو package-lock.json، فالمساعد قد يكتب كود إصدار أحدث أو أقدم مليس عندك.مثال محلول
المسألة: دالة مولَّدة تقسم فاتورة 100 ريال على 3: round(total / n, 2) لكل شخص. الاختبار: sum(split(100, 3)) == 100 يفشل: 33.33 × 3 = 99.99. أصغر إصلاح: احسب الأجزاء بالهللات (أعداد صحيحة)، وأعطِ الباقي لأول شخص: [3334, 3333, 3333] هللة. الاختبار ينجح، والمال لا يضيع.
خرافة مقابل حقيقة
| الخرافة | الحقيقة |
|---|---|
| الكود الذي يعمل للمثال صحيح. | المثال السعيد أسهل حالة. الأخطاء في الأطراف. |
| إذا اقترح المساعد مكتبة فهي موجودة. | قد يخترع اسمًا، وقد يكون مسجّلًا بواسطة مهاجم. |
اختبر فهمك
دالة بقيمة افتراضية history=[] تعطي نتائج تتراكم بين الاستدعاءات. لماذا؟
القيم الافتراضية تُقيَّم عند تعريف الدالة لا عند كل استدعاء.
المساعد اقترح حزمة لم تسمع بها. أول خطوة؟
المساعد قد يؤكد ما اخترعه. المصدر الحقيقي هو السجل.
ما الإصلاح الجيد؟
التغيير الصغير أسهل مراجعة وأقل خطرًا.
بطاقات مراجعة سريعة
تحقق من فهمك
لماذا تكتب الاختبار قبل الإصلاح؟
ليثبت الخطأ أولًا، ثم يثبت أن الإصلاح عالجه ولم يكسر غيره.
ما الحالات الحدية التي تجربها دائمًا؟
فارغ، صفر، سالب، None، نص عربي، قيمة كبيرة جدًا.
كيف تتعامل مع المال في الكود؟
بأعداد صحيحة لأصغر وحدة (هللات) أو Decimal، لا float.