دليل بنية التطبيق

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

تجارب المستخدمين في تطبيقات الأجهزة الجوّالة

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

أشكال أجهزة متعدّدة

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

قيود الموارد

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

شروط إطلاق المتغيّر

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

المبادئ المعمارية الشائعة

إذا كان من غير المفترض استخدام مكوّنات التطبيق لتخزين بيانات التطبيق وحالته، كيف يمكن تصميم تطبيقك بدلاً من ذلك؟

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

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

فصل الاهتمامات

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

يُرجى العِلم أنّك لا تملك عمليات تنفيذ Activity وFragment، بل هي مجرد فئات ربط تمثّل العقد بين نظام التشغيل Android وتطبيقك. ويمكن لنظام التشغيل إتلافها في أي وقت استنادًا إلى تفاعلات المستخدم أو بسبب ظروف النظام، مثل انخفاض الذاكرة. لتقديم تجربة مستخدم مرضية وتجربة صيانة أكثر سهولة للتطبيق، من الأفضل تقليل اعتمادك عليها.

التنسيقات التكيّفية

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

إنشاء واجهة مستخدم من نماذج البيانات

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

تُعدّ النماذج الثابتة مثالية للأسباب التالية:

  • لا يفقد المستخدمون البيانات إذا دمّر نظام التشغيل Android تطبيقك لإتاحة المزيد من الموارد.

  • يستمر تطبيقك في العمل في الحالات التي يكون فيها اتصال الشبكة غير مستقر أو غير متاح.

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

مصدر واحد للحقيقة

عند تحديد نوع بيانات جديد في تطبيقك، عليك تعيين مصدر واحد للحقيقة (SSOT) له. يكون نظام SSOT هو المالك لهذه البيانات، ولا يمكن لأي نظام آخر تعديلها أو تغييرها. لتحقيق ذلك، تعرض SSOT البيانات باستخدام نوع غير قابل للتغيير، ولتعديل البيانات، تعرض SSOT دوال أو تتلقّى أحداثًا يمكن أن تستدعيها أنواع أخرى.

يوفّر هذا النمط مزايا متعدّدة:

  • ويؤدي ذلك إلى تركيز جميع التغييرات على نوع معيّن من البيانات في مكان واحد.
  • ويحمي البيانات حتى لا تتمكّن الأنواع الأخرى من التلاعب بها.
  • تسهّل تتبُّع التغييرات التي يتم إجراؤها على البيانات. وبالتالي، يسهل رصد الأخطاء.

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

تدفّق البيانات أحادي الاتجاه

يتم غالبًا استخدام مبدأ المصدر المرجعي الوحيد في أدلتنا مع نمط "تدفّق البيانات أحادي الاتجاه" (UDF). في الدوال المعرَّفة من قِبل المستخدم، يتدفق الحالة في اتجاه واحد فقط. الأحداث التي تعدّل تدفّق البيانات في الاتجاه المعاكس

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

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

يوضّح هذا القسم كيفية تنظيم تطبيقك وفقًا لأفضل الممارسات المقترَحة.

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

  • طبقة واجهة المستخدم التي تعرض بيانات التطبيق على الشاشة
  • طبقة البيانات التي تحتوي على منطق النشاط التجاري لتطبيقك وتعرض بيانات التطبيق

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

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

بنية التطبيقات الحديثة

تشجّع بنية التطبيقات الحديثة على استخدام الأساليب التالية، من بين أساليب أخرى:

  • بنية متكيّفة ومتعدّدة الطبقات
  • تدفّق البيانات أحادي الاتجاه (UDF) في جميع طبقات التطبيق
  • طبقة واجهة مستخدم تتضمّن عناصر الاحتفاظ بالحالة لإدارة تعقيد واجهة المستخدم
  • الروتينات المشتركة وتدفّقات البيانات
  • أفضل ممارسات إدخال التبعية

لمزيد من المعلومات، راجِع الأقسام التالية وصفحات "البنية" الأخرى في جدول المحتويات وصفحة الاقتراحات التي تتضمّن ملخّصًا لأهم أفضل الممارسات.

طبقة واجهة المستخدم

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

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

  • عناصر واجهة المستخدم التي تعرض البيانات على الشاشة يمكنك إنشاء هذه العناصر باستخدام الدوال الخاصة بـ Views أو Jetpack Compose. تتيح كلّ من "طرق العرض" وJetpack Compose استخدام التصاميم التكيُّفية.
  • عناصر الاحتفاظ بالحالة (مثل فئات ViewModel) التي تحتفظ بالبيانات وتعرضها على واجهة المستخدم وتتعامل مع منطق التطبيق
في بنية نموذجية، تعتمد عناصر واجهة المستخدم في طبقة واجهة المستخدم على عناصر الاحتفاظ بالحالة، والتي تعتمد بدورها على الفئات من طبقة البيانات أو طبقة النطاق الاختيارية.
الشكل 2. دور طبقة واجهة المستخدم في بنية التطبيق

لمزيد من المعلومات عن هذه الطبقة، اطّلِع على صفحة طبقة واجهة المستخدم.

