فلسفة الكود
مصدر واحد للحقيقة
١٠ أكتوبر ٢٠٢٦ · 6 دقائق قراءة
اللي حصل
في واحد من أكتر المشاريع اللي اشتغلت عليها (بوت تليجرام فيه شوية أوامر، كل أمر محتاج صلاحية محددة)، اكتشفت إن فحص الصلاحية ده مكرر على كل أمر تقريبًا:
# play.py
if not (await check_perms(user_id, "play")):
return await c.reply("مش مخول")
# download.py
if not (await check_perms(user_id, "download")):
return await c.reply("مش مخول")
والصورة بتتصفّى: أي تعديل على طريقة الفحص (تغيير الرسالة، إضافة شرط، تغيير اسم الفانكشن) كان يتكرر في كل ملف على حدة. وبطبيعة الحال، كنت بأصلح الخطأ في عشرين مكان وأبقى ناسي أتنين، فيطلع المستخدم اللي فات أمره شايل الخطأ القديم.
القرار
بدل ما أستمر أعمل Replace All في كل مرة، وقفت وسألت سؤال بسيط: «مين هو صاحب الحقيقة هنا؟» الإجابة: الأمر مش فحص الصلاحية — الفحص هو اللي بيعرّف الأمر. يعني الصلاحية حاجة مشتركة بين كل الأوامر، فراح مكان واحد:
def processor(required: str):
def deco(func):
@wraps(func)
async def wrapper(event, c):
if not await check_perms(event.sender_id, required):
return await c.reply("مش مخول")
return await func(event, c)
return wrapper
return deco
وده بالظبط مبدأ مصدر واحد للحقيقة (Single Source of Truth): تعرّف القاعدة مرة واحدة، وخلّي كل ما يقرا منها.
المكاسب اللي لاحظتها فعليًا
- الأعطال بتتصلح من مكان واحد. أي باج في الفحص كانت بتتشال بشخطة واحدة، وبتختفي من كل الأوامر في نفس اللحظة.
- القرارات الجديدة بقت رخيصة. لاحقًا احتجت أضيف فحص على مستوى الاشتراك داخل نفس الفانكشن المركزي، والتعديل كله كان سطر واحد.
- الأوامر بقت أنحف. كل أمر بقى بيعرّف حاجته عبر ديكوريتور
@processor("play")، وقارئ الكود دلوقتي بيفهم من أول سطر: «ده أمر محتاج صلاحية play».
أول مرة المبدأ ده خانني
قلت في البداية إن ده مقال صريح بالعيوب، وعيب المبدأ ده اتظهر قدامي على شكلين:
الأول — المعالج المركزي للأخطاء. عملت معالج استثناءات واحد لكل الأوامر، وكان طبيعيًا لحد ما احتجت أميّز خطأً بعينه «يفضل في الهاندلر والمستخدم يكمّل» بدل ما يطلع للمستخدم عمومي. المعالج المركزي كان بيهضم الخطأ قبل ما أفكّر فيه. الحل: غيّرت إن الكود يرفع استثناءات محددة، والمركزي يمسك النوع بتاعه وياخد قراره من غير ما يمسك كل حاجة بـ broad.
التاني — المعالج المركزي مش دايماً عارف السياق. لما ظهرت الـ inline updates، طلع المعالج المركزي اللي بيمسك كل التحديثات مش عارف «الـ chat ده بتاع مين» لما مسك الاستعلام. واضطررت أعمل فحص شرطي مرة واحدة — في المكان الوحيد اللي كان بيتعرف فيه السياق ده.
الخلاصة
التمسك بمصدر واحد للحقيقة بمشروعية كبيرة، بس هي من التجربة، والقاعدة نفسها قايلة: أي قرار واحد بتفرضه لازم يعيش في المكان اللي بيقدر يكون شايف كل سياق. حتى القاعدة دي، اللي هي «أي حاجة تتعرّف في مكان واحد»، محتاجة استثناء واضح ومصرح به بدل حاجز أعمى.