Ribs للهاتف المحمول عبر الأنظمة الأساسية من Uber

في 20 ديسمبر 2016 ، نشر الرجال من Uber Engineering مقالًا حول الهندسة المعمارية الجديدة (إليك ترجمة هذه المقالة على المحور). أقدم لكم ترجمة الجزء الرئيسي من التوثيق.

ما هي بنية RIBs؟


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

في تطوير هذا الإطار ، التزم مهندسو أوبر بالمبادئ التالية:

  • دعم التعاون بين الأشخاص الذين يتطورون على منصات مختلفة: تتشابه الغالبية العظمى من الأجزاء المعقدة من تطبيقات Uber على نظامي iOS و Android. توفر RIBs أنماط تطوير مشتركة لنظامي Android و iOS. عند استخدام RIBs ، يمكن للمهندسين على كل من iOS و Android مشاركة بنية مطورة بشكل مشترك لوظائفهم.
  • تقليل الحالات والقرارات العالمية : يمكن أن تؤدي التغييرات العالمية في الحالة إلى سلوك غير متوقع ويمكن أن تجعل من المستحيل معرفة ما ستؤدي إليه هذه التغييرات أو تلك التغييرات في رمز البرنامج. تشجع الهندسة القائمة على RIBs الحالات المغلفة في تسلسل هرمي عميق من RIBs المعزولة جيدًا لتجنب المشاكل مع الدول العالمية.
  • قابلية الاختبار والعزل: يجب أن تكون الفصول بسيطة حتى تتمكن من كتابة اختبارات الوحدة ، ولها أيضًا سبب للعزل (في إشارة إلى برنامج التقويم الاستراتيجي ). تتحمل فئات RIB الفردية مسؤوليات مختلفة (على سبيل المثال ، التوجيه ، منطق الأعمال ، منطق العرض التقديمي ، إنشاء فئات RIB أخرى). بالإضافة إلى ذلك ، فإن منطق RIB الأصلي منفصل بشكل أساسي عن منطق RIB التابع. هذا يجعل من السهل اختبار فئات RIB وتقليل التبعية بين مكونات النظام.
  • أدوات التطوير الإنتاجي: يمكن أن يؤدي استعارة الأنماط المعمارية غير التافهة إلى مشكلات في نمو التطبيق إذا لم تكن هناك أدوات موثوقة لدعم الهندسة المعمارية. تأتي بنية RIBs مع أدوات IDE لإنشاء التعليمات البرمجية والتحليل الثابت وتكامل وقت التشغيل ، مما يحسن إنتاجية المطورين في الفرق الكبيرة والصغيرة.
  • مبدأ القرب من الانفتاح: يجب على المطورين ، إذا أمكن ، إضافة وظائف جديدة دون تغيير الكود الحالي. عند استخدام RIBs ، يمكن رؤية تنفيذ هذه القاعدة في عدد من الأماكن. على سبيل المثال ، يمكنك إرفاق أو إنشاء RIB طفل معقد يتطلب تبعيات على RIB الأصل الخاص به ، مع تغيير طفيف أو بدون تغيير في RIB الأصل.
  • الهيكلة حول منطق الأعمال: يجب ألا تعكس بنية منطق الأعمال الخاصة بالتطبيق بشكل صارم بنية واجهة المستخدم. على سبيل المثال ، لتسهيل الحركة وأداء العرض ، قد يكون التسلسل الهرمي للعرض أصغر من التسلسل الهرمي لـ RIB. أو يمكن لوظيفة RIB واحدة التحكم في مظهر ثلاث طرق عرض تظهر في أماكن مختلفة على واجهة المستخدم.
  • العقود الدقيقة: يجب الإعلان عن المتطلبات باستخدام العقود التي يتم التحقق منها في وقت الترجمة. لا يجب تجميع الفصل الدراسي إذا لم تكن راضياته الخاصة ، وكذلك تبعيات الضيوف غير راضية. تستخدم بنية RIBs ReactiveX لتمثيل تبعيات الضيف وأنظمة حقن التبعية الآمنة من النوع ( DI ) لتمثيل تبعيات الفصل والعديد من ميزات DI الأخرى للمساعدة في إنشاء ثوابت البيانات.

عناصر المكون RIBs


إذا كنت قد عملت سابقًا مع هندسة VIPER ، فستبدو الفئات التي يتكون منها RIB مألوفة لك. تتكون RIBs عادةً من العناصر التالية ، والتي يتم تنفيذ كل منها في فئتها الخاصة:



متفاعل


