labZero:~$ cd ./notes / note-null-db-semantic-me...

الملاحظات
نسخة صفر 4 يونيو 2026

null في قاعدة البيانات: إهمال في التصميم أم قرار معماري مقصود؟

عمود nullable كان يعني شيئاً مختلفاً لكل مطوّر في الفريق — الغموض في المعنى أنتج queries تفحص الحالة بطرق متضاربة.

#Architecture #MySQL #Database

في مشروع مشترك لإدارة طلبات التوريد، وجدت عمود approved_at بنوع TIMESTAMP وnullable. ثلاثة مطوّرين مختلفون كتبوا ثلاثة interpretations مختلفة: الأول يفحص != null ليعني «موافق عليه»، الثاني يفحص is null ليعني «معلق»، الثالث أضاف column منفصلة is_rejected لأنه اعتقد أن null تعني «لم يُنظر فيه بعد» وهو سيناريو مختلف عن «مرفوض».

الجوهر: الثلاثة كانوا محقين في سياقهم — المشكلة أن null حمل ثلاثة معانٍ في وقت واحد: «لم يصدر قرار بعد»، «لا يحتاج موافقة»، و«البيانات لم تُملأ تاريخياً». خلط المعاني الثلاثة في عمود واحد أنتج queries متضاربة وreports لا يُوثق بها. الحل لم يكن إزالة null بل توثيق معناها صراحةً: approved_at IS NULL + status = 'pending' يعني «ينتظر»، وapproved_at IS NULL + status = 'not_required' يعني «لا يحتاج». جعلت null تعني شيئاً واحداً فقط: «لم يُتخذ قرار بعد».

// تصريح صريح بدل التخمين
$query->whereNull('approved_at')
      ->where('status', ApprovalStatus::Pending);

الدرس الذي أحمله: null في قاعدة البيانات ليس «افتراضي آمن» — هو قرار دلالي يجب توثيقه في migration comment أو enum الحالة. كلما رأيت nullable column بلا تعليق يشرح ما تعنيه قيمة null، افترض أن الكود حولها يخمّن.

لديك مشكلة مشابهة؟

إذا واجهت موقفًا قريبًا من هذا في مشروعك، يمكننا الحديث عنه.

لنتحدّث عنها