مؤشر الأداء الأحمر في كل Pull Request: كيف أوقفتُ تدهور سرعة الموقع بدمج k6 في GitHub Actions

يا جماعة الخير، السلام عليكم ورحمة الله.

اسمحوا لي أبدأ معكم بقصة صارت معي قبل فترة، قصة علّمتني درس قاسي عن “القاتل الصامت” للمواقع والتطبيقات. كنت شغال على مشروع كبير، منصة تجارة إلكترونية، والأمور كانت ماشية زي الحلاوة. كل أسبوعين بنضيف ميزات جديدة، والفريق كله مبسوط، والعميل راضي. لكن شوي شوي، بلشت توصلنا شكاوى مش واضحة: “الموقع بحسّه ثقيل”، “الصفحات بتطوّل لَتْحمّل”.

في البداية، كنا بنفكّر إنها مشكلة من عند المستخدم أو من سرعة الإنترنت عنده. لكن الشكاوى زادت، وصارت شبه يومية. في ليلة من الليالي، وأنا قاعد بقلّب في تقارير الأداء، انصدمت. متوسط سرعة تحميل الصفحة الرئيسية زاد بنسبة 300% خلال 6 شهور! مش بيوم وليلة، لأ، كان بيزيد شوي شوي، 5 ميلي ثانية هون، 10 ميلي ثانية هناك، مع كل تحديث وكل ميزة جديدة. زي اللي وزنه بيزيد كيلو كل شهر، ما بحس على حاله إلا لما يلاقي أواعيه بطلت تسكّر عليه. وقتها أدركت إننا كنا بنضيف “ديون تقنية” في الأداء مع كل Pull Request بنعمله merge، وما كان في حدا يراقب أو يحاسب.

هذا الموقف كان نقطة تحول. قررت إنه لازم نلاقي طريقة نكشف فيها هاي المشاكل “قبل” ما تصير جزء من الكود الرئيسي. ومن هنا بدأت رحلتي مع مؤشر الأداء الأحمر في كل Pull Request.

لماذا يعتبر تدهور الأداء “القاتل الصامت”؟

على عكس الأخطاء البرمجية (Bugs) اللي بتسبب توقف التطبيق فجأة، تدهور الأداء مشكلة خبيثة ومتسللة. هي لا تظهر كخطأ 500 Internal Server Error واضح، بل تتجلى في:

  • زيادة طفيفة في زمن الاستجابة: كل عملية دمج كود (merge) قد تضيف 10-20 ميلي ثانية. لوحدها، لا تكاد تُلاحظ. لكن بعد 50 عملية دمج، يصبح لديك ثانية كاملة من التأخير الإضافي.
  • استهلاك أعلى للموارد: الكود الأقل كفاءة يستهلك ذاكرة ومعالجاً أكثر، مما يرفع تكاليف الاستضافة ويجعل التطبيق أبطأ تحت الضغط.
  • تجربة مستخدم سيئة: المستخدمون لا يصبرون. أبحاث جوجل تظهر أن احتمالية مغادرة المستخدم للموقع تزيد بنسبة 32% إذا زاد وقت التحميل من ثانية إلى 3 ثوانٍ.

المشكلة أننا كمطورين، نركز على أن الميزة “تعمل” وظيفياً، وننسى كيف “تعمل” من ناحية أداء. الحل ليس في جلسات تحسين أداء ماراثونية كل ستة أشهر، بل في دمج ثقافة مراقبة الأداء في صلب عملنا اليومي.

الحل: اختبارات الأداء الاستباقية مع كل تغيير

الفكرة بسيطة: مثلما لدينا اختبارات الوحدات (Unit Tests) واختبارات التكامل (Integration Tests) التي تعمل تلقائياً لتضمن صحة الكود، لماذا لا يكون لدينا اختبارات أداء تلقائية لتضمن سرعة الكود؟

هنا يأتي دور دمج اختبارات الأداء في مسار التكامل والنشر المستمر (CI/CD). الهدف هو أن يفشل بناء الـ Pull Request (PR) ليس فقط بسبب خطأ في الكود، ولكن أيضاً إذا تسبب في تدهور ملحوظ في الأداء. هذا هو “مؤشر الأداء الأحمر” الذي نصبو إليه.

لماذا اخترت k6؟

في عالم اختبارات الأداء، الأدوات كثيرة مثل Apache JMeter و Gatling وغيرها. لكن اختياري وقع على k6 لعدة أسباب جوهرية، خصوصاً في سياق الأتمتة والـ CI/CD:

  • سهولة الاستخدام والكتابة: تُكتب اختبارات k6 بلغة JavaScript (ES2015/ES6). هذا يعني أن معظم مطوري الويب يمكنهم البدء بكتابة الاختبارات بسرعة دون الحاجة لتعلم لغة جديدة أو التعامل مع واجهات رسومية معقدة.
  • أداء عالي: k6 مكتوبة بلغة Go، وهي مصممة لتكون خفيفة على الموارد وقادرة على توليد ضغط كبير من جهاز واحد.
  • صديقة للمطورين والأتمتة (Developer & Automation Friendly): كل شيء يتم عبر الكود وسطر الأوامر، مما يجعلها مثالية للاندماج مع أنظمة الـ CI/CD مثل GitHub Actions.
  • الـ Thresholds (عتبات الأداء): هذه هي الميزة القاتلة. يمكنك تعريف معايير نجاح أو فشل للاختبار مباشرة في السكربت. مثلاً: “يجب أن يفشل الاختبار إذا كان 95% من الطلبات أبطأ من 200 ميلي ثانية”. هذا هو أساس مؤشرنا الأحمر.