يحتوي الوسيط على منطق الأعمال. في هذه الفئة ، يتم الاشتراك في إشعارات Rx ، ويتم اتخاذ قرارات بشأن تغيير الحالة ، وتخزين البيانات وإرفاق RIBs التابعة.

يجب أن تقتصر جميع العمليات التي تتم في Interactor على دورة حياتها. أنشأت Uber مجموعة أدوات لضمان تنفيذ منطق الأعمال فقط مع التفاعل النشط. هذا يمنع تعطيل المتفاعلات ، لكن اشتراكات Rx لا تزال تعمل وتتسبب في تحديثات غير مرغوب فيها لمنطق الأعمال أو حالة واجهة المستخدم.

جهاز التوجيه


يراقب جهاز التوجيه الأحداث من Interactor ويحول هذه الأحداث إلى إرفاق وفصل RIBs التابعة. يوجد جهاز التوجيه لثلاثة أسباب بسيطة:

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

باني


مطلوب منشئ لإنشاء مثيلات لكافة الفئات المضمنة في RIB ، بالإضافة إلى إنشاء مثيلات من منشئي RIBs التابعة.

يضيف تسليط الضوء على منطق إنشاء الصف في Builder دعمًا للقدرة على إنشاء بذرة في iOS ويجعل بقية كود RIB غير حساس لتفاصيل تنفيذ DI. منشئ هو الجزء الوحيد من RIB الذي يجب أن يكون على بينة من نظام DI المستخدم في المشروع. من خلال تطبيق منشئ آخر ، يمكنك إعادة استخدام ما تبقى من كود RIB في المشروع باستخدام آلية DI مختلفة.

مقدم


المقدِّم هو فئة عديمة الحالة تترجم نموذج الأعمال إلى نموذج عرض تقديمي والعكس صحيح. يمكن استخدامه لتسهيل اختبار تحويلات عرض النموذج. ومع ذلك ، غالبًا ما تكون هذه الترجمة تافهة جدًا لدرجة أنها لا تبرر إنشاء فئة منفصلة للمقدم. إذا لم يتم تقديم المقدم ، فإن ترجمة نماذج العرض تصبح مسؤولية العرض (وحدة التحكم) أو المتفاعل.

عرض (وحدة تحكم)


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

مكون


يتم استخدام المكون لإدارة تبعيات RIB. يساعد المنشئ على إنشاء الطبقات الأخرى التي يتألف منها RIB. يوفر المكون الوصول إلى التبعيات الخارجية اللازمة لإنشاء RIB ، وكذلك التبعيات الخاصة به التي أنشأها RIB نفسه ، ويتحكم في الوصول إليها من RIBs الأخرى. عادة ما يتم تضمين مكون RIB الأصل في RIB-Builder التابع لتزويد RIB التابع بالوصول إلى تبعيات RIB الأصل.

إدارة الدولة


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



تتخذ RIBs قرارات الدولة فقط ضمن اختصاصها. على سبيل المثال ، يقوم LoggedIn RIB فقط باتخاذ قرار الانتقال بين حالات مثل Request و OnTrip. لا يتخذ أي قرارات بشأن ما يجب أن يكون عليه سلوك النظام عندما نكون على شاشة OnTrip.

لا يمكن حفظ جميع الحالات عن طريق إضافة RIBs أو إزالتها. على سبيل المثال ، عندما تتغير إعدادات ملف تعريف المستخدم ، لا يقوم RIB بالربط أو قطع الاتصال. كقاعدة ، نقوم بحفظ هذه الحالة داخل تدفقات النماذج غير القابلة للتغيير ، والتي تعيد إرسال القيم عند تغيير الأجزاء. على سبيل المثال ، يمكن تخزين اسم المستخدم في ملف ProfileDataStream ، والذي يقع ضمن اختصاص LoggedIn. ردود الشبكة فقط لديها حق الكتابة إلى هذا الدفق. نحن نقوم بتمرير واجهة توفر الوصول للقراءة إلى هذه المواضيع إلى الرسم البياني لـ DI.

لا يوجد شيء في RIBs هي الحقيقة المطلقة لحالة RIBs. هذا يتناقض مع حقيقة أن الأطر الأكثر إتقانًا مثل React يتم توفيرها بالفعل خارج الصندوق. في سياق كل RIB ، يمكنك اختيار الأنماط التي تسهل تدفق البيانات أحادية الاتجاه ، أو يمكنك ترك حالة منطق الأعمال وعرض الحالة تنحرف مؤقتًا عن القاعدة من أجل الاستفادة من أطر الرسوم المتحركة الفعالة للمنصة.

