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

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

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

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

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

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

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

قيود الموارد

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

شروط تفعيل المتغيّرات

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

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

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

مع زيادة حجم تطبيقات Android، من المهم تحديد بنية تتيح توسيع نطاق التطبيق. تحدّد بنية التطبيق المصمَّمة جيدًا الحدود بين أجزاء التطبيق والمسؤوليات التي يجب أن يتحمّلها كل جزء.

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

صمِّم بنية تطبيقك وفقًا لبعض المبادئ المحدّدة.

المبدأ الأهم هو فصل الاهتمامات. من الأخطاء الشائعة كتابة كل الرمز في Activity أو Fragment.

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

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

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

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

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

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

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

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

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

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

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

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

يقدّم هذا النمط مزايا متعددة:

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

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

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

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

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

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

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

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

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

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

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

تستخدم بنية تطبيقات Android الحديثة الأساليب التالية (من بين أساليب أخرى):

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

لمزيد من المعلومات، يُرجى الاطّلاع على اقتراحات بشأن بنية Android.

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

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

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

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

بالنسبة إلى واجهات المستخدم المتكيّفة، تعرض عناصر الاحتفاظ بالحالة، مثل عناصر ViewModel، حالة واجهة المستخدم التي تتكيّف مع فئات أحجام النوافذ المختلفة. يمكنك استخدام currentWindowAdaptiveInfo() لاشتقاق حالة واجهة المستخدم هذه. يمكن بعد ذلك أن تستخدم مكوّنات مثل NavigationSuiteScaffold هذه المعلومات للتبديل تلقائيًا بين أنماط التنقّل المختلفة (على سبيل المثال، NavigationBar أو NavigationRail أو NavigationDrawer) استنادًا إلى مساحة الشاشة المتاحة.

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

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

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

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

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

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

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

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

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

طبقة النطاق

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

الحفاظ على حالة واجهة المستخدم عند إجراء تغييرات في الإعدادات:

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

تصميم مكوّنات واجهة مستخدم قابلة لإعادة الاستخدام والدمج:

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

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

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

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

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

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

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

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

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

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

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

نماذج

توضّح النماذج التالية بنية التطبيق الجيدة: