في المقال اللي فات، لاحظنا حاجة من غير ما نتوقف عندها كتير: كل ما تعمل push، Vercel وRailway بينشروا نسخة جديدة تلقائيًا. ده شكل بسيط جدًا من فكرة أكبر بكتير اسمها DevOps، ومعظم الناس بتسمع عنها كأوامر YAML بتتنسخ من مقال لمقال من غير ما تفهم ليه أصلاً بنعملها. في المقال ده هناخد خطوة للخلف، نفهم الفلسفة الأول، وبعدين نطبقها على مشروع الميرن ستاك بتاعنا.
المحتويات
- أولاً: DevOps إيه، ومش بس أدوات
- ثانياً: Continuous Integration ومشكلة “جهنم الدمج”
- ثالثاً: Delivery ولا Deployment؟ الفرق اللي بيتلخبط فيه الكل
- رابعاً: أول Workflow بـ GitHub Actions
- خامساً: الاختبارات كبوابة، مش كخطوة زيادة
- سادساً: مبدأ Fail Fast وليه بيغير طريقة تفكيرك
- سابعاً: أخطاء شائعة، تقنية وفكرية
- ثامناً: خطوة قبل المراقبة
أولاً: DevOps إيه، ومش بس أدوات
الغلطة الأشهر: الناس بتفتكر DevOps هو اسم تاني لأداة زي Docker أو GitHub Actions. ده مش صح. DevOps أصلاً كلمة مدمجة من Development وOperations، وهي ثقافة عمل قبل ما تكون أدوات: بدل ما يكون فيه فريق بيكتب الكود وفريق تاني منفصل تمامًا بيشغله على السيرفرات (وكل واحد بيلوم التاني لما حاجة تعطل)، الفكرة إن نفس الفريق بيتحمل مسؤولية الكود من أول سطر لحد ما يشتغل في الإنتاج.
الأدوات (زي Docker اللي بنيناه، وGitHub Actions اللي هنبنيه دلوقتي) هي الوسيلة اللي بتخلي الثقافة دي ممكنة عمليًا، مش الثقافة نفسها. لو فريق عنده كل الأدوات دي بس لسه فاكر إن “شغلي خلص لما الكود يشتغل عندي”، هو مش بيمارس DevOps فعليًا، بس بيستخدم أدواته.
ليه المفهوم ده مهم قبل ما نكتب أي سطر YAML؟ لأن الـ CI/CD اللي هنبنيه النهاردة هو انعكاس مباشر للثقافة دي: أتمتة مسؤوليات كانت زمان موزعة على أشخاص مختلفين بيدوها لبعض، ودمجها في خط واحد بيمشي من غير ما حد ينتظر حد.
ثانياً: Continuous Integration ومشكلة “جهنم الدمج”
تخيل فريق فيه 4 مبرمجين، كل واحد شغال على جزء من مشروع الميرن ستاك بتاعنا لوحده لمدة أسبوعين كاملين من غير ما يدمج كوده مع الباقي. آخر يوم، الكل بيحاول يدمج فروعه مع بعض، ويكتشف إن التعديلات بتتصادم في كل مكان: واحد غيّر شكل الرد من الـ API، وواحد تاني كان بيعتمد على الشكل القديم في الفرونت إند. الظاهرة دي اسمها “جهنم الدمج” (Merge Hell)، وكل ما الفترة بين الدمجات تطول، كل ما الجحيم يكبر.
Continuous Integration (اختصارها CI) هو الحل: كل مبرمج بيدمج كوده مع الفرع الرئيسي كذا مرة في اليوم، مش مرة كل أسبوعين. وكل مرة دمج، نظام آلي بيشغل الاختبارات فورًا ويقولك على طول لو حاجة اتكسرت. المشاكل بتتكشف وهي صغيرة (تعديل سطرين) بدل ما تتراكم لأسابيع وتبقى مستحيلة التتبع. الكلمة المفتاحية هنا هي “Continuous“: مش دمج كبير مرة، دمج صغير باستمرار.
ثالثاً: Delivery ولا Deployment؟ الفرق اللي بيتلخبط فيه الكل
الحرف التاني في CD بيقصد بيه حاجتين مختلفتين، والناس بتستخدمهم كأنهم نفس الحاجة رغم إن الفرق بينهم جوهري.
Continuous Delivery: الكود بعد ما يعدي الاختبارات، بيبقى جاهز للنشر في أي لحظة، لكن حد لازم يدوس زرار يوافق على النشر فعليًا. فيه بوابة بشرية أخيرة قبل ما أي حاجة توصل للمستخدمين.
Continuous Deployment: مفيش زرار خالص. لو الكود عدى كل الاختبارات، بينشر تلقائيًا للإنتاج من غير أي تدخل بشري. ده بالظبط اللي بيحصل دلوقتي مع Vercel وRailway في مشروعنا، وده سبب حقيقي للانتباه: مفيش حد بيراجع قبل ما الكود يوصل للمستخدمين، فالاختبارات بقت هي خط الدفاع الوحيد.
الفرق ده مش تفصيلة أكاديمية، هو قرار حقيقي بتاخده عن مشروعك: مشروع فيه بيانات حساسة أو قرار نشره خطير، غالبًا محتاج Delivery (بوابة بشرية)، ومشروع صغير أو تعليمي زي بتاعنا يقدر يستحمل Deployment الكامل.
رابعاً: أول Workflow بـ GitHub Actions
دلوقتي المفاهيم واضحة، خلينا نطبقها. GitHub Actions هو أداة الأتمتة المدمجة في GitHub نفسه، بتشتغل بملف YAML جوه مجلد .github/workflows/ في مستودعك.
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
لاحظ الجزء on: ده بيحدد إمتى الـ workflow يشتغل. حددناه على كل push أو pull request لفرع main. ده تطبيق مباشر لمبدأ الـ CI اللي شرحناه فوق: أي دمج، صغير كان أو كبير، بيتفحص فورًا.
خامساً: الاختبارات كبوابة، مش كخطوة زيادة
دلوقتي نضيف الجزء اللي بيحول الملف من “بيتصل بس” لـ “بيحمي فعليًا”: تشغيل الاختبارات، ومنع أي حاجة تكمل لو فشلوا. السطور دي بتتلزق تحت نفس steps: بتاعة الكود اللي فوق مباشرة، بعد خطوة setup-node، مش في ملف جديد.
- name: Install backend dependencies
run: npm install
working-directory: ./backend
- name: Run backend tests
run: npm test
working-directory: ./backend
- name: Install frontend dependencies
run: npm install
working-directory: ./frontend
- name: Run frontend tests
run: npm test -- --watchAll=false
working-directory: ./frontend
لو مش عندك اختبارات مكتوبة لسه، عندك مقال Jest وCypress اللي هيوريك تكتب إزاي. لحد دلوقتي، الخطوات دي بترجع علامة ✓ أو ✗ على أي pull request، بس المفاجأة إن GitHub بيسمحلك تدمج حتى لو العلامة ✗، إلا لو فعّلت إعداد منفصل. البوابة الحقيقية لسه ناقصة، وهنكملها في الفقرة اللي جاية.
عشان تحول العلامة من مجرد تنبيه لبوابة فعلية، روح لإعدادات المستودع: Settings ← Branches ← أضف قاعدة حماية لفرع main ← فعّل Require status checks to pass before merging، واختار الـ job اللي سميناه test. من دلوقتي، زرار الدمج نفسه هيبقى معطل لحد ما الاختبارات تعدي، مش مجرد رسالة تحذير بتقدر تتجاهلها.
سادساً: مبدأ Fail Fast وليه بيغير طريقة تفكيرك
فيه مبدأ أساسي في DevOps اسمه Fail Fast: لو حاجة هتفشل، الأفضل تفشل بسرعة وبوضوح، مش تتأخر وتظهر في مكان أخطر. رتب الخطوات في الـ workflow بالترتيب ده بالذات مش صدفة: تثبيت المكتبات الأول (أسرع خطوة)، بعدين الاختبارات (أبطأ شوية)، وده بيدي أسرع رد فعل ممكن لو حاجة غلط.
المبدأ ده بيتطبق برضو على القرارات اللي أخدناها في السلسلة كلها: فاكر ليه في مقال الـ JWT رجّعنا نفس رسالة الخطأ لو الإيميل أو الباسورد غلط، بدل ما نستنى ونكتشف المشكلة في خطوة بعيدة؟ نفس فلسفة الـ Fail Fast: اكتشف المشكلة في أقرب نقطة ممكنة، مش في آخر نقطة ممكنة.
تطبيق عملي تاني لنفس الفلسفة: كل مرة الـ workflow يشتغل، خطوة npm install بتنزل نفس المكتبات من الصفر، وده بياخد وقت من غير داعي. خاصية cache المدمجة في setup-node بتحل المشكلة دي بسطر واحد بس.
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
السطر ده بيتحط جوه خطوة setup-node اللي عملناها في قسم رابعاً بدل ما تكتبها من جديد. المرات الجاية، GitHub Actions هيرجع للمكتبات المحفوظة بدل ما ينزلها تاني، ورد الفعل اللي اتكلمنا عنه (اكتشاف المشكلة بسرعة) بيتحقق فعليًا لما كل دورة بتاخد ثواني أقل.
سابعاً: أخطاء شائعة، تقنية وفكرية
- نسيان working-directory في مشروع فيه فولدرين منفصلين (باك إند وفرونت إند)، فالأوامر بتتنفذ في المكان الغلط وتفشل بسبب غير حقيقي.
- الاعتماد الكامل على الأتمتة من غير ما تفهم إيه اللي بيحصل فيها، فلو الـ pipeline فشل، محدش يعرف يصلحه لأن محدش فاهمه.
- بناء pipeline معقد جدًا من أول يوم (اختبارات، وتحليل كود، ونشر مرحلي، وتنبيهات) قبل ما يبقى عندك حتى اختبار واحد حقيقي يستاهل التعقيد ده.
- الظن إن CI/CD بيغني عن مراجعة الكود بشريًا تمامًا، بينما هو أداة تكمل المراجعة البشرية مش تلغيها.
ثامناً: خطوة قبل المراقبة
دلوقتي عندك خط كامل بيمشي لوحده: كود بيتكتب، يتفحص، يتنشر، من غير ما تلمس زرار. بس فيه سؤال لسه من غيره إجابة: لو حاجة عطلت بعد ما وصلت للمستخدمين، إزاي هتعرف؟ الاختبارات بتكتشف المشاكل المتوقعة قبل النشر، لكن مش كل حاجة قابلة للتوقع. المقال الجاي، والأخير في السلسلة، هيغطي بالظبط الجزء ده: المراقبة والـ Logging في الإنتاج.
لو وصلت للنقطة دي في السلسلة، يبقى تقدر تشرح لحد تاني ليه بنعمل CI/CD أصلاً، مش بس تنسخله ملف YAML جاهز. لو عندك سؤال أو تجربة مختلفة، قولّي في التعليقات.
اكتشاف المزيد من كود التطور
اشترك للحصول على أحدث التدوينات المرسلة إلى بريدك الإلكتروني.