طبقة البيانات

تحتوي طبقة البيانات في التطبيق على منطق النشاط التجاري. منطق النشاط التجاري هو ما يمنح تطبيقك قيمته، وهو يتألف من قواعد تحدّد كيفية إنشاء تطبيقك للبيانات وتخزينها وتغييرها.

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

في بنية نموذجية، توفّر مستودعات طبقة البيانات البيانات لبقية التطبيق وتعتمد على مصادر البيانات.
الشكل 3. دور طبقة البيانات في بنية التطبيق

تكون فئات المستودع مسؤولة عن المهام التالية:

  • عرض البيانات لبقية التطبيق
  • تجميع التغييرات التي تطرأ على البيانات
  • حلّ التعارضات بين مصادر البيانات المتعددة
  • تجريد مصادر البيانات من بقية التطبيق
  • يحتوي على منطق النشاط التجاري.

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

لمزيد من المعلومات عن هذه الطبقة، يُرجى الاطّلاع على صفحة طبقة البيانات.

طبقة النطاق

طبقة النطاق هي طبقة اختيارية تقع بين طبقتَي واجهة المستخدم والبيانات.

طبقة النطاق مسؤولة عن تغليف منطق النشاط التجاري المعقّد أو منطق النشاط التجاري الأبسط الذي يتم إعادة استخدامه من خلال عدة ViewModels. هذه الطبقة اختيارية لأنّ بعض التطبيقات لا تتضمّن هذه المتطلبات. يجب استخدامها فقط عند الحاجة، مثلاً للتعامل مع التعقيد أو تفضيل إعادة الاستخدام.

عند تضمينها، توفّر طبقة النطاق الاختيارية التبعيات لطبقة واجهة المستخدم وتعتمد على طبقة البيانات.
الشكل 4. دور طبقة النطاق في بنية التطبيق

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

لمزيد من المعلومات عن هذه الطبقة، اطّلِع على صفحة طبقة النطاق.

إدارة التبعيات بين المكوّنات

تعتمد الفئات في تطبيقك على فئات أخرى لتعمل بشكل سليم. يمكنك استخدام أحد نمطَي التصميم التاليَين لجمع التبعيات الخاصة بفئة معيّنة:

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

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

أفضل الممارسات العامة

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

على الرغم من أنّ الاقتراحات التالية ليست إلزامية، إلا أنّ اتّباعها في معظم الحالات يجعل قاعدة الرموز البرمجية أكثر قوة وقابلة للاختبار والصيانة على المدى الطويل:

لا تخزِّن البيانات في مكوّنات التطبيق.

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

تقليل الاعتماد على فئات Android:

يجب أن تكون مكوّنات تطبيقك هي الفئات الوحيدة التي تعتمد على واجهات برمجة التطبيقات لحزمة تطوير البرامج (SDK) الخاصة بإطار عمل Android، مثل Context أو Toast. يساعد تجريد الفئات الأخرى في تطبيقك من هذه الفئات على إمكانية الاختبار ويقلّل من الربط داخل تطبيقك.

تحديد حدود واضحة للمسؤولية بين الوحدات في تطبيقك:

على سبيل المثال، لا توزّع الرمز الذي يحمّل البيانات من الشبكة على عدة فئات أو حِزم في قاعدة الرموز البرمجية. وبالمثل، لا تحدّد مسؤوليات متعدّدة غير ذات صلة، مثل تخزين البيانات مؤقتًا وربط البيانات، في الفئة نفسها. سيساعدك اتّباع بنية التطبيق المقترَحة في تحقيق ذلك.

عرض أقل قدر ممكن من كل وحدة

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

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

لا تعِد اختراع العجلة من خلال كتابة رمز نموذجي نفسه مرارًا وتكرارًا. بدلاً من ذلك، ركِّز وقتك وجهدك على ما يميّز تطبيقك، واترك مكتبات Jetpack والمكتبات الأخرى المقترَحة تتولّى معالجة الرموز النموذجية المتكرّرة.

استخدام التنسيقات الأساسية وأنماط تصميم التطبيقات:

توفّر مكتبات Jetpack Compose واجهات برمجة تطبيقات قوية لإنشاء واجهات مستخدم متكيّفة. استخدِم التصاميم الأساسية في تطبيقك لتحسين تجربة المستخدم على عوامل شكل وأحجام عرض متعددة. راجِع معرض أنماط تصميم التطبيقات لاختيار التنسيقات الأنسب لحالات الاستخدام.

فكِّر في كيفية إتاحة اختبار كل جزء من تطبيقك بشكل منفصل.

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

تكون الأنواع مسؤولة عن سياسة التزامن.

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

الاحتفاظ بأكبر قدر ممكن من البيانات الحديثة وذات الصلة:

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

مزايا الهندسة المعمارية

يوفّر تنفيذ بنية جيدة في تطبيقك العديد من المزايا لفريقَي المشروع والهندسة:

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

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

نماذج

توضّح نماذج Google التالية بنية التطبيق الجيدة. يمكنك الاطّلاع عليها للاطّلاع على هذه الإرشادات عمليًا: