كانت تطبيقاتنا تغرق في البيانات: رحلتي من جحيم الـ Over-fetching في REST إلى نعيم GraphQL

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

كنا شغالين على تطبيق اجتماعي جديد، والفريق كله حماس وطاقة. الواجهات الخلفية (Backend) شغالة زي الساعة على بنية REST API محترمة، والواجهات الأمامية (Frontend) بتصاميمها الجذابة جاهزة. أطلقنا نسخة تجريبية للموظفين، وهون بلشت الشكاوى. “التطبيق بعلّق على النت الضعيف”، “ليش صفحة البروفايل بتطوّل لَتفتح؟”. كالعادة، أول اشي بنفكّر فيه هو استعلامات قاعدة البيانات أو كفاءة الكود في الخادم.

قعدت في ليلة من الليالي، فتحت أدوات المطورين (Developer Tools) وشغّلت التطبيق على محاكاة لشبكة 3G بطيئة. فتحت صفحة بروفايل مستخدم، وشفت الكارثة بعيني. طلب API واحد لصفحة البروفايل، اللي المفروض تعرض بس اسم المستخدم وصورته وكم معلومة بسيطة، كان بيرجع ملف JSON حجمه ضخم! فيه تاريخ ميلاد المستخدم، كل عناوينه المسجلة، سجل مشترياته، آخر مرة سجل فيها دخوله بالمللي ثانية، وحتى آراءه في منتجات ما الها علاقة بالتطبيق! وقتها صرخت بالفريق (طبعاً بيني وبين حالي): “يا جماعة، شو القصة؟ إحنا بنحمّل كل تاريخ حياته للمستخدم عشان نعرض صورته؟!”.

كانت هاي اللحظة هي بداية رحلتنا للبحث عن حل، رحلة أخذتنا من عالم REST المألوف إلى عالم GraphQL الواسع والفعّال.

ما هو الجحيم الذي أتحدث عنه؟ لنُعرّف الـ Over-fetching

المشكلة اللي واجهناها الها اسم تقني معروف: Over-fetching أو “جلب البيانات المفرط”. ببساطة، هي لما العميل (زي تطبيق الموبايل أو الويب) يطلب بيانات من الخادم عبر API، والخادم يرجعله بيانات أكتر بكتير من اللي بيحتاجها العميل فعلاً لعرض الصفحة الحالية.

خلينا ناخد مثال صفحة المستخدم اللي حكيتلكم عنها. تطبيق الموبايل كان محتاج يعرض بس معلومتين:

  • اسم المستخدم (name)
  • صورته الشخصية (profilePictureUrl)

لكن نقطة النهاية (Endpoint) في الـ REST API اللي صممناها، /api/users/{id}، كانت مصممة عشان تكون شاملة وترجع كل معلومات المستخدم. فكانت الاستجابة (Response) اللي بترجع للتطبيق شكلها زي هيك:


{
  "id": "123",
  "name": "أبو عمر",
  "username": "abu_omar_dev",
  "email": "abu.omar@example.com",
  "profilePictureUrl": "https://.../abu_omar.jpg",
  "coverPhotoUrl": "https://.../cover.jpg",
  "bio": "مبرمج فلسطيني بحب الكنافة والـ Clean Code",
  "dateOfBirth": "1985-01-15T00:00:00.000Z",
  "address": {
    "street": "شارع الجامعة",
    "city": "رام الله",
    "country": "فلسطين"
  },
  "lastLogin": "2023-10-27T10:30:00.000Z",
  "accountCreatedAt": "2020-05-20T14:00:00.000Z",
  "purchaseHistory": [
    { "productId": "prod_a", "date": "..." },
    { "productId": "prod_b", "date": "..." }
  ],
  "userPreferences": {
    "theme": "dark",
    "notifications": true
  }
}

شايفين كمية البيانات الهائلة هاي؟ التطبيق كان محتاج بس سطرين من كل هاي “الجريدة”، ولكنه كان مضطر يستقبلها كلها، يحللها، وبعدين يتجاهلها. وهذا هو تماماً معنى “الغرق في البيانات”.

الآثار الجانبية الكارثية للـ Over-fetching

  • بطء التطبيق: نقل بيانات أكبر يعني وقت أطول للتحميل، خصوصاً على شبكات الموبايل البطيئة أو غير المستقرة.
  • استهلاك باقة الإنترنت: إنت حرفياً بتحرق باقة الإنترنت للمستخدم على بيانات ما رح يشوفها.
  • زيادة الحمل على الخادم: الخادم بيبذل مجهود في جلب كل هاي البيانات من قاعدة البيانات وتحويلها لصيغة JSON، مع إنه جزء كبير منها غير ضروري.
  • تجربة مستخدم سيئة: النتيجة النهائية لكل هاد هي تطبيق بطيء ومحبط للمستخدم.

الـ REST API: ليست شريرة، ولكنها… محدودة في هذا السياق

