تطبيقاتنا كانت تستجدي البيانات أو تغرق فيها: كيف أنقذنا GraphQL من جحيم الـ Over-fetching والـ Under-fetching؟

حكاية “صفحة المستخدم” التي كادت أن تُفشّل المشروع

يا جماعة الخير، السلام عليكم. معكم أخوكم أبو عمر.

قبل كم سنة، كنت شغال مع فريق على تطبيق اجتماعي جديد، تطبيق طموح وفيه ميزات كثيرة. وصلنا لمرحلة تطوير “صفحة المستخدم” (User Profile). للوهلة الأولى، المهمة تبدو بسيطة: عرض صورة المستخدم، اسمه، نبذة عنه، وآخر 5 منشورات كتبها. لكن هون بلشت المشاكل اللي “بتطلّع الشيب براس الواحد”.

فريق الواجهة الأمامية (Frontend) كان يصرخ: “يا أبو عمر، بدنا نعرض اسم المستخدم وصورته بس في الهيدر، ليش بنضطر نحمّل كل بياناته الشخصية من عنوانه لتاريخ ميلاده في طلب واحد؟ التطبيق بطيء على الإنترنت الضعيف!”. كانوا على حق، هذه المشكلة اسمها Over-fetching، أو “الجلب الزائد للبيانات”. كنا نغرقهم ببيانات لا يحتاجونها.

وبنفس الوقت، عشان يعرضوا آخر 5 منشورات، كانوا يبعثوا طلب يجيب بيانات المستخدم، وبعدها طلب ثاني يجيب قائمة ID المنشورات، وبعدها 5 طلبات منفصلة، طلب لكل منشور عشان يجيبوا تفاصيله! تخيلوا الكارثة؟ 7 طلبات شبكة (Network Requests) عشان نعرض صفحة واحدة! هذه المشكلة اسمها Under-fetching، أو “الجلب الناقص للبيانات”، اللي بتجبرك تعمل رحلات مكوكية للسيرفر. التطبيق كان يستجدي البيانات قطعة قطعة.

الوضع كان متأزم، اجتماعات طويلة، واللوم يترمى بين فريق الواجهة الخلفية (Backend) والواجهة الأمامية. إحنا كـ Backend نقول “اعملوا طلب واحد وخذوا اللي بدكم ياه”، وهم يقولوا “الطلب الواحد فيه جيجات من الداتا ما بدنا إياها!”. شعرنا أننا في جحيم تقني، إلى أن قررنا تجربة حل كان الكل يتكلم عنه وقتها: GraphQL.


ما هو جحيم الـ Over-fetching والـ Under-fetching؟

قبل ما نغطس في الحل، خلينا نفصّل المشكلة أكثر عشان تكون واضحة للجميع، خصوصًا للمبرمجين الجدد.

مشكلة الـ Over-fetching: عندما تغرق في البيانات

تخيل أنك ذهبت لمطعم لتطلب كوب ماء، فقام النادل بإحضار بوفيه كامل يتضمن كل ما في المطبخ، ووضع لك الفاتورة كاملة. هذا بالضبط هو الـ Over-fetching في عالم الـ APIs.

باستخدام REST API التقليدي، غالبًا ما يكون لديك نقاط وصول (Endpoints) ثابتة مثل /api/users/123. هذه النقطة قد تُرجع كائن JSON ضخمًا:


{
  "id": 123,
  "name": "أبو عمر",
  "username": "abu_omar_dev",
  "email": "abu.omar@example.com",
  "address": {
    "street": "شارع القدس",
    "city": "نابلس",
    "country": "فلسطين"
  },
  "bio": "مبرمج ومطور برمجيات...",
  "followers_count": 5000,
  "following_count": 150,
  "posts": [ ...قائمة طويلة جدًا من المنشورات... ]
}

الآن، إذا كانت واجهة الموبايل تحتاج فقط لعرض الاسم (name)، فهي مضطرة لتحميل كل هذه البيانات واستهلاك باقة الإنترنت للمستخدم وإبطاء التطبيق بلا أي داعٍ.

مشكلة الـ Under-fetching: عندما تستجدي البيانات

هذه هي المشكلة المعاكسة. تخيل أنك تريد بناء صفحة تعرض المستخدم ومنشوراته وتعليقات المتابعين على كل منشور.

باستخدام REST، ستكون الرحلة كالتالي:

  1. الطلب الأول: GET /api/users/123 لجلب بيانات المستخدم.
  2. الطلب الثاني: GET /api/users/123/posts لجلب قائمة منشوراته.
  3. الطلبات التالية (N طلبات): لكل منشور، ستقوم بعمل طلب جديد GET /api/posts/POST_ID/comments لجلب التعليقات.

هذه المشكلة تُعرف بـ “N+1 Problem”. أنت تقوم بطلب واحد رئيسي، ثم N من الطلبات الإضافية. هذا العدد الكبير من رحلات الذهاب والإياب بين العميل والخادم يقتل أداء التطبيق، خصوصًا على شبكات الموبايل غير المستقرة.


GraphQL: المنقذ الذي يمنحك قوة الاختيار

