قضايا العمارة في المشاريع الكبيرة

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


النظر في 5 مواضيع مهمة. بالطبع ، تمت مناقشة معظمها في المجتمع أكثر من مرة ، ولكن وراء كل موضوع هي الألم والدموع وضياع الوقت ، والأهم من ذلك ، التجربة التي كانت مفيدة لنا ، وآمل أن تكون مفيدة لك.


صورة


في بداية تطوير تطبيق الهاتف المحمول ، يواجه القائد أو المصمم السؤال - ما النمط المعماري الذي يجب استخدامه؟ لدينا الاستوديو لديه النمط المعماري المشترك MVP. إن MVP Pure جيد بالتأكيد في شكله النقي (انظر الصورة أدناه) ، لكننا لن نكون مطورين حقيقيين إذا لم نقم بوضع اللمسات الأخيرة على هذا النمط. لم يتوقفوا عن خيار واحد ، وحصلنا على فرعين من MVP النقي.


صورة


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


دعونا نلقي نظرة على اثنين من MVPs لدينا على المنشطات.


SurfMVP


صورة


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


صورة


الميزة الرئيسية لـ SurfMVP هي أن كل طبقة في MVP مفصولة بواسطة بروتوكول. تُظهر الصورة مخططًا للطبقات وعلاقة البروتوكولات بينها. هناك حاجة إلى بروتوكولات بحيث يتم فصل كل طبقة عن الأخرى ومن الناحية النظرية يتم استبدالها بسهولة. يجب ألا تكشف كل طبقة عن تفاصيل التنفيذ.


لننظر فيها بشكل منفصل:


ViewInput - ينفذ عرض نفسه ، مقدم يحافظ على الارتباط. يصف هذا البروتوكول الطرق التي يمكن بها لمقدم العرض التحكم في طريقة العرض ، ونقل البيانات ، وتغيير الحالات ، وما إلى ذلك.


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


RouterInput - ينفذ Router ، ويحافظ مقدم العرض على رابط إليه ، لأنه المسؤول الوحيد عن بدء التنقل الإضافي في التطبيق.


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


ModuleInput - تنفذ مقدم . يجب أن يحتوي هذا البروتوكول على طرق يمكن بها لتغيير وحدة نمطية حالية وحدة أخرى تحتوي على رابط لهذا البروتوكول.


ModuleOutput - تنفذ مقدم وحدة الاتصال ، يحمل الرابط مقدم الوحدة النمطية المدعوة. إذا كان من الممكن عرض شاشة ملف التعريف من وحدة الأخبار ، فيجب أن يقوم تطبيق NewsPresenter بتطبيق ProfileModuleOutput ، ويجب أن يحتوي ProfilePresenter على رابط إليها.
يتم تمرير ModuleOutput إلى Configurator الخاص بالوحدة النمطية وتثبيته في مقدم العرض . يحتوي على أساليب الوحدة النمطية التي تؤثر على سلوك وحدة الاستدعاء.


SurfMVP مشكلة


استنادا إلى كل ما سبق ، هناك مشكلة رئيسية واحدة - الملاحة. على الرغم من أن رسالة تمييز كيان جهاز توجيه منفصل كانت مشكلات في التنقل ، كما اتضح فيما بعد ، فقد اختفت ، ولكن ليس لفترة طويلة. لقد تم استخدام SurfMVP بنجاح في المشروعات ذات التنقل المسطح البسيط ، بدون DeepLinks و Push-Notifications المعقدة.


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


صورة


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


صورة


تبدأ المشاكل في الوقت الحالي عندما يكون من الضروري نقل المستخدم من النقطة A إلى النقطة D ، وهذا يجب أن يحدث دون مشاركته. على سبيل المثال ، إذا نقر المستخدم على Push-Notification أو اتبع رابطًا من تطبيق تابع لجهة خارجية. في حالة SurfMVP ، سيتعين علينا إضافة جهاز توجيه عالمي يتحكم في التنقل بغض النظر عن مكان وجود المستخدم حاليًا في التطبيق. لحل هذه المشكلة على المستوى العالمي ، قررنا استخدام المنسقين ، دعنا ننتقل إليهم.


صورة


SurfMVP المنسقة


صورة


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


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


في منسق SurfMVP ، استبدل كيان الموجه كيان المنسق ، وهو الآن المسؤول عن التنقل ليس فقط وحدة واحدة منفصلة ، ولكن مجموعة من الوحدات النمطية التي ترتبط منطقيا مع بعضها البعض. هذا يبسط التنقل والعمل مع التطبيق. بشكل تخطيطي ، يبدو تطبيقنا كما يلي:


صورة


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


إذا كان لدينا Deeplinks أو Push-Notifications في تطبيقنا ، فيمكننا دائمًا تعيين قواعد التهيئة وبدء التنسيق للمنسقين حتى يتمكنوا من بناء المكدس مباشرةً على النقطة D المطلوبة ، والتي تحدثنا عنها سابقًا.


صورة


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


إيجابيات وسلبيات منسق SurfMVP


المزايا:


  1. الميزة الرئيسية لنهج المنسق هي القدرة على إعادة استخدام كتل التنقل بأكملها داخل التطبيق. الآن ، من أي مكان في التطبيق ، من الممكن استدعاء هذا المنسق وعدم التفكير في أي شيء آخر غير إكمال عمله.
  2. نظرًا لأن منطق التنقل معزول داخل منسق منفصل ، فقد أصبح الآن أكثر ملاءمة لمتابعة التنقل: ما عليك سوى فتح ملف واحد والصورة الكاملة أمام عينيك. لم تعد هناك حاجة إلى اختراق جميع الوحدات الفردية من أجل فهم ما يتم الوصول إليه وتجميع التطبيق وإلقاء نظرة على التصميم.
  3. هو أكثر ملاءمة للتصميم في فرق كبيرة. يكفي في مرحلة التصميم لميزة جديدة منفصلة أن تأخذ الوقت الكافي لبناء التنقل بأكمله وتهيئة جميع الوحدات ، ثم تفويض التطوير لعدد كبير من المطورين ، وستكون هناك مشاكل أقل بكثير في تكامل هذه الشاشات بين بعضها البعض.
  4. لم يعد دمج Deeplinks و Push-Notifications بمثابة صداع.

العيوب:


كما هو الحال مع أي منهج معماري ، هناك جوانب سلبية للتنسيق SurfMVP.


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

حالة نموذجية

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


  func runAuthFlow() { let coordinator = AuthCoordinator(router: MainRouter()) coordinator.finishFlow = { [weak self, weak coordinator] in self?.removeDependency(coordinator) } self.addDependency(coordinator) coordinator.start() } 

النتائج


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


متى يجب استخدام منسق SurfMVP


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


  • هيكل الشاشات معقد وقابل للتغيير ؛
  • هناك Deeplinks و / أو دفع الإخطارات مع الملاحة.
  • لديه للعمل في فريق كبير.

متى تستخدم SurfMVP


لم ننس النمط المعماري الأول لدينا. لا نزال نستخدمه في الاستوديو عند تطوير المشاريع إذا كان يفي بالشروط التالية:


  • المشروع صغير بما فيه الكفاية ولا يخطط للتطور بسرعة ؛
  • يحتوي المشروع على بنية شاشة بسيطة للغاية ، ولا يخضع لتغييرات قوية.

مواد إضافية



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

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


All Articles