هون لازم أكون منصف. الـ REST مش سيئة، بالعكس، هي بنية عظيمة خدمت الويب لعقود وما زالت تخدمه بكفاءة. هي بسيطة، مفهومة، وبتعتمد على معايير الويب (HTTP) بشكل مباشر. مشكلتها مش في تصميمها، ولكن في فلسفتها القائمة على “الموارد” (Resources).

في عالم REST، كل نقطة نهاية (Endpoint) بتمثل مورد كامل. /users هو مورد المستخدمين، و /products هو مورد المنتجات. هاي الفلسفة بتصير عبء لما يكون عندك عملاء مختلفين (موبايل، ويب، تطبيق مكتبي) وكل واحد فيهم بيحتاج جزء مختلف من نفس المورد.

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

طبعاً حاولنا نلاقي حلول ضمن عالم REST. فريق اقترح نعمل endpoint مخصص للموبايل زي /api/mobile/users/{id} يرجع بس البيانات الأساسية. وفريق تاني اقترح نستخدم معاملات الاستعلام (Query Parameters) زي /api/users/{id}?fields=name,profilePictureUrl. هاي الحلول بتشتغل، لكنها بتخلق مشاكل تانية:

  1. فوضى نقاط النهاية (Endpoint Hell): الحل الأول بيعني إنه لكل عميل جديد أو لكل شاشة جديدة، ممكن نضطر نعمل endpoint جديد. بعد فترة، بصير عندك خريطة endpoints معقدة وصعبة الصيانة، زي ما بنحكي “بتصير طوشة”.
  2. إعادة اختراع العجلة: الحل الثاني أفضل، لكنه غير معياري. كل فريق بيعمله بطريقته، وبتحتاج تكتب منطق خاص في الـ Backend عشان تحلل هاي الـ “fields” وتجيب البيانات على أساسها. إنت فعلياً بتكون قاعد بتبني نسخة مصغّرة وغير ناضجة من GraphQL بنفسك!

دخول البطل: مرحباً GraphQL

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

GraphQL مش مكتبة ولا إطار عمل، هي لغة استعلام (Query Language) للـ API، وفلسفتها بسيطة وعبقرية: “اطلب ما تحتاجه بالضبط، وستحصل عليه بالضبط، لا أقل ولا أكثر”.

بدل ما يكون عندك عشرات الـ Endpoints الثابتة، في GraphQL بيكون عندك نقطة نهاية واحدة (عادة /graphql) بتقدر ترسل إلها استعلامات معقدة. العميل هو اللي بيتحكم بشكل ونوع البيانات اللي بدو ياها، مش الخادم.

كيف أنقذتنا GraphQL؟ لنرى المثال عملياً

باستخدام GraphQL، تطبيق الموبايل اللي كان محتاج بس اسم المستخدم وصورته، صار يبعت “استعلام” (Query) للخادم شكله كالتالي:


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

والخادم، اللي بيفهم لغة GraphQL، بيرجع استجابة شكلها مطابق تماماً لشكل الطلب:


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

لاحظ الجمال والبساطة! لا بيانات زيادة، لا حقول غير مستخدمة. حجم الاستجابة صار أصغر بعشرات المرات، والتطبيق صار “يحلّق” حتى على أبطأ الشبكات. أعطينا القوة للـ Frontend ليطلب اللي بيحتاجه، وارتاح الـ Backend من همّ إنشاء endpoints لكل حالة استخدام.

لكن انتظر، هناك المزيد! مشكلة الـ Under-fetching

GraphQL ما حلت بس مشكلة الـ Over-fetching، بل حلت مشكلة تانية على نفس القدر من الأهمية اسمها Under-fetching.

الـ Under-fetching هي الوجه الآخر للعملة. بتحصل لما تحتاج بيانات من موارد مختلفة عشان تعرض شاشة واحدة، فبتضطر تعمل عدة طلبات API. مثلاً، لعرض صفحة مقال في مدونة، ممكن تحتاج:

  1. طلب لـ /api/posts/{postId} عشان تجيب تفاصيل المقال.
  2. طلب لـ /api/users/{userId} عشان تجيب اسم وصورة كاتب المقال.
  3. طلب لـ /api/posts/{postId}/comments عشان تجيب التعليقات.

هون إنت بتعمل 3 رحلات ذهاب وإياب للخادم (Round trips)، وهذا بحد ذاته بطء وتأخير.

في GraphQL، هاي المشكلة بتنحل بطلب واحد فقط. بتقدر تطلب بيانات متداخلة من موارد مختلفة في استعلام واحد:


query GetPostPage {
  post(id: "post-456") {
    title
    content
    author {
      name
      profilePictureUrl
    }
    comments {
      text
      author {
        name
      }
    }
  }
}

بطلب واحد، جبنا المقال، وكاتبه، وكل التعليقات مع أسماء أصحابها. هاي هي قوة GraphQL الحقيقية: القدرة على وصف البيانات اللي بتحتاجها بدقة، بغض النظر عن مدى تعقيدها أو تداخلها.

نصائح من خبرة أبو عمر: متى تختار GraphQL؟

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