GraphQL ليست لغة برمجة، ولا قاعدة بيانات، ولا إطار عمل (Framework) خاص بالـ Backend. ببساطة، GraphQL هي لغة استعلام (Query Language) للـ API الخاص بك، ومواصفة قياسية لكيفية تنفيذ هذه الاستعلامات.

فكر فيها كأنها “بوفيه مفتوح” بدلًا من “قائمة طعام محددة”. مع REST API، أنت تطلب “الوجبة رقم 5”. مع GraphQL، أنت تذهب للبوفيه وتختار بالضبط ما تريده في صحنك: “أريد القليل من الأرز، قطعة دجاج، والكثير من السلطة، وبدون زيتون”.

كيف يعمل السحر؟

بدلاً من وجود عشرات نقاط الوصول (Endpoints)، في GraphQL عادةً ما يكون لديك نقطة وصول واحدة فقط (مثل /graphql). العميل (الواجهة الأمامية) يرسل “استعلامًا” (Query) على شكل نص يصف البيانات التي يريدها بالضبط.

مثال عملي: حل مشكلة الـ Over-fetching

لنفترض أن الواجهة الأمامية تحتاج فقط لاسم المستخدم وصورته. بدلاً من طلب /api/users/123، سترسل استعلام GraphQL كالتالي:


query GetUserProfileHeader {
  user(id: "123") {
    name
    profilePictureUrl
  }
}

والسيرفر سيرد بـ JSON يحتوي فقط على ما طلبته، لا أكثر ولا أقل:


{
  "data": {
    "user": {
      "name": "أبو عمر",
      "profilePictureUrl": "https://example.com/abu_omar.jpg"
    }
  }
}

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

مثال عملي: حل مشكلة الـ Under-fetching

الآن، لصفحة المستخدم الكاملة التي تحتاج لبيانات المستخدم وآخر 3 منشورات له مع عناوينها، يمكن للواجهة الأمامية كتابة استعلام واحد مركب:


query GetUserProfilePage {
  user(id: "123") {
    name
    bio
    posts(last: 3) {
      id
      title
      createdAt
    }
  }
}

والرد سيأتي في طلب واحد فقط، منظم بنفس شكل الطلب:


{
  "data": {
    "user": {
      "name": "أبو عمر",
      "bio": "مبرمج ومطور برمجيات...",
      "posts": [
        {
          "id": "post-1",
          "title": "مقالتي الجديدة عن GraphQL",
          "createdAt": "2023-10-27T10:00:00Z"
        },
        {
          "id": "post-2",
          "title": "أفضل ممارسات الذكاء الاصطناعي",
          "createdAt": "2023-10-26T15:30:00Z"
        },
        {
          "id": "post-3",
          "title": "كيف تبدأ في البرمجة",
          "createdAt": "2023-10-25T12:00:00Z"
        }
      ]
    }
  }
}

بطلب واحد فقط، حصلنا على كل ما نحتاجه. لا رحلات مكوكية، لا بيانات زائدة. كفاءة وسرعة واحترام لباقة الإنترنت الخاصة بالمستخدم.


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

تبني GraphQL كان نقلة نوعية في مشاريعنا، لكن الطريق ما كان مفروش بالورود. إليكم بعض النصائح من قلب التجربة:

1. ابدأ بالـ Schema: عقدك المقدس

كل شيء في GraphQL يبدأ بالـ Schema (المخطط). هو العقد الموثق بين الواجهة الأمامية والخلفية. استثمر وقتًا في تصميمه جيدًا. استخدم لغة GraphQL Schema Definition Language (SDL) لتعريف أنواع البيانات المتاحة (Types) والاستعلامات (Queries) والتعديلات (Mutations).

نصيحة شخصية: لا تخف من تعديل الـ Schema. GraphQL مصمم للتطور. بدلاً من إصدار v2 و v3 من الـ API كما في REST، يمكنك ببساطة إضافة حقول جديدة دون التأثير على العملاء القدامى. يمكن إخفاء الحقول القديمة باستخدام @deprecated.

2. الـ Resolvers هي دماغ العملية

الـ Schema يصف “ماذا” يمكنك أن تطلب، أما الـ Resolvers فهي الدوال التي تجلب البيانات فعليًا، وتجيب على سؤال “كيف”. كل حقل في الـ Schema الخاص بك يقابله Resolver في الكود الخلفي.

هذا يمنحك مرونة هائلة. الـ Resolver الخاص ببيانات المستخدم قد يجلبها من قاعدة بيانات PostgreSQL، بينما الـ Resolver الخاص بمنشوراته قد يجلبها من MongoDB، والـ Resolver الخاص بالطقس قد يستدعي API خارجي آخر. كل هذا يحدث بسلاسة خلف الكواليس.

3. لا تهمل جانب الأمان والأداء

