اختبار الجاهزية للإنتاج
Production Readiness Quiz
اختبار الجاهزية للإنتاج — Production Readiness Quiz
وصلت للاختبار الختامي للفصل الأخير. هذه التحديات لا تختبر الحفظ — تختبر الفهم. هل تعرف متى تستخدم كل أداة؟ هل تستطيع كتابة كود async صحيح؟ هل تفهم لماذا يفشل threading في مهام CPU-bound؟
اقرأ كل تحدٍ بعناية قبل الكتابة. أخطاء مشتركة ستراها في هذه التحديات هي نفس الأخطاء التي يرتكبها المطورون في بيئات الإنتاج الحقيقية.
التحدي الأول: async صحيح أم خاطئ؟
في هذا التحدي ستكتب دالة async تُشغّل ثلاث مهام بالتوازي وتجمع نتائجها. المطلوب هو استخدام asyncio.gather بشكل صحيح.
تذكر: asyncio.gather تُشغّل كل coroutines في نفس الوقت وتُعيد قائمة بنتائجها بنفس ترتيب المدخلات — حتى لو انتهت بترتيب مختلف.
التحدي الثاني: اختيار الأداة الصحيحة
أحد أهم قرارات هندسة الأداء: هل أستخدم asyncio أم threading أم multiprocessing؟
في هذا التحدي ستُطبّق قاعدة الاختيار: I/O-bound وغير متزامن → asyncio؛ I/O-bound ومكتبة قديمة → threading؛ CPU-bound → multiprocessing.
لماذا يهم هذا القرار؟ الخيار الخاطئ لا يُحسّن الأداء — بل قد يُبطّئه. threading على مهمة CPU-bound تجعل الخيوط تتنافس على GIL وتُبطئ بعضها.
التحدي الثالث: إعداد بيئي آمن
أحد أكثر أسباب اختراق التطبيقات شيوعاً هو تضمين الأسرار في الكود. في هذا التحدي ستكتب كلاس إعداد يقرأ من متغيرات البيئة ويُقدّم واجهة واضحة لبقية التطبيق.
لماذا كلاس وليس مجرد متغيرات؟ الكلاس يُعطيك:
- مكاناً واحداً لقراءة كل الإعداد (Single Responsibility)
- قيماً افتراضية صريحة
- التحقق من صحة الإعداد عند بدء التطبيق
- قابلية الاختبار (يمكن تمرير قيم مختلفة للاختبارات)
التحدي الرابع: كشف أخطاء async
بعض الأخطاء الأكثر صعوبة في asyncio هي تلك التي لا تُسبّب crash واضح — تجعل البرنامج يعمل لكن ببطء أو بشكل غير صحيح.
في هذا التحدي ستقرأ كوداً به مشكلة وتُصلحه. المشكلة: asyncio.sleep يُعيد coroutine — لا ينتهي وحده دون await.
الخطأ الشائع: نسيان await قبل asyncio.sleep يعني أن البرنامج لا ينتظر فعلاً — ينتقل للسطر التالي فوراً. هذا يُفسد منطق الانتظار بالكامل.
التحدي الخامس: requirements.txt وجاهزية الإنتاج
قبل النشر، يجب التحقق من اكتمال الإعداد. دالة الفحص (health check) هي أول ما يُنفَّذ عند بدء التطبيق — تتحقق من وجود كل المتطلبات قبل قبول أي طلب.
في هذا التحدي ستكتب دالة تُولّد محتوى requirements.txt ثم تتحقق من الجاهزية.
لماذا إصدارات محددة؟ flask>=3.0 قد يثبّت أي إصدار مستقبلي يكسر كودك. flask==3.0.2 يضمن أن الإنتاج يشغّل نفس ما اختبرته. هذا ما يعنيه “إنتاج موثوق”.
مراجعة المفاهيم
قبل الخلاصة، اختبر القرارات الهندسية نفسها — اختيار الأداة وفهم الخطأ الصامت هما ما يفصل كود الإنتاج عن كود التجارب. أجب قبل أن تنظر إلى الشرح.
multiprocessing ينشئ عمليات مستقلة لكل منها مفسّرها وGIL خاص بها، فتعمل الأنوية فعلاً بالتوازي. أما asyncio وthreading فمكانهما مهام I/O حيث الانتظار هو العبء لا الحساب.await يُنشئ كائن coroutine ولا يشغّله — البرنامج ينتقل للسطر التالي فوراً وكأن الانتظار لم يكن. لا crash ولا رسالة خطأ واضحة (فقط تحذير RuntimeWarning قد لا تلاحظه) — منطق التوقيت كله يفسد بصمت. هذا من أصعب أخطاء asyncio اكتشافاً.flask==3.0.2 يضمن أن الإنتاج يشغّل الإصدار نفسه الذي اختبرته حرفياً. أما >= فيسمح بأي إصدار مستقبلي — وقد يحمل تغييرات كاسرة تصل إنتاجك قبل أن تراها في التطوير. قابلية إعادة البناء (reproducibility) شرط للنشر الموثوق.استرجع الآن الأسماء نفسها من ذاكرتك — هي التي ستكتبها في أول ملف async حقيقي.
asyncio.gather(a(), b(), c()) تشغّل الـ coroutines معاً وتُعيد نتائجها بترتيب المدخلات مهما اختلف ترتيب انتهائها — وهذا ما جعل ناتج التحدي الأول [10, 20, 30] مستقراً.time.sleep استدعاء blocking يجمّد الخيط كله — وفي asyncio الخيط الواحد هو كل شيء، فتتوقف معه كل المهام المتزامنة. داخل الكود غير المتزامن استخدم await asyncio.sleep() التي تُعلّق المهمة الحالية وحدها وتترك الحلقة تخدم البقية.خلاصة الفصل — ما تعلّمته
وصلت للنهاية. إليك خلاصة ما يُمكّنك الآن من فعله:
asyncio: تعرف أن async def تُعرّف coroutine، وawait تُعلّق المهمة الحالية. تعرف أن asyncio.gather يُشغّل مهام I/O-bound بالتوازي في خيط واحد. تعرف أن استخدام time.sleep بدلاً من asyncio.sleep يُجمّد الخيط كله.
threading vs multiprocessing: تعرف أن GIL يمنع تعدد أنوية حقيقية في خيوط Python. تعرف أن threading مفيد للمهام I/O-bound التي تستخدم مكتبات blocking. تعرف أن multiprocessing هو الخيار الوحيد للمهام CPU-bound التي تحتاج أنوية متعددة.
الإنتاج: تعرف كيف تُعرّف الإعداد في متغيرات البيئة لا في الكود. تعرف بناء Dockerfile بسيط لتطبيق Python. تعرف استخدام gunicorn بعمال متعددة بدلاً من خادم التطوير.
مبروك على إتمام مسار Python كاملاً في AzLearn.