التطبيق العملي: دمج k6 مع GitHub Actions خطوة بخطوة

خلونا ندخل في “الزبدة” ونشوف كيف نطبق هذا الكلام عملياً. سنقوم ببناء نظام بسيط يقوم بتشغيل اختبار أداء على كل Pull Request يستهدف الـ branch الرئيسي (main).

الخطوة الأولى: كتابة سكربت اختبار k6

أولاً، نحتاج إلى سكربت يختبر جزءاً حساساً من تطبيقنا. لنفترض أن لدينا نقطة نهاية (endpoint) مهمة مثل /api/products. سننشئ ملفاً جديداً في مشروعنا، مثلاً tests/performance/smoke-test.js.


import http from 'k6/http';
import { check, sleep } from 'k6';

// Options تحدد سلوك الاختبار
export const options = {
  vus: 5, // 5 مستخدمين افتراضيين
  duration: '30s', // لمدة 30 ثانية
  thresholds: {
    // تعريف عتبات الأداء (هنا يكمن السر)
    http_req_failed: ['rate<0.01'], // نسبة الطلبات الفاشلة يجب أن تكون أقل من 1%
    http_req_duration: ['p(95) r.status == 200,
    'transaction time OK': (r) => r.timings.duration < 500,
  });

  sleep(1); // انتظار ثانية بين كل طلب وآخر للمستخدم الافتراضي
}

شرح الكود:

  • vus و duration: يحددان حجم الضغط. في اختبارات الـ PR، لا نحتاج لضغط هائل، بل “اختبار دخان” (Smoke Test) سريع للتأكد من عدم وجود تدهور كبير.
  • thresholds: هذا هو قلب النظام. هنا نضع شروط النجاح. إذا لم تتحقق هذه الشروط، سيخرج k6 برمز خطأ (non-zero exit code)، مما يؤدي إلى فشل خطوة الـ GitHub Action.

الخطوة الثانية: إعداد GitHub Actions Workflow

الآن، سنطلب من GitHub تشغيل هذا السكربت تلقائياً. أنشئ ملفاً جديداً في مسار .github/workflows/performance-test.yml.


name: Performance Test on PR

on:
  pull_request:
    branches:
      - main # أو master حسب اسم الـ branch الرئيسي عندك

jobs:
  k6_performance_test:
    name: k6 Performance Test
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      # هذه الخطوة مهمة إذا كان تطبيقك يحتاج للبناء والتشغيل
      # مثال لتطبيق Node.js
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '18'
      
      - name: Install dependencies and build
        run: |
          npm install
          npm run build
      
      - name: Run application in background
        run: npm start & # علامة & لتشغيل الأمر في الخلفية

      - name: Wait for server to be ready
        run: sleep 10 # انتظر قليلاً ليتسنى للتطبيق البدء

      - name: Run k6 test
        uses: grafana/k6-action@v0.2.0
        with:
          # استبدل الرابط بالرابط المحلي لتطبيقك الذي يعمل في الـ runner
          # عادة يكون http://localhost:PORT
          script: k6 run --env APP_HOSTNAME=http://localhost:3000 tests/performance/smoke-test.js

لاحظ أننا نحتاج لتعديل سكربت k6 قليلاً ليقرأ الرابط من متغيرات البيئة (environment variables) ليكون أكثر مرونة.

تعديل smoke-test.js:


// ... الكود السابق
const API_URL = __ENV.APP_HOSTNAME || 'https://your-app-url.com';

export default function () {
  const res = http.get(`${API_URL}/api/products`);
  // ... باقي الكود
}

الآن، مع كل Pull Request جديد، سيقوم GitHub بتشغيل تطبيقك في بيئة معزولة، ثم يوجه k6 ليقوم باختبار الأداء عليه. إذا تجاوزت أزمنة الاستجابة العتبة التي حددتها (250ms في مثالنا)، ستفشل المهمة، وسيظهر مؤشر أحمر بجانب الـ Pull Request. ✅

الخطوة الثالثة: التحليل والتصرف