القوة الكبيرة تأتي مع مسؤولية كبيرة. بما أن العميل يمكنه طلب استعلامات معقدة جدًا، قد يستغل أحدهم هذه الميزة لإرسال استعلامات تستهلك كل موارد السيرفر (Denial of Service).

  • تحديد عمق الاستعلام (Query Depth Limiting): امنع الاستعلامات المتشعبة جدًا (مثل طلب أصدقاء أصدقاء أصدقاء…).
  • تحليل تكلفة الاستعلام (Query Cost Analysis): أعطِ “تكلفة” لكل حقل، وامنع تنفيذ الاستعلامات التي تتجاوز تكلفتها حدًا معينًا.

  • استخدام Timeouts: لا تسمح لاستعلام واحد بالعمل إلى الأبد.

4. عالم الأدوات رائع، فاستغله

النظام البيئي لـ GraphQL ضخم وناضج. لا تحاول إعادة اختراع العجلة.

  • للـ Backend: استخدم مكتبات مثل Apollo Server (لـ Node.js) أو Strawberry (لـ Python) أو graphql-java (لـ Java). هذه المكتبات توفر لك الكثير من الميزات الجاهزة.
  • للـ Frontend: استخدم عملاء مثل Apollo Client أو Relay. هذه المكتبات تسهل إدارة الحالة، التخزين المؤقت (Caching)، والتحديثات الفورية للواجهة. “ما بتغلب حالك، كل شي جاهز ومستنياك”.

الخلاصة: هل يجب أن أستخدم GraphQL؟

GraphQL ليس الحل السحري لكل المشاكل، و REST API ما زال خيارًا ممتازًا للكثير من الحالات البسيطة. لكن، إذا وجدت نفسك في أحد هذه المواقف، فأنصحك بشدة أن تعطي GraphQL فرصة:

  • لديك تطبيقات متعددة (ويب، موبايل iOS، موبايل Android) ولكل منها متطلبات بيانات مختلفة.
  • واجهات تطبيقك معقدة وتحتاج لبيانات من مصادر متعددة في شاشة واحدة.
  • فريق الواجهة الأمامية يشتكي باستمرار من بطء الـ API أو من حاجته لتعديلات مستمرة في الـ Backend.
  • تريد تقليل عدد رحلات الشبكة لتحسين أداء التطبيق على الإنترنت البطيء.

بالنسبة لنا، الانتقال لـ GraphQL لم يكن مجرد تغيير تقني، بل كان تغييرًا في ثقافة العمل. لقد أعطى القوة والمرونة لفريق الواجهة الأمامية، وحرر فريق الواجهة الخلفية من طلبات التعديل الصغيرة والمستمرة، والأهم من ذلك، جعل تطبيقاتنا أسرع وأكثر كفاءة. ✨

فيا صديقي المبرمج، لا تخف من تجربة الجديد. أحيانًا، تغيير بسيط في “كيف” تطلب البيانات، يمكن أن يصنع فرقًا كبيرًا في “ماذا” يمكنك أن تبني. يلا، شدّوا حيلكم! 💪

أبو عمر

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

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

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

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

آخر المدونات

الحوسبة السحابية

كانت بنيتنا التحتية قصراً من رمال: كيف أنقذتنا “البنية التحتية ككود” (IaC) من جحيم البيئات المتضاربة؟

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

17 مايو، 2026 قراءة المزيد
التوظيف وبناء الهوية التقنية

كان ملفي الشخصي مقبرة لمشاريع الدورات: كيف أنقذتني ‘المساهمة في المصادر المفتوحة’ من جحيم الرفض التلقائي؟

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

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

كانت قاعدة بياناتنا تتوسل الرحمة: كيف أنقذنا التخزين المؤقت (Caching) من جحيم الاستعلامات البطيئة

قصة حقيقية من واقع العمل عن كيفية انهيار نظامنا تحت ضغط الاستعلامات المتكررة، وكيف كان التخزين المؤقت (Caching) هو طوق النجاة. مقالة عملية للمطورين تشرح...

17 مايو، 2026 قراءة المزيد
التكنلوجيا المالية Fintech

كان التحقق من هوية عملائنا يستغرق أياماً: كيف أنقذنا الذكاء الاصطناعي (eKYC) من جحيم الإجراءات اليدوية؟

بصفتي مبرمجاً فلسطينياً، سأروي لكم حكايتنا مع كابوس التحقق اليدوي من هوية العملاء (KYC) وكيف كانت رحلة الانتقال إلى التحقق الإلكتروني (eKYC) باستخدام الذكاء الاصطناعي...

17 مايو، 2026 قراءة المزيد
البنية التحتية وإدارة السيرفرات

كانت أعطالنا تكتشف بعد فوات الأوان: كيف أنقذنا Prometheus من جحيم المراقبة التفاعلية؟

أشارككم قصة حقيقية من قلب المعركة التقنية، كيف انتقلنا من فوضى الأعطال المفاجئة إلى نظام مراقبة استباقي باستخدام Prometheus وGrafana. هذه المقالة ليست مجرد شرح...

17 مايو، 2026 قراءة المزيد
ادارة الفرق والتنمية البشرية

كانت فرقنا صامتة أمام الأخطاء: كيف أنقذتنا ‘السلامة النفسية’ من جحيم ثقافة اللوم؟

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

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