ذكريات “خميس الرفع”: قصة من الأرشيف
يا جماعة الخير، اسمحوا لي أرجع بالزمن شوي… زمان، قبل ما تصير مفاهيم الـ DevOps والـ CI/CD منتشرة زي اليوم، كان يوم الخميس عنا في الشركة إلو رهبة خاصة. كنا نسميه “خميس الرفع” أو “Deployment Day”. كان يوم أشبه بالكابوس، يوم طويل ومتعب ومليان توتر.
أنا أبو عمر، وبذكر منيح كيف كنت أقضي يوم الخميس كاملًا وأنا أحضّر لنشر تحديثات الأسبوع على الخوادم (Servers). القصة كانت تبدأ صباحًا، أجمع كل التغييرات من زملائي المطورين، وأعمل “Merge” للكود يدويًا على جهازي. وبعدها تبدأ رحلة العذاب: أشغل كل الاختبارات (Tests) محليًا، وأدعي ربنا ما يطلعلي إشي خربان. إذا كل شي مشي تمام، أبدأ عملية الـ “Build” اللي كانت تاخد وقتها. بعدين، أفتح برنامج FTP (الله لا يعيدها من أيام)، وأتصل بالخادم، وأبدأ أرفع الملفات واحد ورا التاني، وأنا قلبي على إيدي خايف أنسى ملف أو أرفع ملف في مكان غلط.
بعد ما يخلص الرفع، تيجي اللحظة الحاسمة: إعادة تشغيل الخادم. كنت آخذ نفس عميق وأضغط Enter، وبعدها تبدأ الدقائق اللي بتمر كأنها ساعات وأنا أتفقد الموقع وأتأكد إنه كل شي شغال. وفي كثير من الأحيان، ما كان يكون شغال! مرة نسيت أرفع ملف إعدادات (config file)، ومرة كان في اختلاف بين إصدار مكتبة على جهازي وعلى الخادم، ومرة الكود ببساطة ما اشتغل لسبب مجهول. وقتها كان يبدأ الجحيم الحقيقي: أدخل على الخادم عن طريق SSH وأبدأ أعدّل على الكود مباشرة في بيئة الإنتاج (Production)، والعميل على التلفون بسأل “شو صار؟ الموقع واقع!”. كان خميس طويل، غالبًا ما يمتد لساعات متأخرة من الليل، ويدمر بداية عطلة نهاية الأسبوع.
كانت عملية يدوية، مليئة بالأخطاء البشرية، ومصدرًا هائلاً للضغط النفسي. كنت أفكر بيني وبين حالي: “معقول ما في طريقة أحسن من هيك؟ لازم يكون في حل.”
ومن هنا بدأت رحلتي في البحث عن هذا الحل، الحل الذي حررني وحرر فريقي من كابوس يوم الخميس، وهو ما يُعرف اليوم بأنابيب التكامل والنشر المستمر أو الـ CI/CD Pipelines.
ما هي أنابيب CI/CD؟ ولماذا هي المنقذ؟
ببساطة شديدة، تخيل أن عملية نشر البرمجيات عبارة عن خط إنتاج في مصنع. بدلًا من أن يقوم شخص واحد بنقل المنتج من محطة لأخرى يدويًا، هناك حزام ناقل آلي يقوم بكل شيء بطريقة منظمة وسريعة ودقيقة. هذا الحزام الناقل هو تمامًا ما تفعله أنابيب CI/CD.
CI/CD هو اختصار لمصطلحين أساسيين:
- Continuous Integration (CI) – التكامل المستمر: هي عملية أتمتة دمج تغييرات الكود من عدة مطورين في مستودع مركزي واحد. بعد كل عملية دمج، يتم تشغيل عمليات البناء (Build) والاختبار (Test) بشكل تلقائي. الهدف هو اكتشاف المشاكل في وقت مبكر جدًا.
- Continuous Delivery/Deployment (CD) – التسليم/النشر المستمر: هي امتداد للتكامل المستمر. بعد أن ينجح الكود في مرحلة الـ CI، يتم نشره تلقائيًا على بيئات مختلفة (مثل بيئة الاختبار أو البيئة الحقيقية).
الفكرة كلها تتمحور حول الأتمتة. بدلًا من الخطوات اليدوية المجهدة التي كنت أقوم بها، يقوم “روبوت” (خادم الـ CI/CD) بكل هذا العمل الشاق بالنيابة عنا، وبشكل أسرع وأكثر دقة.
المرحلة الأولى: التكامل المستمر (Continuous Integration – CI)
هذه هي ضربة البداية. بمجرد ما يقوم أي مطور في الفريق بدفع (Push) الكود الجديد إلى المستودع (زي GitHub أو GitLab)، يبدأ الأكشن تلقائيًا. خطوات هذه المرحلة عادةً ما تكون:
- التحقق من الكود (Code Checkout): يقوم الخادم بسحب آخر نسخة من الكود الذي تم دفعه.
- البناء (Build): يقوم بتجميع الكود وتحويله إلى برنامج قابل للتشغيل. إذا فشلت هذه الخطوة (مثل وجود خطأ في الكود)، يتوقف كل شيء ويتم إرسال إشعار فوري للمطور. لا مزيد من “على جهازي شغال!”.
- الاختبار (Test): يقوم بتشغيل جميع أنواع الاختبارات الآلية التي كتبها الفريق (Unit Tests, Integration Tests). إذا فشل أي اختبار، تتوقف العملية. هذا يضمن أن الإضافة الجديدة لم تكسر أي شيء قديم.
- إنشاء الحزمة (Artifact Creation): إذا نجحت كل الخطوات السابقة، يتم تجميع التطبيق في “حزمة” أو “قطعة أثرية” (Artifact) جاهزة للنشر، مثل صورة Docker أو ملف JAR.
نصيحة من خبرة أبو عمر: أهم شيء في هذه المرحلة هو سرعة التغذية الراجعة (Feedback). زمان كنا نكتشف المشاكل بعد ساعات أو حتى أيام. الآن، بفضل الـ CI، يعرف المطور أن الكود الذي كتبه فيه مشكلة خلال دقائق معدودة من دفعه، وهذا يسهل عملية الإصلاح بشكل لا يصدق.
المرحلة الثانية: التسليم والنشر المستمر (Continuous Delivery/Deployment – CD)
بعد أن نتأكد من أن الكود سليم وجاهز من خلال مرحلة الـ CI، ننتقل إلى مرحلة توصيله للمستخدم. هنا يوجد فرق بسيط بين مصطلحين:
- التسليم المستمر (Continuous Delivery): يتم نشر الحزمة تلقائيًا إلى بيئة تشبه البيئة الحقيقية (تسمى Staging). لكن النشر على البيئة الحقيقية (Production) يتطلب موافقة يدوية (كبسة زر من مدير المشروع أو مسؤول الفريق). هذا يعطي طبقة إضافية من التحكم.
- النشر المستمر (Continuous Deployment): هذه هي المرحلة الأكثر تقدمًا. إذا نجحت كل الاختبارات في كل البيئات، يتم نشر الكود تلقائيًا إلى البيئة الحقيقية بدون أي تدخل بشري. هذا الخيار مناسب للفرق التي تمتلك ثقة عالية في عمليات الاختبار الخاصة بها.
الخطوات هنا تشمل نشر الحزمة على الخوادم، تشغيل اختبارات شاملة (End-to-End Tests) للتأكد من أن النظام بأكمله يعمل كما هو متوقع، ومن ثم إتاحة النسخة الجديدة للمستخدمين.
مثال عملي: بناء أنبوب CI/CD بسيط باستخدام GitHub Actions
حتى لا يكون الكلام نظريًا فقط، دعونا نأخذ مثالاً بسيطًا جدًا. لنفترض أن لدينا مشروع Node.js بسيط، ونريد إنشاء أنبوب CI يقوم بالبناء والاختبار تلقائيًا كلما قمنا بدفع الكود إلى فرع `main` على GitHub.
كل ما نحتاجه هو إنشاء ملف بامتداد `.yml` داخل مجلد `.github/workflows` في مشروعنا. لنسمه `ci.yml`.
# اسم الأنبوب (Pipeline)
name: Node.js CI
# متى يتم تشغيل هذا الأنبوب؟
# هنا، سيتم تشغيله عند كل عملية push على فرع main
on:
push:
branches: [ "main" ]
# الوظائف (Jobs) التي سيتم تنفيذها
jobs:
# اسم الوظيفة، يمكنك تسميتها كما تشاء
build-and-test:
# نوع الجهاز الافتراضي الذي ستعمل عليه الوظيفة
runs-on: ubuntu-latest
# الخطوات (Steps) التي سيتم تنفيذها بالترتيب
steps:
# 1. سحب الكود من المستودع إلى الجهاز الافتراضي
- name: Checkout code
uses: actions/checkout@v3
# 2. إعداد بيئة Node.js بالإصدار المطلوب
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
# استخدام الكاش لتسريع عملية تحميل الاعتماديات في المرات القادمة
cache: 'npm'
# 3. تحميل الاعتماديات (Dependencies) الخاصة بالمشروع
- name: Install dependencies
run: npm install
# 4. تشغيل الاختبارات الآلية
- name: Run tests
run: npm test
# 5. بناء المشروع (إذا كان يتطلب خطوة بناء)
# هذه الخطوة اختيارية وتعتمد على طبيعة مشروعك
- name: Build project
run: npm run build
# ... هنا يمكن إضافة خطوات النشر (Deployment) في مرحلة لاحقة
# - name: Deploy to server
# run: |
# echo "Deploying to production server..."
# # هنا تضع أوامر النشر مثل scp, rsync, أو استخدام أدوات سحابية
# ssh user@server 'cd /path/to/project && git pull && npm install && pm2 restart app'
بهذا الملف البسيط، قمنا بأتمتة أهم أجزاء عملية التكامل. الآن، في كل مرة يقوم فيها أي مطور بدفع كود جديد، ستقوم GitHub Actions بتنفيذ هذه الخطوات تلقائيًا. إذا فشلت أي خطوة، سيصلنا إشعار فوري. ودّعنا الأخطاء المفاجئة!
ليش لازم كل فريق يفكر بالـ CI/CD؟ (الفوائد من خبرتي)
بعد تطبيق هذه المنهجية، تغيرت حياتنا كفريق تطوير بشكل جذري. لم يعد يوم الخميس كابوسًا، بل أصبح يومًا عاديًا كأي يوم آخر. وهذه أهم الفوائد التي لمسناها على أرض الواقع:
- تقليل المخاطر بشكل هائل: الأتمتة تقضي على 99% من الأخطاء البشرية. اكتشاف الأخطاء في مرحلة مبكرة جدًا يجعل إصلاحها أسهل وأقل تكلفة.
- زيادة سرعة التسليم (Velocity): صرنا قادرين على نشر ميزات جديدة وإصلاحات للمستخدمين عدة مرات في اليوم الواحد إذا لزم الأمر، وبكل ثقة.
- تحسين جودة الكود: لأن الأنبوب يجبر الجميع على كتابة الاختبارات والتأكد من أن الكود “نظيف” وقابل للبناء، ارتفعت جودة الكود بشكل ملحوظ.
- راحة بال للمطورين: وهذا برأيي أهم مكسب. تحول التركيز من القلق والخوف من عملية النشر إلى الإبداع وحل المشاكل الحقيقية. المطور السعيد هو مطور منتج.
- شفافية أكبر: أصبح بإمكان أي شخص في الفريق، حتى مدير المشروع، أن يرى حالة أي تغيير، وهل نجح في الاختبارات، وهل تم نشره أم لا، كل ذلك من خلال واجهة بسيطة.
الخلاصة: من كابوس الخميس إلى إبداع مستمر 🧘
التحول إلى CI/CD لم يكن مجرد تغيير تقني، بل كان تغييرًا في الثقافة والعقلية. لقد حررنا من قيود العمل اليدوي المتكرر والممل، وسمح لنا بالتركيز على ما نحب: كتابة كود رائع وبناء منتجات مفيدة. لم نعد نخشى “يوم النشر”، بل أصبح النشر جزءًا طبيعيًا، آمنًا، ومستمرًا من عملنا اليومي.
نصيحتي الأخيرة لك: إذا كنت لا تزال تعاني من “كابوس يوم النشر”، فابدأ اليوم. لا تخف من ضخامة المفهوم. ابدأ بخطوات صغيرة وبسيطة. جرّب أن تؤتمت خطوة واحدة فقط، مثل خطوة بناء المشروع (Build) باستخدام GitHub Actions أو GitLab CI. عندما ترى بنفسك كيف توفر عليك هذه الخطوة الوقت والجهد، ستتحمس لإضافة خطوة الاختبار، ثم خطوة النشر، وهكذا. تذكر دائمًا، الشغلة مش سحر، الشغلة خطوات صغيرة ومستمرة بتعمل فرق كبير. بالتوفيق يا جماعة!