Reddit Mobile Architecture Evolution



هذه هي المقالة الأولى التي نتحدث فيها عن بنية تطبيق Reddit لنظام iOS. هنا نتحدث عن وظيفة تعمل بشكل أقرب إلى واجهة المستخدم. على وجه الخصوص ، الانتقال إلى بنية Model-View-Presenter (MVP). مزايا إعادة البناء هذه:

  • تحسين مرونة الشفرة ووضوحها وقابليتها للصيانة لدعم النمو المستقبلي وتسريع التكرارات.
  • زيادة أداء التمرير 1.58 مرة.
  • تحفيز اختبار الوحدة. زاد عدد الاختبارات من عدد قليل إلى أكثر من 200.

فيما يلي رسم تخطيطي لهندسة الطبقات. ستركز المقالة الأولى على مستويات العرض والمقدم.


المنظر النهائي لهندستنا الطبقية

متطلبات التغيير


منذ أكثر من عام ، نشرنا مقالة "بناء شريط في تطبيق Reddit iOS" . وناقش كيفية إنشاء خلاصة منتجة وقابلة للتوسيع بمعدل جلسة 99.95 ٪ رائع بدون تعطل. شرحنا كيفية استخدام بنية Model-View-Controller (MVC) وإنشاء ملخصات لبيانات الترحيل.

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

جوهر المشكلة


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

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

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

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

الانتقال إلى أفضل لاعب


قررنا أنه لحل المشاكل المذكورة أعلاه ، يلزم إصدار جديد من التطبيق. بعد النظر في العديد من الخيارات ، قررنا استخدام بنية Model-View-Presenter (MVP). يستوفي MVP جميع هذه المعايير ، وهي بنية معروفة وموثقة ، لذا من الأسهل تدريب المهندسين. كما يحتفظ بمفهوم "عرض النماذج". إذا لزم الأمر ، في Presenter ، يمكنك إنشاء كائنات نموذج عرض على مبدأ المسؤولية وحدها - واستخدامها لتوسيع آرائنا.


مخطط عرض نموذج مقدم العرض

التخلص من Massive View Controller


بالنسبة لتطبيقات iOS ، من المفترض أن كائنات العرض هي فئات فرعية من UIView ، وكائنات وحدة التحكم هي فئات فرعية من UIViewController ، وكائنات النموذج هي كائنات رأسية بسيطة. كما يوحي الاسم UIViewController ، هنا يتم الجمع بين العرض وجهاز التحكم في كائن واحد. أي أن نموذج MVC على iOS غالبًا ما يفقد مزاياه بسبب الاتصال المحكم بين مستوى العرض وجهاز التحكم. ومن المثير للاهتمام أن شركة Apple نفسها تعترف بهذا الاتصال .


غالبًا ما تتحول بنية Model-View-Controller لنظام iOS إلى

في بنية MVP ، نأخذ هذا المفهوم بعين الاعتبار ونقوم بإضفاء الطابع الرسمي عليه ، مع مراعاة UIViewController ككائن صريح في طبقة العرض التقديمي. أصبح مفهوم التعامل مع UIViewController ككائن عرض تقديمي يحمل اسمًا سيئًا شائعًا في السنوات الأخيرة.

لذا ، نقوم بإزالة جميع المنطق الدخيل في UIViewControllers. ثم نعين المقدِّم للوسيط بين العرض والنموذج. في هذا الدور الجديد ، لا يدرك كائنات العرض مثل UIViewController. لاحظ أن مقدم العرض يتفاعل مع العرض من خلال واجهة. من الناحية النظرية ، يمكنك تغيير تنفيذ طريقة عرض إلى NSViewController (لنظام MacOS) ، إلخ.


نجعل ViewController أسهل من خلال تقديم العارض والمشاركة في المسؤوليات

التفكير في خيارات MVP


كما ترى في مخطط MVP ، جاءت البنية مشابهة جدًا لـ MVC. في الواقع ، هناك أوجه تشابه أكثر من الاختلافات. تساعد هذه البنية ببساطة على إنشاء الفصل الصحيح بين كود العرض ومنطق الأعمال الذي تسعى إليه MVC. في الواقع ، جميع مشتقات بنية MV (x) ، مثل MVP و MVVM و MVAdapter وغيرها ، هي ببساطة إصدارات مختلفة من نفس المفهوم.

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

تحسين المرونة والاستدامة والوضوح


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

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

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


تبسيط التسلسل الهرمي للميراث من خلال التكوين

تغيير مجاني في تنفيذ طبقة العرض التقديمي


كما تمت مناقشته سابقًا ، بدأ أداء تمرير الشريط في الانخفاض من 60 إطارًا في الثانية إلى 45-55 إطارًا في الثانية. لذلك ، بالنسبة لطبقة عرض الشريط ، قررنا استخدام Texture . إنه نظام أساسي قائم على Apple UIKit مفتوح المصدر يعمل على تحسين أداء الواجهة من خلال المعالجة المسبقة في مؤشر ترابط الخلفية. في بنية MVC السابقة ، لم نتمكن من تغيير تنفيذ طبقة العرض التقديمي بدون الكثير من تكرار التعليمات البرمجية.


قبل تنفيذ MVP ، كان عليك نسخ كود غريب في ViewController لم يكن مرتبطًا بـ View (برتقالي)

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


بعد تنفيذ MVP: تم نقل رمز عدم العرض إلى المقدم المشترك

ما هي النتيجة؟ يوضح الرسم البياني أدناه زيادة في أداء تمرير الشريط. أردنا البقاء حوالي 60 إطارًا في الثانية من أجل تحقيق التمرير السلس تمامًا.



اختبار الوحدة


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


زيادة منطقة الاختبار بعد نقل رمز غير عرض خارج هذه الطبقة

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

تحليل نقدي لـ MVP في Reddit


على الرغم من أن التحول إلى MVP قد ساعد كثيرًا ، إلا أنه لا يزال هناك بعض الأشياء التي يجب مراعاتها.

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

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

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


في بعض الأحيان يمكنك التبديل من طبقة عرض إلى طبقة RedditCore بدون مقدم

في الواقع ، لم يتم تحويل تطبيقنا بالكامل إلى بنية MVP. أولاً ، تحويل كل UIViewController إلى مقدم عرض سوف يستغرق وقتًا طويلاً - وليس تطوريًا. ثانيًا ، كما ذكر في الفقرة السابقة ، أحيانًا لا تكون هناك حاجة إلى مقدم العرض. كما وجدنا في عملنا على تنفيذ Texture for Ribbon ، يعد مقدم العرض رائعًا لتسهيل MVC الضخمة أو لتنفيذ طريقة العرض بسلوك متغير ، أو إذا كان لديك منطق معقد يحتاج إلى التحقق. ولكن في بعض الأحيان يكون UIViewController بسيطًا جدًا لدرجة أن المقدم لا معنى له. لذا فهو اختياري. يجب تقديم مقدم العرض فقط إذا لزم الأمر.

الملخص والخطط المستقبلية


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

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

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


All Articles