اركتت تطبيقات الجوال

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

لن اتحدث عن تقنية او لغة معينة لكن عن الـ architecture عامة  و التي من الممكن تطبيقها حتى على مشاريع الويب لكنها أكثر مناسبة لتطبيقات سطح المكتب و الموبايل. يمكن أن تطبق على ال native mobile application و حتى Flutter و Xamarin و Ionic و غيرها. كذلك لن اتطرق إلى “كيف” فذلك يحتاج لكتاب او ملزمة على الأقل لكن سأحاول أن ابين الفائدة من وراء استخدام هذا النمط او ذاك ويمكن للقاريء البحث عن طريقة ال Implementation حسب التقنية و اللغة التي تستخدمها

من اشهر أنماط التصميم المستخدمة في بناء التطبيقات هي ال MVVM و تطبيقه ليس بمجرد ان اقسم التطبيق إلى View و ViewModel و Model فعلينا أن نعرف ماذا سنضع و أين ؟ و حيث ستظهر أسئلة مثل أين اضع الValidation ؟ و اين اضع الية التعامل مع الAPI او قواعد البيانات و كيف ادير الNavigation و البيانات الخاصة بال Configuration و ال Authentication و الAuthorization و غيرها.

دائماً كلما كانت اجزاء التطبيق منفصلة كلما سهل التطوير و الصيانة و الإختبار و يمكن أن يكون هناك فريق

من المطورين يعملون على جزئية معينة في التطبيق و هذا ما يوفره لنا الـ Dependency Injection و التي تجعل الربط في الRunTime بدل الكود.

تعلّم هذه الأشياء يحتاج جهد و يأتي من خلال العمل على محاولة تطبيقه في مشروع حقيقي , قد يكون صعباً و محبطاً في البداية لكن ما أن يكتمل مشروع واحد حتى يصبح هذا المشروع مرجعاً لك في مشاريعك الجديدة.

لنتكلم عملياً :

حسب ال MVVM سنحتاج على الأقل إلى ثلاثة مجلدات View تضع فيه الملفات الخاصة بالشاشات و مجلد Model نضع فيه الكلاسات الخاصة بشكل البيانات و ViewModel الذي سيكون به الBusiness Logic

المفترض حسب الـ MVVM ان الView يعتمد فقط على ال ViewModel و الViewModel على الModel و اللي بدوره يبلغ الViewModel باي تغيير حصل عليه و ViewModel بدوره يبلغ الView.

الView

الView لن يحتوي أي اكواد تتعلق بال Business Logic إلا اذا كان شي يتعلق بالشاشة نفسها مثل الValidation البسيط على المدخلات كالحد الأقصى لطول حقل معين أو نوع البيانات التي تدخل من حيث رقم او حرف او صحة ايميل او مثلاً قد يحوي كود لعرض البيانات بشكل معين. لكن البيانات يفضل ان تكون مربوطة من خلال آلية Binding تجعل الView يكون Binded للViewModel الخاص بها حتى في موضوع إخفاء او اظهار جزء منها في الشاشة بالإضافة إلى دور الBinding  في استقبال نشاط المستخدم و تفاعله مع الشاشة.

الViewModel

الViewModel اشبه بالController في الMVC. يعرض بيانات الModel للView مباشرة او يقوم بتعديلها بما يتناسب مع الشاشة , هذا غير ان الViewModel بياناته بتكون كما ذكرنا Bindable للView , اي تغيير يتم على ال Model ينعكس مباشرة على الView و العكس. لكن الModel قد تكون مجرد Plain Objects. و بما ان الObjects في الViewModel  كما ذكرنا Bindable فيمكن ان نجعلها ترسل Event اذا تغيرت و اعتماداً على ذلك التغيير يقوم الViewModel بدوره كمسؤول عن الـ Navigation بين الشاشات.

الModel

الModel مهمته الاحتفاظ و حماية الObject الخاصة بالداتا سواء الأساسية التي تتعلق بالDomain أو التي يرسلها او يتلقاها من الويب سيرفس كـDTOs. 

لكن ايضا نحتاج إلى مجلدات اخرى.

أول مجلد بيكون ال Services و فيه  الكلاسات المسؤولة عن إحضار او ارسال البيانات من و إلى قواعد البيانات او الAPI و بيكون لها Interface نتمكن من حقنها في الـ Constructor الخاصة بالViewModel من خلال عملية ال Dependency Injection. و سنحرص دائماً على التخاطب مع قاعدة البيانات او الAPI الاخرى من خلال استدعائها بطريقة Async حتى لا تجعل تطبيقك “يعلّق” مثلاً أثناء قراءة البيانات او إرسالها. يستحسن اذا كان تطبيقك فيه اكثر من جزئية مثل Orders أو Products أن تنشيء مجلد فرعي داخل مجلد ال Services يحتوي ملفين على سبيل المثال IOrderService و OrderService

الAPI معرضة لأن تكون هي او قاعدة البيانات ورائها خارج الخدمة , لا تكتفي بالقراءة او الكتابة مرة واحدة قبل أن تخبر المستخدم بوجود مشكلة , حاول 3 مرات على الاقل. هذا يسمى ال Resilience

من خلال ال retry pattern وايضا هناك نمط آخر يسمى circuit breaker pattern يعتمد على احصائيات الفشل بحيث تمنع على اثرها المستخدم من استدعاء بعض الخدمات التي تتوقع أن تفشل 

المجلد الثاني Configuration لأنك أغلب الأحيان سنقرأ من عدد محدود من الـ API شبه ثابته فيفضل أن تحتفظ بعنوان تلك ال APIs في مخزن لل Configurations الشبيهه. بحيث اذا احتجت الى تغييرها فلن تحتاج إلى تتبعها في كل أجزاء البرنامج.

