خدمة الواجهة الخلفية للواجهة الأمامية (BFF) هي خدمة خلفية مخصصة مصممة لواجهة أمامية واحدة محددة. بدلاً من أن يتصل كل عميل (الويب، iOS، Android، جهات خارجية) بنفس الواجهة الخلفية ذات الأغراض العامة، يحصل كل منهم على طبقته الخاصة من جانب الخادم التي تجمع وتعيد تشكيل البيانات من خدماتك المصغرة إلى الحمولة الدقيقة التي تحتاجها تلك الواجهة.
أطلق سام نيومان هذا النمط وروج له في عام 2015، استنادًا إلى العمل المنجز في SoundCloud. بعد أكثر من عقد من الزمان، لا يزال نمط BFF أداة قياسية للفرق التي تدير الخدمات المصغرة خلف تطبيقات عميل متعددة، وتوثقه مايكروسوفت كنمط معماري سحابي أساسي.
المشكلة التي تحلها خدمة الواجهة الخلفية للواجهة الأمامية (BFF)
تصور نظامًا بدأ بتطبيق ويب واحد وواجهة خلفية واحدة. كشفت الواجهة الخلفية عن نقاط نهاية REST، استهلكها تطبيق الويب، وكانت الحياة بسيطة. ثم أطلقت الشركة تطبيقًا للهاتف المحمول. ثم تكاملًا مع شريك. ثم أداة ساعة ذكية. فجأة، أربعة عملاء مختلفين جدًا يسحبون جميعًا من نفس الواجهة الخلفية، وتحاول هذه الواجهة الخلفية إرضاء الجميع في وقت واحد.
يخلق هذا مشكلتين متكررتين.
الإفراط في الجلب (Over-fetching) والنقص في الجلب (Under-fetching). نقطة النهاية ذات الأغراض العامة تُرجع شكلاً ثابتًا من البيانات. قد ترغب لوحة تحكم سطح المكتب في سجل العميل الكامل مع سجل الطلبات والتوصيات وإعدادات الحساب في استجابة واحدة. بينما يرغب تطبيق الهاتف المحمول على اتصال خلوي متقطع في ثلاثة حقول لا أكثر. عندما يصل كلاهما إلى نفس نقطة النهاية، يحصل أحدهما على كمية خاطئة من البيانات. يقوم العميل المتنقل إما بتنزيل حمولة كبيرة يجب التخلص منها (الإفراط في الجلب) أو يضطر إلى إجراء عدة رحلات ذهابًا وإيابًا إضافية لتجميع ما يحتاجه (النقص في الجلب).
العملاء الثرثارون (Chatty clients). عندما لا تكون الواجهة الخلفية مصممة خصيصًا لشاشة معينة، يعوض العميل ذلك بإجراء العديد من المكالمات. قد تقوم شاشة الهاتف المحمول الرئيسية التي تحتاج إلى بيانات ملف شخصي وعدد الإشعارات وموجز بإطلاق ثلاثة أو أربعة طلبات منفصلة إلى ثلاث أو أربع خدمات مصغرة، ثم تجمع النتائج معًا على الجهاز. كل رحلة ذهاب وعودة إضافية تكلف زمن استجابة وبطارية، وتتسرب منطق التنسيق إلى العميل حيث يصعب اختباره وتطوير إصداراته.
يكمن التوتر الجذري في الجانب التنظيمي بقدر ما هو تقني. الواجهة الخلفية المشتركة لديها متطلبات متضاربة من كل فريق واجهة أمامية. يجب التحقق من تغييرات فريق واحد مقابل احتياجات كل فريق آخر قبل نشرها، مما يحول الواجهة الخلفية إلى عنق الزجاجة ومصدر للاحتكاك بين الفرق.
كيف يعمل نمط BFF
يقدم نمط BFF طبقة رفيعة من جانب الخادم تجلس بين واجهة أمامية واحدة وخدماتك النهائية. تحصل كل واجهة على واجهتها الخلفية الخاصة بها.
[ Web app ] ---> [ Web BFF ] ---\
[ iOS app ] ---> [ iOS BFF ] -----> [ Microservices ]
[ Android app] ---> [ Android BFF ] ---/
تقوم كل خدمة واجهة خلفية للواجهة الأمامية (BFF) بثلاث وظائف لعميلها:
- التجميع. تستدعي الخدمات المصغرة النهائية التي تحتاجها الشاشة وتجمع استجاباتها، بحيث يقوم العميل بطلب واحد بدلاً من خمسة. هذا هو تجميع واجهة برمجة التطبيقات (API aggregation) المطبق على تجربة مستخدم واحدة. إذا كنت تريد النسخة العامة لهذه الفكرة، فراجع شرحنا حول نمط مجمع واجهة برمجة التطبيقات (API aggregator).
- إعادة التشكيل. تقوم بقص الحقول، وإعادة تسمية الأشياء بمصطلحات سهلة الاستخدام للعميل، وتسطيح الهياكل المتداخلة، وتنسيق القيم بالطريقة التي تتوقعها الواجهة. تُرجع خدمة الواجهة الخلفية للواجهة الأمامية (BFF) الخاصة بالهاتف المحمول حمولات خفيفة؛ وتُرجع خدمة الواجهة الخلفية للواجهة الأمامية (BFF) الخاصة بسطح المكتب حمولات غنية.
- الترجمة. تتعامل مع المخاوف الخاصة بالعميل مثل استراتيجية تقسيم الصفحات، وتخزين استجابات مؤقتًا لتناسب ذلك العميل، وخيارات البروتوكول، دون فرض هذه القرارات على الخدمات المشتركة الأساسية.
تظل الخدمات المصغرة النهائية ذات أغراض عامة ومستقلة عن الواجهة الأمامية. تكشف عن إمكانيات نظيفة وقابلة لإعادة الاستخدام. تُعد خدمة الواجهة الخلفية للواجهة الأمامية (BFF) هي المكان الذي توجد فيه عملية التشكيل الخاصة بالعميل، مما يبقي هذا المنطق خارج كل من الخدمات المصغرة وتطبيق العميل. إذا كنت جديدًا على طبقة الخدمة الأساسية، فإن نظرتنا العامة حول الخدمات المصغرة مقابل واجهات برمجة التطبيقات والانتقال من التطبيقات المتجانسة إلى الخدمات المصغرة توضح السياق.
خدمة BFF واحدة لكل تجربة عميل
إرشادات نيومان الأساسية موجزة: تجربة واحدة، خدمة BFF واحدة. إذا كانت تطبيقات iOS و Android الخاصة بك تقدم تجارب مختلفة بشكل جوهري، فامنح كل واحدة منها خدمة BFF خاصة بها. إذا تباعد تطبيق ويب وتطبيق جوال، تنطبق نفس القاعدة.
الهدف من القاعدة هو إبقاء كل خدمة BFF مركزة. في اللحظة التي تحاول فيها خدمة BFF واحدة خدمة عميلين باحتياجات مختلفة، تبدأ في تجميع منطق شرطي ("إذا كان جوالاً، أعد هذا؛ إذا كان ويبًا، أعد ذاك")، وتعود إلى واجهة خلفية للأغراض العامة مع جميع مشاكل التنسيق نفسها. تظل خدمة BFF المركزة صغيرة، وهذه هي الخاصية التي تجعل النمط برمته مجديًا.
هناك استثناء معقول استمده نيومان نفسه من SoundCloud: عندما يمتلك فريق واحد عميلين متشابهين، مثل تطبيقات iOS و Android التي تتشارك نفس التجربة تقريبًا، يمكن أن يكون من المنطقي مشاركة خدمة BFF متنقلة واحدة بينهما. العامل الحاسم هو الملكية والتشابه، وليس أسماء المنصات. القاعدة هي افتراضية، وليست قانونًا.
الملكية تعود لفريق الواجهة الأمامية
خدمة الواجهة الخلفية للواجهة الأمامية (BFF) ليست طبقة يبنيها فريق المنصة ويسلمها. فريق الواجهة الأمامية الذي يمتلك العميل يمتلك خدمة BFF الخاصة به. هذا هو النصف الثاني مما يجعل النمط يعمل.
عندما يمتلك فريق الواجهة الأمامية خدمة الواجهة الخلفية للواجهة الأمامية (BFF)، فإنهم يتحكمون في وتيرة إصدارها، ويختارون لغتها وبيئة التشغيل الخاصة بها، ويضعون أولويات مهامها المتراكمة، ويشحنون التغييرات إلى العميل وخدمته الخلفية معًا. لا يتطلب تغيير واجهة المستخدم الذي يحتاج إلى نقطة نهاية مجمعة جديدة تقديم تذكرة إلى فريق واجهة خلفية منفصل والانتظار حتى يتم مسح قائمة انتظار ذلك الفريق. الفريق الذي يشعر بالألم يمتلك الحل.
هذا الاستقلال هو المكسب الحقيقي. تحرك خدمة الواجهة الخلفية للواجهة الأمامية (BFF) الحدود بحيث تُتخذ القرارات الخاصة بالعميل من قبل الأشخاص المسؤولين عن العميل، وهو بالضبط المكان الذي يضع فيه تفكير الاتصال الموجه بواجهة برمجة التطبيقات (API-led connectivity) طبقة "التجربة".
BFF مقابل بوابة API
هذه هي المقارنة التي يقع فيها معظم الفرق، لأن خدمة الواجهة الخلفية للواجهة الأمامية (BFF) وبوابة API تبدوان متشابهتين من مخطط. كلاهما يجلس بين العملاء والخدمات. كلاهما يمكنه التوجيه والتجميع. لكنهما يجيبان على أسئلة مختلفة.
تُعد بوابة API نقطة دخول عامة الأغراض تتعامل مع المخاوف الشاملة لجميع حركة المرور: المصادقة، تحديد المعدل، التوجيه، إنهاء TLS، وتسجيل الطلبات. يمتلكها فريق المنصة أو البنية التحتية وهي مستقلة عن العميل عمدًا. بوابة واحدة تخدم الجميع بنفس الطريقة.
خدمة الواجهة الخلفية للواجهة الأمامية (BFF) هي العكس. إنها مصممة خصيصًا للعميل، ويمتلكها فريق الواجهة الأمامية، وهدفها الرئيسي هو أن تكون مختلفة لكل واجهة. إنه المكان الذي يعيش فيه تشكيل حمولة عميل واحد، وليس نقطة اختناق مشتركة.
الاثنان ليسا متنافسين. في تصميم إنتاجي شائع، تجلس بوابة API في الأمام، وتتعامل مع المصادقة وتحديد المعدل والمراقبة لجميع حركة المرور، ثم توجه كل عميل إلى خدمة BFF المخصصة له خلف البوابة. توضح بنية مايكروسوفت المرجعية هذا بالضبط: بوابة تدير المخاوف الشاملة، مع خدمة BFF لا خادمية (serverless) لكل عميل خلفها. استخدم البوابة لما هو متشابه عبر العملاء، وخدمة BFF لما هو مختلف. (نغطي النسخة العميقة من هذا التباين في مقال منفصل؛ هنا يكفي أن نعرف أنهما يقعان في طبقات مختلفة ويلبيان احتياجات مختلفة.)
بالنسبة لمشهد البوابة المحيط، تساعد هذه المقارنات المنشورة: إدارة API مقابل بوابة API، بوابة API مقابل موازن التحميل، و شبكة الخدمات مقابل بوابة API.
متى تستخدم خدمة BFF
يكتسب هذا النمط قيمته عندما تتوفر هذه الشروط:
- لديك عملاء متعددون ومختلفون حقًا. الويب بالإضافة إلى الجوال بالإضافة إلى تكامل شريك، ولكل منها احتياجات بيانات مميزة. كلما تباعدت التجارب، زادت مساعدة خدمة BFF.
- أصبحت الواجهة الخلفية المشتركة عنق الزجاجة. إذا كان كل تغيير في الواجهة الأمامية يفرض تفاوضًا بين الفرق، فإن تقسيم التشكيل الخاص بالعميل إلى خدمات BFF لكل فريق يزيل عبء التنسيق.
- تريد حمولات محسّنة للعميل. يحتاج الجوال إلى استجابات خفيفة وتخزين مؤقت قوي؛ ويرغب سطح المكتب في بيانات مجمعة غنية. تتيح لك خدمة BFF تحسين كل منها دون مساومة.
- لغة تناسب واجهة أمامية واحدة بشكل أفضل. يمكن للفريق بناء خدمة BFF الخاصة به في بيئة التشغيل التي تناسب عميله، بغض النظر عما تستخدمه خدمات BFF الأخرى.
متى لا تستخدم خدمة BFF
النمط ليس مجانيًا، وهناك حالات واضحة يضيف فيها تكلفة دون عائد:
- لديك عميل واحد فقط. بواجهة واحدة، خدمة BFF هي مجرد قفزة إضافية. قم ببناء واجهة خلفية عادية.
- يقوم عملاؤك بنفس الطلبات. إذا كان الويب والجوال يريدان بيانات متطابقة تقريبًا بنفس الشكل، فإن خدمات BFF المنفصلة تكرر الجهد دون فائدة. ادمج بدلاً من ذلك.
- يحل GraphQL بالفعل مشكلة التشكيل لديك. باستخدام GraphQL، يستعلم كل عميل بالضبط عن الحقول التي يحتاجها من نقطة نهاية واحدة، وهذا يغطي جزءًا كبيرًا مما تفعله خدمة BFF لتشكيل الحمولة. إذا كان لديك طبقة GraphQL مع محللات خاصة بالواجهة الأمامية، فإن طبقة BFF منفصلة غالبًا لا تضيف قيمة. راجع ما هو GraphQL للحكم على ما إذا كان مناسبًا قبل إضافة طبقة BFF.
- بوابة بالإضافة إلى الخدمات المصغرة كافية. للأنظمة الأبسط، يمكن لبوابة API أمام الخدمات المصغرة المصممة جيدًا أن تحقق نتائج مقبولة دون طبقة مخصصة لكل عميل.
العيوب الصريحة
حتى عندما تكون خدمة BFF هي الخيار الصحيح، فإنك تتحمل تكاليف حقيقية. التعامل مع الأمر بعيون مفتوحة هو جزء من استخدام النمط بشكل جيد.
- تكرار الكود. هذا هو المقايضة الرئيسية، وتوثيقات مايكروسوفت تشير إليه مباشرة. عندما تحتاج ثلاث خدمات BFFs إلى استدعاء نفس فحص المصادقة أو تنسيق نفس التاريخ بنفس الطريقة، يميل هذا المنطق إلى أن يُكتب ثلاث مرات. أنت تقايض التكرار بالتخصيص. الحل هو الانضباط: احتفظ بالمنطق المشترك حقًا في المكتبات التي تستوردها خدمات BFF، واحتفظ بخدمة BFF نفسها لتشكيل خاص بالعميل. ادفع المخاوف الشاملة الحقيقية (المصادقة، تحديد المعدل، المراقبة) إلى البوابة بدلاً من إعادة تنفيذها لكل خدمة BFF.
- المزيد من الخدمات للتشغيل. كل خدمة BFF هي وحدة أخرى قابلة للنشر بدورة حياتها الخاصة، وخط أنابيبها، وتناوب المناوبة، ومساحة الأمان الخاصة بها. المزيد من الخدمات يعني المزيد من الأعباء التشغيلية.
- قفزة شبكة إضافية. لم يعد العملاء يتحدثون إلى الخدمات مباشرة. تضيف خدمة BFF قفزة، وهذا يمكن أن يزيد من زمن الاستجابة. عادة ما تكون مقايضة مجدية لأن خدمة BFF تزيل عدة رحلات ذهاب وعودة للعميل، لكنها تكلفة يجب قياسها، وليس افتراضها.
- خطر تضخم خدمة BFF. إذا بدأت خدمة BFF في خدمة عملاء متعددين أو استيعاب منطق أعمال ينتمي إلى الخدمات المصغرة، فإنها تعود إلى الواجهة الخلفية ذات الأغراض العامة التي كنت تحاول الهروب منها. حافظ عليها خفيفة.
الحفاظ على مزامنة عقود BFF مع Apidog
الجزء الصعب في تشغيل خدمات الواجهة الخلفية للواجهة الأمامية (BFF) عمليًا هو العقود. تكشف كل خدمة BFF عن واجهة برمجة التطبيقات الخاصة بها الموجهة للعميل، وتعتمد أيضًا على عقود الخدمات المصغرة الأساسية. هذا يعني الكثير من الواجهات المتنقلة عبر فرق تمتلك طبقات مختلفة، والانجراف بينها هو مصدر الأخطاء والعملاء المعطلين.

