اختبرنا نماذج الذكاء الاصطناعي في كتابة كود حقيقي: من حلول ذكية إلى أخطاء كارثية. إليك ما اكتشفناه بعد مئات الساعات من التجارب العملية في بيئات إنتاج فعلية.
عندما طلبت من GitHub Copilot كتابة دالة لتصفية المصفوفات في JavaScript، أعطاني حلاً أنيقاً يستخدم Array.prototype.filter مع callback ذكي. لكن عندما حاولت تشغيله على مصفوفة تحتوي قيم null، تعطل كل شيء لأن الكود لم يتعامل مع الحالات الهامشية. هذا ليس خطأً عادياً — إنه نمط متكرر: الذكاء الاصطناعي ينتج كوداً يبدو جميلاً على السطح، لكنه يفشل في التفاصيل التي لا يراها المطورون المبتدئون. في آخر مشروع عملت عليه، وجدنا أن 42% من الـ PRs التي كتبها الذكاء الاصطناعي احتاجت تعديلات جوهرية قبل الدمج، أغلبها في معالجة الأخطاء والتعامل مع البيانات غير المتوقعة.
المشكلة ليست في قدرة الذكاء الاصطناعي على كتابة الكود — بل في قدرته على فهم السياق الحقيقي وراءه. عندما تطلب من ChatGPT كتابة دالة لحساب المتوسط، سيقدم لك حلاً مثالياً. لكن عندما تطلب نفس الدالة للعمل على بيانات حقيقية من قاعدة بيانات تحتوي قيم مفقودة وأصفار سالبة، سيبدأ الكود في الانهيار. في إحدى التجارب التي أجريناها على 50 مهمة برمجية واقعية، فشل الذكاء الاصطناعي في 38% منها في التعامل مع حالات البيانات غير المتوقعة، وهي نسبة كارثية لو كنت تعمل على نظام مالي أو طبي.
لفهم لماذا يفشل الذكاء الاصطناعي في كتابة كود جيد، يجب أن نفهم كيف يعمل تحت الغطاء. عندما تطلب من نموذج مثل GPT-4 كتابة دالة في Python، فهو لا يفهم البرمجة بالمعنى الذي نفهمه نحن. بدلاً من ذلك، يعمل النموذج على مستوى الـ tokens — قطع صغيرة من النص — ويحاول التنبؤ بالـ token التالي بناءً على السياق الذي تلقاه. هذا يعني أنه لا يفهم مفهوم الذاكرة أو الـ Event Loop أو حتى الفرق بين الـ I/O Bound والـ CPU Bound tasks. في إحدى المرات، كتب لي Copilot دالة تستخدم async/await داخل loop متزامن، مما تسبب في تعليق السيرفر بالكامل لأن الكود كان ينتظر كل طلب بشكل متسلسل بدلاً من التوازي.
الذكاء الاصطناعي جيد في تقليد الأنماط التي رآها في الكود الموجود على الإنترنت، لكنه ضعيف في فهم لماذا كُتب هذا الكود بهذه الطريقة. مثلاً، عندما طلبنا منه كتابة دالة لقراءة ملف CSV، أعطانا حلاً يستخدم pandas.read_csv بدون أي معالجة للأخطاء. عندما سألناه لماذا لم يضف try/except، أجاب ببساطة: "هذا هو الحل الأكثر شيوعاً في الأمثلة على الإنترنت". الحقيقة هي أن معظم الأمثلة على الإنترنت هي مجرد عروض توضيحية وليست كوداً جاهزاً للإنتاج. هذا هو الفارق الرئيسي بين الكود الذي يكتبه الذكاء الاصطناعي والكود الذي يكتبه مهندس متمرس: الأول يقلد، والثاني يفهم.
# مثال على كود كتبه الذكاء الاصطناعي يبدو جيداً لكنه فاشل في الإنتاج
import pandas as pd
def read_csv(file_path):
# هذا الكود يبدو أنيقاً لكنه خطير جداً
data = pd.read_csv(file_path)
return data
# المشاكل هنا:
# 1. لا معالجة للأخطاء (ماذا لو الملف غير موجود؟)
# 2. لا فحص لنوع الملف (ماذا لو كان الملف تالفاً؟)
# 3. لا حدود لحجم الملف (ماذا لو كان الملف 50 جيجا؟)
# 4. لا معالجة للترميز (ماذا لو كان الملف بترميز غير UTF-8؟)
# النسخة المعدلة للإنتاج:
import pandas as pd
import os
def read_csv_safe(file_path, max_rows=None, encoding='utf-8'):
if not os.path.exists(file_path):
raise FileNotFoundError(f"الملف {file_path} غير موجود")
try:
data = pd.read_csv(file_path, nrows=max_rows, encoding=encoding)
if data.empty:
raise ValueError("الملف فارغ أو غير صالح")
return data
except pd.errors.ParserError:
raise ValueError("الملف تالف أو ليس بصيغة CSV صحيحة")
except Exception as e:
raise RuntimeError(f"حدث خطأ أثناء قراءة الملف: {str(e)}")الذكاء الاصطناعي ليس بلا فائدة — في الواقع، هناك مجالات محددة يتفوق فيها بشكل ملحوظ. مثلاً، في كتابة الـ boilerplate code، لا يوجد منافس له. عندما كنت أعمل على مشروع React مؤخراً، استخدمنا Copilot لكتابة 80% من الـ components الأساسية، مما وفر لنا أسابيع من العمل. كما أنه ممتاز في كتابة الـ unit tests، خاصة عندما تعطيه الكود الأساسي وتطلب منه كتابة اختبارات له. في إحدى التجارب، كتب لنا 120 test case في أقل من ساعة، غطت معظم الحالات الأساسية التي كنا سنكتبها يدوياً.
لكن حتى في هذه المجالات، هناك نقاط ضعف مخفية. مثلاً، عندما طلبنا من الذكاء الاصطناعي كتابة اختبارات لوحدة تستخدم قاعدة بيانات، كتب اختبارات تعتمد على بيانات ثابتة بدلاً من استخدام قاعدة بيانات اختبار حقيقية. هذا النوع من الاختبارات يعطي شعوراً زائفاً بالأمان، لأنه لا يختبر التكامل الحقيقي بين الكود وقاعدة البيانات. كما أنه يميل إلى تكرار نفس الأنماط في الاختبارات، مما يجعلها غير فعالة في كشف الأخطاء الحقيقية. في أحد المشاريع، وجدنا أن 65% من الـ test cases التي كتبها الذكاء الاصطناعي كانت إما مكررة أو غير مفيدة في كشف الأخطاء الحقيقية.
في شركة ناشئة كنت أعمل معها العام الماضي، قررنا استخدام الذكاء الاصطناعي بشكل مكثف في تطوير MVP لمنصة تحليل بيانات. استخدمنا GitHub Copilot لكتابة الكود الأساسي، وChatGPT لتصميم قاعدة البيانات، وTabnine للمساعدة في كتابة الـ frontend. النتائج كانت مختلطة بشكل كبير. من ناحية، تمكنا من إطلاق النسخة الأولى في 6 أسابيع بدلاً من 3 أشهر المتوقعة. لكن من ناحية أخرى، واجهنا مشاكل كبيرة في الأداء والأمان.
أحد أكبر المشاكل التي واجهناها كانت في قاعدة البيانات. عندما طلبنا من ChatGPT تصميم قاعدة بيانات لـ "منصة تحليل بيانات"، أعطانا تصميماً يبدو منطقياً على الورق، لكنه كان كارثة في الواقع. مثلاً، وضع كل البيانات في جدول واحد ضخم بدلاً من تقسيمها إلى جداول متعددة، مما تسبب في بطء شديد عند الاستعلامات. كما أنه لم يضف أي فهارس على الأعمدة المستخدمة في الـ WHERE clauses، مما جعل الاستعلامات أبطأ بعشرات المرات مما كان يجب. عندما اكتشفنا المشكلة، اضطررنا لإعادة تصميم قاعدة البيانات بالكامل، مما أضاع أسبوعين من العمل.
-- تصميم قاعدة البيانات الذي اقترحه الذكاء الاصطناعي
CREATE TABLE data_analysis (
id INT PRIMARY KEY,
user_id INT,
report_type VARCHAR(50),
report_data JSON,
created_at TIMESTAMP,
updated_at TIMESTAMP,
-- 20 عمود آخر هنا
-- المشكلة: كل شيء في جدول واحد ضخم
);
-- التصميم المعدل للإنتاج
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(100) UNIQUE
);
CREATE TABLE reports (
id INT PRIMARY KEY,
user_id INT REFERENCES users(id),
report_type_id INT REFERENCES report_types(id),
created_at TIMESTAMP,
updated_at TIMESTAMP
);
CREATE TABLE report_data (
id INT PRIMARY KEY,
report_id INT REFERENCES reports(id),
data_key VARCHAR(50),
data_value JSONB
);
-- إضافة فهارس للأعمدة المستخدمة في الاستعلامات
CREATE INDEX idx_reports_user_id ON reports(user_id);
CREATE INDEX idx_report_data_report_id ON report_data(report_id);أكبر فخ يقع فيه المطورون هو الثقة العمياء في الكود الذي ينتجه الذكاء الاصطناعي. في إحدى المرات، طلبت من أحد المطورين الجدد في الفريق كتابة دالة لتحويل التواريخ بين المناطق الزمنية. استخدم Copilot وكتب دالة تبدو مثالية، لكنها كانت تستخدم مكتبة moment.js التي أصبحت deprecated منذ سنوات. المشكلة أن المطور لم يراجع الكود بدقة لأنه كان "يعمل" على بياناته البسيطة. عندما قمنا بتشغيل الكود على بيانات حقيقية، بدأنا نرى أخطاء غريبة في التواريخ بسبب مشاكل في معالجة المناطق الزمنية المعقدة.
فخ آخر هو تجاهل الـ edge cases. الذكاء الاصطناعي جيد في كتابة الكود للسعادة Cases، لكنه ضعيف جداً في التعامل مع الحالات الهامشية. مثلاً، عندما طلبنا منه كتابة دالة لحساب متوسط درجات الطلاب، كتب كوداً مثالياً للعمل على مصفوفة تحتوي أرقاماً صحيحة. لكن عندما أعطيناه مصفوفة تحتوي قيم null أو strings، بدأ الكود في إلقاء أخطاء غريبة. في بيئة الإنتاج، هذه الأخطاء يمكن أن تسبب مشاكل كبيرة، خاصة إذا كان الكود يتعامل مع بيانات حساسة مثل الدرجات المالية أو الطبية.
السر في استخدام الذكاء الاصطناعي بكفاءة هو معاملته كمساعد ذكي، وليس كمطور بديل. في تجربتي، أفضل طريقة هي استخدامه في المهام التي يكون فيها جيداً، وتجنب الاعتماد عليه في المهام التي يفشل فيها. مثلاً، استخدمه لكتابة الـ boilerplate code أو الـ documentation، لكن لا تعتمد عليه في كتابة الـ business logic المعقدة. كما يجب دائماً مراجعة الكود الذي ينتجه بدقة، خاصة في النقاط التي ذكرناها سابقاً: معالجة الأخطاء، التعامل مع البيانات غير المتوقعة، والأداء.
أحد الأساليب الفعالة التي استخدمناها في الفريق هو تقسيم المهام إلى أجزاء صغيرة واستخدام الذكاء الاصطناعي لكل جزء على حدة. مثلاً، بدلاً من طلب كتابة دالة كاملة، نطلب منه كتابة الجزء المتعلق بالحسابات، ثم الجزء المتعلق بمعالجة الأخطاء، وهكذا. هذا الأسلوب يقلل من فرص الوقوع في الأخطاء الكبيرة، ويسهل عملية المراجعة. كما أننا نطلب منه دائماً شرح الكود الذي ينتجه، مما يساعدنا على فهم المنطق وراءه والتأكد من أنه مناسب للمهمة.
// مثال على استخدام الذكاء الاصطناعي بكفاءة
// بدلاً من طلب دالة كاملة، نطلب أجزاء صغيرة ونراجع كل جزء
// الجزء الأول: الحساب الأساسي (مراجعة سريعة)
function calculateAverage(numbers) {
if (!Array.isArray(numbers)) {
throw new Error("Input must be an array");
}
const sum = numbers.reduce((acc, num) => acc + num, 0);
return sum / numbers.length;
}
// الجزء الثاني: معالجة الأخطاء (مراجعة دقيقة)
function calculateAverageSafe(numbers) {
if (!Array.isArray(numbers)) {
throw new TypeError("Input must be an array");
}
if (numbers.length === 0) {
throw new Error("Array cannot be empty");
}
const validNumbers = numbers.filter(num => typeof num === 'number' && !isNaN(num));
if (validNumbers.length === 0) {
throw new Error("Array must contain at least one valid number");
}
const sum = validNumbers.reduce((acc, num) => acc + num, 0);
return sum / validNumbers.length;
}
// الجزء الثالث: تحسين الأداء (مراجعة للأداء)
function calculateAverageOptimized(numbers) {
if (!Array.isArray(numbers)) {
throw new TypeError("Input must be an array");
}
let sum = 0;
let count = 0;
for (const num of numbers) {
if (typeof num === 'number' && !isNaN(num)) {
sum += num;
count++;
}
}
if (count === 0) {
throw new Error("Array must contain at least one valid number");
}
return sum / count;
}الذكاء الاصطناعي أداة قوية، لكنه ليس بديلاً عن التفكير الهندسي العميق. استخدمه لتسريع عملك، لكن لا تعتمد عليه في اتخاذ القرارات البرمجية الحرجة. دائماً افحص الكود الذي ينتجه بدقة، خاصة في النقاط التي ذكرناها: معالجة الأخطاء، الأداء، الأمان، والتعامل مع البيانات غير المتوقعة. تذكر أن الكود الجيد ليس مجرد كود يعمل — إنه كود يفهم السياق، ويتعامل مع الاستثناءات، ويؤدي وظيفته بكفاءة في بيئة الإنتاج الحقيقية. إذا اتبعت هذه القاعدة، ستستفيد كثيراً من الذكاء الاصطناعي دون أن تقع في الفخاخ التي يقع فيها الكثيرون.
الخطوة التالية؟ جرب بنفسك. خذ مهمة برمجية صغيرة، اطلب من الذكاء الاصطناعي كتابتها، ثم افحص الكود بدقة. ابحث عن الأخطاء التي ذكرناها، وحاول تحسين الكود لجعله جاهزاً للإنتاج. هذه هي أفضل طريقة لتعلم الفرق بين الكود الذي يبدو جيداً والكود الذي هو جيد حقاً.