و يمكنك بسهولة التغيير من بيئة التجربة إلى بيئة الى UAT وصولاً الى بيئة التشغيل او الProduction 

و يمكن لتحقيق ذلك عمل كلاس باسم Settings مثلا و تخزين البيانات في ملف نصي.

المجلد الثالث لل Caching و هو للتعامل مع البيانات التي لا تتغير أو تتحدث دائماً مثل اسماء الدول او المدن. هذه التقنية ستوفر عليك الكثير من الحَمل على الAPI و قواعد البيانات و تقلل التكاليف إن احسنت استخدامها إلى 90% في بعض الحالات.

ايضا هناك مجلدات أخرى لأشياء مثل الـ Authentication اغلب التطبيقات الكبيرة تعتمد على بروتوكول ال OAuth 2.0 عبر مكتبة مثل OpenID Connect المبنية على ذلك البروتوكول . بحيث يطلب منها العميل  Token و يستخدم هذا الToken في التعامل مع الـ API

وعليه ايضاً تحدد الصلاحيات Authorization من حيث اي من ال Methods يمكنه التعامل معها.

ال Validation مهم في أي تطبيق , و هو للتحقق من ان البيانات المدخلة من قبل المستخدم صحيحة و ان لا يكون هناك بيانات مدخلة بغرض الاختراق!. جزئية الValidation قد تكون في الModel للتأكد ان البيانات تحقق المطلوب و يمكن أن تكون في الView للأشياء البسيطة مثل التحقق من صحة الإيميل أو رقم الهاتف كما ذكرنا سابقاً و ممكن أن تكون في ال ViewModel إذا كان التحقق يختص بالBusiness Logic او يحتاج للتعامل مع API. ايضاً هنا تستطيع توحيد آلية لإبلاغ المستخدم بالأخطاء

التنقل بين الشاشات او ما يسمى بالـ Navigation يفضل ان يكون Service ايضاً بحيث يمكنك اضافة اشياء مثل ال Logging لتتبع نشاط المستخدم و توحيد طريقة استقبال ال Parameters .  و لتكن هناك نسخة واحدة من هذا الكلاس Singleton تدير عمليات التنقل تلك عبر الViewModel بدل ان تربط زر معين في View مباشرة مع شاشة اخرى قد تغيرها لاحقاً.

شيء مهم آخر وهو كيف تتراسل و تتواصل اجزاء التطبيق مع بعضها , من الأفضل أن يكون آلية تعزز مفهوم ال decoupling و نستفيد من الMVVM مثل الاعتماد على ال publish-subscribe pattern بحيث لو تغيرت قيمة في الViewModel تنعكس مباشرة على الView دون الحاجة إلى عمل Refresh للشاشة. ايضا يمكن لأي ViewModel ان يقوم بعمل Subscribe لـ  ViewModel اخر. فمثلاً لو ضغط المستخدم على زر Add لمنتج معين تقوم ال ViewModel بإرسال رسالة تستفيد منها ال ViewModel الخاصة باحتساب الفاتورة. و هنا يمكن ان نستخدم الCommand Pattern احد ال Design Patterns بحيث نفصل المستدعي او الطالب من الاستدعاء او الطلب و نستطيع استخدام الCommand اكثر من مرة

ما سبق ليس خاصاً بتطبيقات الجوال بل مع اي تقنية بها Code Behind مثل ASP القديمة و الـ Windows Forms و الWPF

بالنسبة للـ Backend تحتاج مقالة أخرى مستقلة و لكن بدون الدخول في التفاصيل  فال Microservices تحميك في حالة التوسع Scalability بحيث انك لا تضع حِمل زائد على ما هو موجود لديك بتقسيم التطبيق الى اقسام اصغر بالإضافة إلى فوائدها الأخرى

مثل اختصاص كل جزء بتقنياته و قواعد بياناته الأنسب له و تقسيم الفريق بحيث يتخصص في ادارة هذه الجزئية الخ

الطريقة الشائعة هي التعامل مع الAPI لكل Microservice على حدة لكن هناك طريقة افضل خصوصا اذا كان عدد الطلبات كبير جداً و هو من خلال Event Bus بحيث أن التطبيق يرسل رسائل لل Event Bus ثم تقوم الMicroservice بعمل Subscribe للرسائل التي تهمها منه و ترسل رسائل مرة اخرى ليقرأها التطبيق. و هنا سيكون اتصالك من التطبيق عبر AMQP و ليس HTTP او TCP اما بين ال Microservices فيما بينها سيكون عادة REST اي HTTP و ممكن يكون العكس

ان يتواصل التطبيق عبر API و تتواصل الMicroservices مع بعضها عبر Event Bus.

من الأفضل دائماً او حتى من الضروري هنا أن تبدأ بـUnit Testing لأن تطبيقات الجوال تختلف عن تطبيقات الويب و سطح المكتب من حيث تعدد موديلات الهواتف فتحتاج للتأكد من أنها تعمل  بشكل صحيح على الأجهزة المختلفة و تحتاج لاختبار ال Integration و ال UI.

مبدأ الUnit Testing يعتمد على تجزئة التطبيق إلى وحدات صغيرة Unit و تقوم باختبار كل وحدة منفصلة مع كل تعديل للتأكد ان التعديل يعمل و لم يؤثر على اي جزء اخر و ستختبر Validation وال Messaging و Events و الException Handling وحتى العمليات التي يقوم بها التطبيق Asynchronous .