استخدم GraphQL عندما…

  • لديك عملاء متعددون: تطبيق ويب، تطبيق موبايل (iOS و Android)، ساعة ذكية… كل واحد منهم يحتاج مجموعة بيانات مختلفة. GraphQL بتخليك تخدمهم كلهم من API واحد.
  • الأداء وحجم البيانات حرج: خصوصاً في تطبيقات الموبايل اللي بتشتغل على شبكات متغيرة.
  • البيانات عندك مترابطة ومعقدة: إذا كانت بياناتك تشبه “الرسم البياني” (Graph) بطبيعتها (مستخدمين، منشورات، تعليقات، أصدقاء…)، فاسم GraphQL لم يأتِ من فراغ.
  • تريد تسريع وتيرة تطوير الواجهات الأمامية: GraphQL بتعطي مطوري الـ Frontend استقلالية كبيرة، ما بيحتاجوا يطلبوا تغييرات في الـ Backend كل مرة بيحتاجوا حقل بيانات جديد.

تمسّك بـ REST عندما…

  • الـ API بسيط جداً: إذا كان تطبيقك عبارة عن عمليات CRUD بسيطة على موارد قليلة ومستقلة، فالـ REST قد تكون أسرع وأسهل في التنفيذ.
  • * فريقك غير جاهز: GraphQL تتطلب منحنى تعلم، سواء في الـ Backend (بناء الـ Schema والـ Resolvers) أو في الـ Frontend (استخدام مكتبات زي Apollo أو Relay).

  • تعتمد بشدة على التخزين المؤقت (Caching) على مستوى HTTP: الـ REST تستفيد من الـ Caching تبع الـ HTTP بشكل رائع. في GraphQL، بما إنه كل الطلبات بتروح على endpoint واحد وبطريقة POST، فإن آليات التخزين المؤقت بتختلف وبتحتاج استراتيجية مختلفة على مستوى العميل.

الخلاصة: هل نرمي REST في سلة المهملات؟

بالتأكيد لا. القصة اللي حكيتها ما كانت عن التخلص من REST، بل عن فهم حدودها واختيار الأداة المناسبة للمشكلة المناسبة. REST ما زالت رائعة للـ Microservices، وللـ APIs العامة البسيطة، وللحالات اللي بتكون فيها الموارد واضحة ومحددة.

اللي تعلمناه من هذيك التجربة هو أهمية “تمكين العميل” (Empowering the client). GraphQL أعطت تطبيقاتنا صوت، خلتها تقدر تطلب اللي بتحتاجه بالضبط، وحولتها من تطبيقات “تغرق” في البيانات إلى تطبيقات “تسبح” برشاقة وخفة.

نصيحتي الأخيرة الك: لا تتعصب لتقنية على حساب أخرى. في عالم البرمجة، ما في حل سحري واحد لكل المشاكل. الأهم هو فهم المشكلة كويس واختيار الأداة الصح… زي النجار الشاطر اللي بعرف متى يستخدم المنشار ومتى يستخدم المطرقة. 😉

أبو عمر

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

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

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

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

آخر المدونات

برمجة وقواعد بيانات

تحديثات قاعدة البيانات بدون توقف: كيف أنقذنا نمط التوسيع والتعاقد (Expand/Contract) من جحيم التوقفات المجدولة؟

هل سئمت من إيقاف الخدمة مع كل تحديث لهيكلة قاعدة البيانات؟ أشارككم قصة حقيقية وكيف أنقذنا نمط التوسيع والتعاقد (Expand/Contract) من ليالي النشر الطويلة والمُجهدة،...

4 يونيو، 2026 قراءة المزيد
الشبكات والـ APIs

كانت إعادة المحاولة كارثة: كيف أنقذتنا مفاتيح عدم تكرار العمليات (Idempotency Keys) من جحيم الفواتير المزدوجة؟

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

4 يونيو، 2026 قراءة المزيد
الحوسبة السحابية

من التوقف التام إلى النجاة: كيف أنقذتنا استراتيجية “الضوء المرشد” (Pilot Light) يوم انقطعت السحابة؟

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

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

كانت مهمتي البرمجية للاختبار مجرد كود: كيف أنقذني توثيق القرارات من جحيم الصمت بعد المقابلة؟

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

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

من الانتظار لأيام إلى الدفع في ثوانٍ: كيف أنقذتنا شبكات الدفع الفوري من جحيم التحويلات البنكية؟

أسرد لكم من واقع تجربتي كـ "أبو عمر"، كيف عانينا من بطء وتكلفة التحويلات البنكية الدولية، وكيف جاءت شبكات الدفع الفوري ومعيار ISO 20022 لتكون...

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

كان كل خادم لدينا ‘ندفة ثلج’ فريدة: كيف أنقذنا ‘الكود كبنية تحتية’ (IaC) من جحيم الانجراف اليدوي؟

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

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

كانت تغطية الاختبارات 100% لكن الأخطاء تتسرب: كيف أنقذنا “الاختبار الطفري” من جحيم الثقة الزائفة؟

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

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