مرحبًا ، اسمي Alexei Valyakin ، أنا أكتب تطبيقات Android. قبل بضعة أشهر ، تحدثت في اجتماع لفريق Yandex.Taxi مع مطوري الأجهزة المحمولة. تم تكريس تقريري للانتقال إلى بنية RIBs في سيارات الأجرة (يشير RIB إلى أفضل ثلاثة أجهزة توجيه و Interactor و Builder). هنا هو الفيديو ، وتحت القص - خلاصة:
- لقد حان الوقت للقفز قليلا في القطار مع الضجيج. هذا هو موضوع الكلاسيكية حول الهندسة المعمارية في الروبوت.
على محمل الجد ، أود اليوم أن أخبركم كيف ولماذا قمنا بتنفيذ هذه البنية ، وما الصعوبات التي واجهناها وكيف يمكن أن تساعدك.

عندما انضممت إلى الشركة ، كان فريقنا يتكون من أربعة أشخاص. بالفعل في تلك اللحظة كان لدينا عدد كبير من الصعوبات. كان المشروع قديمًا ، وقد بدأ في عام 2012. تم جمع بعض المشكلات الفنية ، واحدة منها هي CI مبني بشكل خاطئ ، والكثير من التباين في الأساليب والاختبارات التي لا تغطي كل شيء. وبشكل عام ، كان هناك عدد كبير من الصعوبات ودمج الصراعات.
خلال عامين ، نما عدد أفرادنا إلى 12 شخصًا ، مما يعني أننا قمنا بزيادة موازاة تطوير الميزات. وبالتالي ، هناك المزيد من تعارضات الدمج ، ومع وجود الكثير من تماسك الكود ، فأنت تفهم ما يمكن أن يؤدي إليه. في مرحلة ما ، بدأنا للتو في الغرق ، وبطريقة ما كان علينا أن نفهم ذلك. تم حل جزء من هذه المشكلات عن طريق إعادة هيكلة النقاط ، وجزء من مكتبة المكونات ، والتي تستحق الحديث عنها في تقرير منفصل.

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

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

MVP الكلاسيكية. ما هي التحديات التي نواجهها في MVP الكلاسيكية؟ إذا نظرنا إلى مثال مشروعنا ، فوجدنا أن هناك نشاط MVP أو MVP Fragment أو MVP View. وتبين تقلب كبير جدا في ما يحتاج إلى إضافته. في بعض الحالات ، تعتقد أنك بحاجة إلى إضافة طريقة عرض وشظية. ثم اتضح أن إضافة بعض الميزات الصغيرة التي يأتي بها المدير إليك أمر صعب للغاية ، لأنه يقع عمومًا في نشاط MVP منفصل.
تتعلق المشكلة الثانية التي تواجه MVP بحقيقة أن جهاز التوجيه يطرح. تريد توصيل الأطفال بمرونة وبالتالي يكون لديك نوع من الجوهر لهذا الغرض. لذلك ، عادةً ما تأتي MVPs في نوع من الموجهات ذاتية الصنع أو أي شيء آخر. والنهج الذي يحركه الرأي هو ناقص كبير جدا. في العديد من أنماط MVP ، يكون المقدم هو الذي يتم حقنه في العرض ، مما يجعله بالفعل أقل فاعلية وينتهك العمارة النظيفة.

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

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

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

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

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

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

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

لذلك ، يعد Builder مكونًا لرمز الغراء الكلاسيكي ، وتتمثل مهمته الرئيسية في تجميع كل شيء معًا ، وتجميع مكون Dagger و View. عادةً ما يقوم "العرض" بالاتصال بالبناء فقط ، ولا يوجد شيء معقد هناك. في بعض الحالات ، قد يكون تضخيم.

الجزء الثاني ، الموجود في Builder ، يدور حول الإدمان ، أي حول كيفية حصول الطفل على أي إدمان من الخارج.

يحتوي على واجهة Parent Component التي تحدد التبعيات التي يحتاجها. وبالتالي ، في منشئ المكون الفرعي ، يتم توفير جميع التبعيات التي يحتاجها من أعلاه.