هنا يأتي دور Apidog في سير العمل. Apidog هي منصة لتصميم واجهة برمجة التطبيقات واختبارها ومحاكاتها وتوثيقها، لذا فإن عقد API الخاص بكل خدمة BFF له منزل واحد يمكن لفرق الواجهة الأمامية والخلفية العمل عليه:
- صمم العقد أولاً. حدد كل نقطة نهاية لخدمة BFF ومخطط الطلب والاستجابة الخاص بها في مصمم Apidog المرئي باستخدام OpenAPI كقاعدة، بحيث يتم الاتفاق على الشكل الموجه للعميل قبل كتابة الكود. هذا هو نهج تصميم API على أساس العقد أولاً المطبق على طبقة BFF، ويحافظ على عقد API واضحًا.
- احاكِه قبل وجوده. يمكن لفريق الواجهة الأمامية البدء في البناء بالاعتماد على محاكاة Apidog الذكية لخدمة BFF في يوم الاتفاق على العقد، دون انتظار أن تكون خدمة BFF أو خدماتها النهائية جاهزة.
- اختبر العقد. تتحقق الاختبارات والتأكيدات الآلية في Apidog من أن كل خدمة BFF تُرجع الحمولة المجمعة والمعاد تشكيلها التي يتوقعها عميلها، وتتلاءم مع التكامل المستمر (CI) بحيث يتم اكتشاف أي تغيير في الخدمات النهائية يؤدي إلى كسر استجابة BFF مبكرًا.
- وثّق للجانبين. يقوم Apidog بتوليد وثائق تفاعلية تلقائيًا من العقد، بحيث يتشارك فريق الواجهة الأمامية الذي يقرأ واجهة برمجة تطبيقات BFF وفريق الواجهة الخلفية الذي يمتلك الخدمات الأساسية مصدرًا واحدًا للحقيقة.
لتوضيح النطاق: Apidog لا يقوم ببناء أو استضافة أو تشغيل خدمة BFF الخاصة بك، وهي ليست بوابة API. إنها المكان الذي تقوم فيه بتصميم ومحاكاة واختبار وتوثيق عقد API الذي تستند إليه كل خدمة BFF، وهو ما يحافظ على تزامن فرق الواجهة الأمامية والخلفية مع تطور خدمات BFF. التعامل مع كل خدمة BFF كمنتج بعقد مستقر وموثق جيدًا هو ما يجعل هذا النمط مستدامًا.
الأسئلة الشائعة
هل BFF خدمة مصغرة؟ خدمة BFF هي خدمة من جانب الخادم، وفي إعداد الخدمات المصغرة عادة ما تعمل كواحدة منها. لكن وظيفتها تختلف عن وظيفة الخدمة المصغرة النموذجية. تمتلك الخدمة المصغرة قدرة عمل وتظل مستقلة عن العميل؛ بينما تمتلك خدمة BFF تجربة عميل واحدة وتوجد لتجميع وإعادة تشكيل تلك الخدمات المصغرة لذلك العميل. إنها خدمة على مستوى التجربة، وليست خدمة قدرة عمل.
كم عدد خدمات BFF التي يجب أن أمتلكها؟ الافتراضي هو واحدة لكل تجربة عميل مميزة: واحدة للويب، وواحدة لنظام iOS، وواحدة لنظام Android، وهكذا. ادمج اثنتين فقط عندما يمتلك فريق واحد عملاء باحتياجات متطابقة تقريبًا. قم بالتقسيم أكثر عندما تبدأ إحدى خدمات BFF في تجميع منطق شرطي لكل عميل.
هل يحل GraphQL محل نمط BFF؟ يمكنه ذلك، بالنسبة لجزء تشكيل الحمولة. يسمح GraphQL لكل عميل بطلب الحقول التي يحتاجها بالضبط من نقطة نهاية واحدة، مما يغطي الإفراط في الجلب والنقص في الجلب دون الحاجة إلى واجهة خلفية لكل عميل. إذا كان لديك GraphQL مع محللات (resolvers) خاصة بالواجهة الأمامية، فإن طبقة BFF منفصلة غالبًا لا تضيف الكثير. لا تزال خدمات BFF مفيدة عندما تحتاج إلى تنسيق خاص بالعميل، أو ترجمة بروتوكول، أو خيارات تشغيل لا يمكن لخادم GraphQL المشترك توفيرها بسهولة.
هل يمكنني استخدام BFF وبوابة API معًا؟ نعم، وهذا أمر شائع. تتعامل بوابة API مع المخاوف المشتركة بين جميع العملاء، مثل المصادقة، وتحديد المعدل، والمراقبة، وتوجه حركة المرور إلى خدمة BFF الصحيحة. تتعامل كل خدمة BFF مع ما هو خاص بعميلها. إنهما يقعان في طبقات مختلفة ويؤديان مهام مختلفة.
من يجب أن يمتلك خدمة BFF؟ فريق الواجهة الأمامية الذي يمتلك العميل. هذه الملكية محورية في النمط. تتيح للفريق شحن تغييرات واجهة المستخدم ونقاط النهاية الخلفية معًا، واختيار بيئة التشغيل الخاصة به، والتحرك دون انتظار دور فريق واجهة خلفية منفصل.
هل تضيف خدمة BFF زمن استجابة؟ إنها تضيف قفزة شبكة واحدة، ولها تكلفة. عمليًا، عادة ما تقلل من إجمالي زمن استجابة العميل، لأنها تستبدل عدة رحلات ذهاب وعودة من العميل إلى الخدمة بطلب واحد من العميل إلى BFF وتسمح لـ BFF باستدعاء الخدمات بالتوازي بالقرب منها. قم بقياسها لعبء عملك بدلاً من الافتراض بأي من الاتجاهين.
