موجّه مراجعة الكود يجب أن يخبر النموذج بما يبحث عنه، ومدى خطورة كل ملاحظة، وأي دليل يقدّمه. عبارة "راجع هذا الكود" تعطيك قائمة ودية من الاقتراحات تقع فيها ثغرة أمنية بين نصيحة عن docstring وتفضيل في التسمية. أما موجّه المراجعة الذي فيه قائمة تحقق ودرجات خطورة وطلب تعديلات diff فيعطيك تقريرًا تستطيع العمل عليه، ملاحظة بعد ملاحظة.
من "راجع هذا" إلى قائمة تحقق مع درجات خطورة
الكود في التبويبين فيه خطآن حقيقيان. قارن كيف يعرضهما كل رد.
def get_user(conn, username):
cur = conn.cursor()
cur.execute(f"SELECT id, email FROM users WHERE name = '{username}'")
row = cur.fetchone()
return {"id": row[0], "email": row[1]}الدالة بشكل عام قصيرة وسهلة المتابعة. بعض الاقتراحات:
- أضف تلميحات الأنواع، مثل
username: str، لتوضيح التوقيع. - أضف docstring يشرح ما تُرجعه الدالة.
- استخدم الاستعلامات ذات المعاملات. بناء SQL بـ f-strings قد يؤدي إلى حقن SQL.
- تعامل مع المستخدمين غير الموجودين.
fetchone()قد تُرجعNone. - التسمية: قد يصف الاسم
fetch_userالوصول إلى قاعدة البيانات أفضل.
وجد الرد الأول الخطأين كليهما، وهذه هي المشكلة في الحكم على المراجعة بما تذكره. الحقن يأتي ثالثًا في قائمة من خمسة، مخفّفًا بعبارة "قد يؤدي إلى"، دون إصلاح، بجوار نصيحة عن docstring. القارئ المستعجل سيضيف تلميحات الأنواع ويمضي.
غيّر الموجّه الثاني أربعة أشياء:
- النطاق. عبارة "الأخطاء والأمان ومعالجة الأخطاء فقط. تجاوز الأسلوب" تزيل الضجيج. الأسلوب مكانه أداة الفحص (linter) وأداة التنسيق، وهما أسرع ولا تناقضان نفسيهما أبدًا.
- درجة الخطورة. تجبر النموذج على الترتيب، والقائمة المرتّبة تخبرك من أين تبدأ.
- مُدخل يسبّب المشكلة. عبارة "
x' OR '1'='1" تحوّل الخطر المبهم إلى عرض عملي تستطيع تشغيله. وهي أيضًا أفضل مُصفٍّ للإنذارات الكاذبة، كما يُظهر القسم الأخير. - تعديلات diff. التعديل الصغير لكل ملاحظة يمكن قبوله أو رفضه وحده. أما الدالة المعاد كتابتها فتخلط كل إصلاح بتغييرات لم يطلبها أحد.
عبارة "إذا لم يوجد شيء في درجة خطورة ما، فلا تخترع شيئًا" أهم مما تبدو. حين يُطلب من النموذج مراجعة، يميل إلى إنتاج ملاحظات حتى حين يكون هناك القليل مما يُعثر عليه، وأضعفها يحشو القائمة. الإذن الصريح بعدم الإبلاغ عن شيء في درجة ما يقطع هذا الحشو.
السياق الذي يحتاجه المراجع
المراجع البشري يعرف الغرض من الكود ومن أين تأتي مُدخلاته. أما النموذج فلا يعرف إلا ما تلصقه. جملة "username يأتي مباشرة من نموذج تسجيل الدخول" هي ما يجعل حقن SQL ملاحظة عالية الخطورة لا نظرية. سياق مفيد للمراجعة:
- من أين تأتي المُدخلات: المستخدمون، أو خدمة داخلية أخرى، أو ملف إعدادات تتحكم فيه.
- ما الذي يستدعي الكود وما الذي يتوقعه في المقابل.
- بيئة التشغيل: إصدار اللغة، وإطار العمل، ومشغّل قاعدة البيانات. إصلاح الحقن أعلاه يستخدم
?لأن sqlite3 تستخدم هذا العنصر النائب، وبعض المشغّلات الأخرى تستخدم%s. - ما يهمك أكثر في هذا التغيير: الصحة، أو الأمان، أو الأداء، أو الثلاثة معًا.
موجّه مراجعة قابل لإعادة الاستخدام
يحوّل هذا المثال قائمة التحقق إلى قالب. غيّر اللغة والتركيز والكود، واحتفظ بالقواعد. إيقاف جزء القيود طريقة سريعة لترى كم من الضجيج يعود من دونه.
async function loadAll(ids) {
const results = [];
ids.forEach(async (id) => {
const res = await fetch(`/api/items/${id}`);
results.push(await res.json());
});
return results;
}1. عالية: الدالة تعود قبل أن ينتهي أي طلب (السطر 3)
forEach لا تنتظر الدوال غير المتزامنة. تُرجع loadAll المصفوفة الفارغة results فورًا، وتحدث الإضافات لاحقًا. أي مستدعٍ يحصل على [].
2. متوسطة: الطلبات الفاشلة تُعامل كبيانات (السطر 5)
الاستجابة 404 أو 500 ليست استثناءً في fetch. جسم خطأ بصيغة JSON يُحلَّل ويُضاف كأنه عنصر، والجسم غير JSON يجعل res.json() تطلق خطأ داخل دالة لا ينتظرها أحد.
إصلاح للاثنين، يحافظ أيضًا على ترتيب النتائج مطابقًا لترتيب ids:
async function loadAll(ids) {
- const results = [];
- ids.forEach(async (id) => {
- const res = await fetch(`/api/items/${id}`);
- results.push(await res.json());
- });
- return results;
+ return Promise.all(
+ ids.map(async (id) => {
+ const res = await fetch(`/api/items/${id}`);
+ if (!res.ok) throw new Error(`Item ${id}: HTTP ${res.status}`);
+ return res.json();
+ })
+ );
}
سطر الدور يضع معيارًا ("المشكلات الحقيقية ولا شيء غيرها")، وهنا يساعد موجّه الدور أكثر ما يساعد. وإذا كان برنامج سيقرأ المراجعة، مثل سكربت ينشر الملاحظات تعليقات على pull request، فاطلب JSON بحقول ثابتة بدلًا من النثر، وتُظهر صفحة المخرجات المنظمة كيف.
التعامل مع الإنذارات الكاذبة
بعض الملاحظات ستكون خاطئة. النموذج لا يرى المستدعي الذي يفحص المُدخل، ولا قيد قاعدة البيانات الذي يجعل حالة ما مستحيلة، ولا سبب أن سطرًا غريب المظهر مقصود. وقد يخطئ أيضًا في سلوك مكتبة ما، وتشرح صفحة هلوسة الذكاء الاصطناعي لماذا لا يكون الادعاء الواثق ادعاءً مفحوصًا.
اختبر كل ملاحظة بالمُدخل الذي يسبّبها. إذا لم تستطع إنتاج مُدخل يصل إلى المشكلة في نظامك، فاعترض بالسياق الناقص بدلًا من قبول الإصلاح:
function formatPrice(cents) {
return `$${(cents / 100).toFixed(2)}`;
}
لا تُستدعى إلا من `renderCart`، التي تعود مبكرًا ما لم يكن `Number.isInteger(cents)` صحيحًا. هل ما زالت هذه مشكلة؟ إن لم تكن، فاسحب الملاحظة.مع وجود ذلك الفحص، لا: formatPrice لا تتلقى إلا عددًا صحيحًا، فالملاحظة لا تنطبق وأسحبها.
شيء واحد لا يغطيه الفحص: الأعداد الصحيحة السالبة تجتاز Number.isInteger، وformatPrice(-500) تُرجع "$-5.00". إذا كانت المبالغ المستردة أو الخصومات يمكن أن تصل إلى هذه الدالة، فقد تريد "-$5.00" بدلًا منها. وإن لم تكن، فلا شيء يحتاج إلى تغيير.
النموذج الذي يُعرض عليه دليل جديد يجب أن يسحب الملاحظة أو يشرح لماذا تظل قائمة مع هذا الدليل. كلا الأمرين مفيد. أما النموذج الذي يوافق على كل اعتراض ببساطة فلا يراجع، فاحكم على الرد بأسبابه، لا بموافقته. وفي الكود الذي كتبه النموذج نفسه، أجرِ المراجعة في محادثة جديدة، حتى لا تُقرأ المراجعة من خلال الاستدلال نفسه الذي أنتج الكود. والعادات نفسها في النطاق والسياق والاختبارات تجعل الكود أفضل من البداية، وراجع موجّهات لكتابة الكود.
الأسئلة الشائعة
ما الموجّه الجيد لمراجعة الكود؟
سمِّ ما تجب مراجعته (الأخطاء، والأمان، ومعالجة الأخطاء)، واطلب درجة خطورة لكل ملاحظة، واشترط مُدخلًا فعليًا يسبّب المشكلة مع تعديل diff يصلحها. واطلب من النموذج تجاوز التنسيق والتسمية ما لم تطلبهما. وأعطه السياق الذي يملكه المراجع البشري: الغرض من الكود وما الذي يستدعيه.
هل يمكن أن يحل الذكاء الاصطناعي محل مراجعة الكود البشرية؟
لا، لكنه مرور أول مفيد. إنه سريع، وجيد في أنماط الأخطاء الشائعة مثل None غير المعالجة، وawait المنسية، واستعلامات SQL المبنية من النصوص. لكنه لا يعرف قواعد منتجك ولا بقية قاعدة الكود ولا سبب اتخاذ قرار ما، وبعض ملاحظاته ستكون خاطئة. استخدمه قبل المراجعة البشرية، لا بدلًا منها.
لماذا تُبلغ مراجعة الذكاء الاصطناعي عن مشكلات غير حقيقية؟
النموذج لا يرى إلا الكود الذي ألصقته. إذا كانت قيمة ما تُفحص لدى المستدعي، أو كانت حالة ما مستحيلة في نظامك، فلا يستطيع النموذج معرفة ذلك، فيُبلغ عن الخطر على أي حال. طلب مُدخل فعلي يسبّب الفشل يُصفّي كثيرًا منها: الملاحظة التي لا يوجد مُدخل واقعي يسبّبها هي في الغالب إنذار كاذب.
هل أطلب من الذكاء الاصطناعي إعادة كتابة الكود أثناء المراجعة؟
اطلب تعديلات diff صغيرة، واحدًا لكل ملاحظة، بدلًا من ملف معاد كتابته. إعادة الكتابة الكاملة تخلط الإصلاحات بتغييرات لم يطلبها أحد، وستضطر إلى مراجعة إعادة الكتابة أيضًا. تعديلات diff تتيح لك قبول كل ملاحظة أو رفضها وحدها.