Interactor هو في الأساس أهم فئة هي منطق الأعمال. الحقن فقط مسموح بها. هذا هو عمليا أهم شيء يتم اختباره. يتلقى حدثًا من طبقة واجهة المستخدم باستخدام أحداث Stream RX. مقدم العرض هو واجهة تحدد الطرق التي يوفرها الحدث الخاص بي.
ما هو مناسب أيضًا لمناطق الاستثمار الإقليمية؟ من خلال حقيقة أنه في طبقة المتفاعل والمقدم يمكنك تنظيم التفاعل الذي تريده. يمكن أن يكون MVP و MVVM و MVVI. كل شخص هنا حر في اختيار ما يحبه. قد يبدو الاشتراك في أحداث مقدم العرض شيئًا من هذا القبيل.

وهنا كيف تبدو معالجة هذه الأحداث.

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

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

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

بادئ ذي بدء ، تحتاج إلى دمج كل شيء في نقطة تنقل واحدة ، أولاً إنشاء كائن إله - موجه نشاط معين ، حيث ستتمكن أيضًا من إدارة مجموعة من الأجزاء ، لأنه سيكون لديك الكثير من التعليمات البرمجية القديمة. لن يسمح لك أحد بتنفيذ بنية جديدة طوال اليوم وإيقاف عمل تجاري. عند القيام بذلك ، سوف تحتاج إلى تكوين صداقات مع كومة من RIBs. تحتوي RIBs أيضًا بشكل طبيعي على كومة - يمكن الوصول إليها من أسفل الغطاء. ولكن ما هو المهم هنا؟ سيتعين علينا إكمال الكثير من التعليمات البرمجية. لا يدعم Uber دوران الشاشة ، لذلك لا يتعلق الأمر باستعادة الحالة. لذلك ، كان أول شيء كان علي فعله عندما بدأت في دراسة هذه البنية هو إضافة وريث على جهاز التوجيه ، والذي يدعم استعادة التسلسل الهرمي لـ RIBs وحالة التطبيق بالكامل.
ستحتاج إلى دعم ميزة التبديل. ليس هناك مشروع كبير واحد يمكن الاستغناء عنه. الآن واحد من المطورين لدينا هو تطوير مفهوم. إذا شاهد شخص ما Mobius 2016 ،
تحدثنا عن Plugin Factory على ذلك ، والذي يسمح لك بالاتصال وقطع كتل معينة من المنطق بشكل ديناميكي - وليس بالضرورة قطع مع شاشات. يمكن أن تعمل ، على سبيل المثال ، اعتمادًا على التجارب التي تأتي من الخادم. كل شيء يتم بشكل تجريدي ويتم تبسيط التفاعل.
يعد سير عمل RIBs مفهومًا مثيرًا للاهتمام قد تحتاجه. هذا عندما يكون لديك العديد من RIBs التي لا تعرف شيئًا عن بعضها البعض ، تكون في نفس المستوى تقريبًا ، ولكن في نفس الوقت تحتاج إلى بدء العملية بالبيانات عند الإدخال ، وفي النهاية عليك أن تضع كل شيء معًا.
وعلى سبيل المثال ، شاشات مشروط. لدينا تصميم مخصص للغاية ، لذلك لم يتبقى أي مربعات حوار تقليدية تقريبًا. كل شيء مكتوب ذاتيا ، علينا أن ننفذ كل شيء بأنفسنا.
ما الذي يمكنك الحصول عليه باستخدام RIBs؟ عزل الكود ، بنية بسيطة مفهومة ، طريقة سهلة للتطبيق ، التخلص من الشظايا ، نهج النشاط الفردي وراحة التطوير الموازي للميزات.
المراجع:
-
github.com/uber/RIBs-
github.com/uber/RIBs/tree/master/android/tutorials-
habr.com/ar/company/livetyping/blog/320452-
youtu.be/Q5cTT0M0YXg-
github.com/xzaleksey/Role-Playing-System-V2-
github.com/xzaleksey/DeezerSampleالرابط الأخير يؤدي إلى مشروعي الحيوانات الأليفة. منذ ستة أشهر ، بدأت في تطوير RIBs لتجربة هذه البنية قبل تقديمها لنا. وهناك حالات حقيقية أكثر أو أقل يمكن أن تساعدك. لقد جربت الكثير ، لذلك هناك أشياء مثيرة للجدل. ولكن بشكل عام ، يمكنك أن ترى كيف يعمل هناك. وربما من هناك سوف تأخذ شيئا لنفسك.
نفكر أيضًا في تخصيص كل هذا في مكتبة منفصلة ، كما فعلنا في عصرنا مع مكتبة المكونات. سيكون هناك مثل هذه الأضلاع ياندكس. لكن هذا في المستقبل. قلت لك كل شيء ، شكرا.