التفاعل بين RIBs


عندما يتخذ Interactor قرارًا منطقيًا للأعمال ، فقد يحتاج إلى إبلاغ RIB الآخر بالأحداث ، مثل إكمال البيانات وإرسالها. لا يتضمن إطار RIB أي طريقة واحدة لنقل البيانات بين RIBs. ومع ذلك ، تم تصميم هذه الطريقة لتسهيل بعض الأنماط الشائعة.

كقاعدة ، إذا انقطع الاتصال بالطفل RIB ، فإننا ننقل هذه المعلومات كأحداث في تدفق Rx. أو يمكن تضمين البيانات كمعلمة في طريقة build () التابعة لـ RIB التابع ، وفي هذه الحالة تصبح هذه المعلمة ثابتة لعمر الطفل.



إذا كان الاتصال يرتفع من شجرة RIB إلى RIP Interactor الأصل ، فإن هذا الاتصال يتم من خلال واجهة المستمع ، حيث يمكن أن يكون لـ RIB الأصل دورة حياة أطول من الطفل RIB. يقوم أحد RIB الأصل ، أو بعض الكائنات على الرسم البياني لـ DI الخاص به ، بتنفيذ واجهة مستمع ووضعه على الرسم البياني DI الخاص به بحيث يمكن لـ RIB التابعة له الاتصال به. إن استخدام هذا القالب لنقل البيانات في المنبع بدلاً من أن يكون لأصحاب RIBs المشتركين مباشرة في تدفقات Rx لأطفالهم RIBs له مزايا عديدة. يمنع تسرب الذاكرة ، ويسمح لك بكتابة واختبار والحفاظ على RIBs الأصلية دون معرفة أي طفل RIBs متصل بها ، ويقلل أيضًا من مقدار الضجة المطلوبة لإرفاق / فصل طفل RIB. لا تحتاج دفق Rx أو المستمعون إلى إلغاء التسجيل أو إعادة التسجيل باستخدام هذه الطريقة لإرفاق RIB طفل.



مجموعة أدوات RIB


لضمان التنفيذ السلس لبنية RIB في التطبيقات ، قام مهندسو Uber بإنشاء أدوات لتبسيط استخدام RIB واستخدام الثوابت التي تم إنشاؤها من خلال تنفيذ بنية RIB. كان رمز مصدر مجموعة الأدوات هذا مفتوحًا جزئيًا وتم ذكره في الأمثلة (راجع الجزء الأيمن - تقريبًا لكل.).

تتضمن مجموعة الأدوات المفتوحة المصدر حاليًا ما يلي:


مجموعة الأدوات التي تخطط أوبر لفتح مصدرها في المستقبل:

  • محلل ثابت لمنع تسرب الذاكرة المختلفة في RIB
  • تكامل RIB مع كاشف تسرب الذاكرة أثناء تنفيذ البرنامج
  • (Android) معالجات التعليقات التوضيحية لتسهيل الاختبار
  • (Android) محلل RxJava الثابت الذي يوفر لـ RIBs طرق عرض لم تتغير من سلسلة الرسائل الرئيسية

ملاحظة


نحن في sports.ru نحب حقًا نهج مهندسي أوبر ، لأن واجهنا عدة مرات جميع المشاكل المعمارية التي وصفها المقال. على الرغم من المعقولية ، فإن RIB لديه عدد من العيوب ، على سبيل المثال ، عتبة عالية إلى حد ما لدخول الهندسة المعمارية. سنحلل بمزيد من التفصيل إيجابيات وسلبيات الهندسة المعمارية في المقالات التالية ، حيث تم التخطيط لها على الأقل - لنظامي iOS و Android. بالنسبة لأولئك الذين يرغبون في الغوص في RIB في الوقت الحالي ، هناك عمود في صفحة ويكي على اليمين يحتوي على دروس في اللغة الإنجليزية. بمفردي ، ألاحظ أن الهندسة المعمارية ولدت بوضوح في مناقشات فنية طويلة وجمعت أفضل الممارسات لبناء معماريات لتطبيقات الهاتف المحمول المتوفرة حاليًا. وأخيرًا ، القليل من العلاقات العامة - نحن في sports.ru أيضًا نحب المناقشات الفنية ، وغالبًا ما نعقد ورش عمل فنية للزملاء ، ودراسة التقنيات الجديدة بانتظام ، وبشكل عام ، لدينا أجواء رائعة. لذا إذا كنت تريد أن تصبح جزءًا من فريقنا - مرحبًا !

Source: https://habr.com/ru/post/ar424305/


All Articles