عندما ترى ذلك المؤشر الأحمر، هذا يعني أن التغييرات التي قمت بها أثرت سلباً على الأداء. الآن يمكنك:

  1. فتح تقرير GitHub Action: ستجد مخرجات k6 التفصيلية التي توضح أي عتبة (threshold) تم تجاوزها بالضبط.
  2. تحليل الكود: هل أضفت استعلام قاعدة بيانات غير فعال؟ هل هناك حلقة (loop) تستهلك وقتاً طويلاً؟
  3. إصلاح المشكلة: قم بتحسين الكود، وادفع (push) التغييرات الجديدة. الـ workflow سيعمل مرة أخرى، ونأمل أن ترى المؤشر الأخضر هذه المرة.

نصائح من خبرة أبو عمر 🧔

  • ابدأ صغيراً: لا تحاول اختبار كل شيء من اليوم الأول. ابدأ بنقطة نهاية واحدة أو اثنتين من الأكثر أهمية أو استخداماً في تطبيقك. ثم توسع تدريجياً.
  • كن واقعياً في عتباتك (Thresholds): لا تضع أهدافاً مستحيلة. ابدأ بقياس الأداء الحالي، ثم ضع عتبة أعلى بقليل (مثلاً 10-20%). الهدف هو منع التدهور، وليس الوصول للكمال فوراً. زي ما بنحكي، “ما بدنا نكون ملكيين أكثر من الملك”.
  • البيئة تلعب دوراً: أداء التطبيق في GitHub runner قد يختلف عن بيئة الإنتاج. الهدف هنا ليس قياس الأرقام المطلقة، بل “مقارنة” الأداء قبل وبعد التغيير. المهم هو اكتشاف التدهور النسبي.
  • استخدم تعليقات الـ PR: هناك أدوات متقدمة يمكنها نشر ملخص لنتائج k6 كتعليق على الـ Pull Request مباشرة. هذا يجعل مراجعة تأثير الأداء أسهل بكثير للفريق بأكمله.

الخلاصة 🚀

إن دمج اختبارات الأداء في دورتك اليومية ليس ترفاً، بل هو ضرورة للحفاظ على جودة المنتج ورضا المستخدمين على المدى الطويل. لقد حوّلنا مشكلة “الأداء” من مهمة ضخمة ومخيفة نقوم بها مرة كل عدة أشهر، إلى فحص روتيني وسريع يحدث عشرات المرات في اليوم.

باستخدام أدوات بسيطة وقوية مثل k6 و GitHub Actions، يمكنك بناء شبكة أمان تكتشف التدهور في الأداء وهو لا يزال فكرة في Pull Request، قبل أن يراه مستخدم واحد. لا تنتظر حتى يخبرك عملاؤك أن موقعك بطيء، اجعل الكود يخبرك بذلك بنفسه أولاً بأول.

أتمنى أن تكون هذه التجربة مفيدة لكم. بالتوفيق في مشاريعكم!

أبو عمر

سجل دخولك لعمل نقاش تفاعلي

كافة المحادثات خاصة ولا يتم عرضها على الموقع نهائياً

آراء من النقاشات

لا توجد آراء منشورة بعد. كن أول من يشارك رأيه!

آخر المدونات

التوظيف وبناء الهوية التقنية

سيرتي الذاتية عبرت فلتر الـ ATS لكنها فشلت أمام المدير التقني: كيف أعدت بناءها لتتحدث لغة المهندسين؟

من واقع تجربة شخصية، أسرد لك كيف تحوّل سيرتك الذاتية من مجرد قائمة مهارات يتجاهلها المديرون التقنيون إلى قصة إنجازات مُقنعة تفتح لك أبواب المقابلات....

28 فبراير، 2026 قراءة المزيد
التوسع والأداء العالي والأحمال

خدمة واحدة فاشلة كادت أن تسقط النظام بأكمله: كيف أنقذني نمط ‘قاطع الدائرة’ (Circuit Breaker) من كارثة متتالية؟

أتذكر ذلك اليوم جيداً، حين كادت خدمة واحدة أن تتسبب في انهيار نظامنا بالكامل في ليلة نهاية أسبوع مزدحمة. في هذه المقالة، أشارككم قصة حقيقية...

27 فبراير، 2026 قراءة المزيد
اختبارات الاداء والجودة

لقد ‘هاجمت’ تطبيقي بنفسي عمداً: كيف كشفت لي ‘هندسة الفوضى’ نقاط الضعف التي لم تظهرها الاختبارات التقليدية

أشارككم قصة حقيقية حول إطلاق فاشل كاد أن يدمر سمعتنا، وكيف قادتنا هذه التجربة المريرة إلى تبني "هندسة الفوضى" (Chaos Engineering). اكتشفوا معنا كيف يمكن...

26 فبراير، 2026 قراءة المزيد
التوسع والأداء العالي والأحمال

عاصفة من الطلبات كادت أن تغرق تطبيقي: كيف أنقذتني طوابير الرسائل (Message Queues) من كارثة الجمعة السوداء؟

أشارككم قصة حقيقية من قلب المعركة في يوم الجمعة السوداء، وكيف تحولت كارثة محققة في أداء تطبيقي إلى نجاح باهر بفضل مفهوم بسيط وقوي اسمه...

24 فبراير، 2026 قراءة المزيد
البودكاست