عندما تتعطل تطبيقات الجوال لأن المستخدمين لا يُحدّثون

تضيف نقطة نهاية جديدة في الواجهة الخلفية. أحدث إصدار من التطبيق يتعامل معها بشكل مثالي. كل شيء يبدو أخضر في خط أنابيب CI/CD الخاص بك. ثم تبدأ تقارير الأعطال في الوصول.

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

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

مشكلة فجوة الإصدارات

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

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

sequenceDiagram participant AppV1 as App v1.0 participant AppV2 as App v2.0 participant Backend as Backend Note over Backend: Backend evolves AppV1->>Backend: GET /api/orders (old format) Backend-->>AppV1: 200 OK (old response) Note over AppV1: Works fine AppV2->>Backend: GET /api/v2/orders (new format) Backend-->>AppV2: 200 OK (new response) Note over AppV2: Works fine AppV1->>Backend: GET /api/v2/orders (new format) Backend-->>AppV1: 200 OK (new response) Note over AppV1: CRASH - can't parse new format Note over Backend: Solution: keep old endpoint for backward compatibility

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

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

اعرف الإصدارات الموجودة في البرية

قبل أن تتمكن من إدارة التوافق، تحتاج إلى رؤية. متاجر التطبيقات تعطيك بعض البيانات—Google Play Console و App Store Connect كلاهما يُظهر توزيع الإصدارات. لكن هذه البيانات متأخرة ومجمعة. تخبرك بما قام المستخدمون بتثبيته، وليس ما يستخدمونه بنشاط.

نهج أفضل: أرسل إصدار التطبيق مع كل طلب. أضف عنوانًا مخصصًا مثل X-App-Version أو قم بتضمينه في سلسلة User-Agent الخاصة بك. تسجل الواجهة الخلفية هذه المعلومات، ويمكنك تجميعها في لوحة تحكم تُظهر اعتماد الإصدار في الوقت الفعلي.

هذه البيانات تجيب على أسئلة حاسمة:

  • ما هي النسبة المئوية للمستخدمين النشطين على كل إصدار؟
  • ما مدى سرعة اعتماد المستخدمين لأحدث إصدار؟
  • ما هي الإصدارات القديمة التي لا تزال تحمل حركة مرور كبيرة؟
  • متى يمكنك إسقاط دعم إصدار قديم بأمان؟

بدون هذه البيانات، أنت تتخذ قرارات بشكل أعمى. قد تُهمل إصدارًا لا يزال لديه 30% من المستخدمين النشطين، أو تستمر في دعم إصدار يستخدمه 2% فقط.

حافظ على توافق الواجهة الخلفية

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

على سبيل المثال، بدلاً من تعديل /api/orders، أنشئ /api/v2/orders وأبقِ /api/v1/orders قيد التشغيل. تطبيقك الأحدث يتحدث مع v2، التطبيقات الأكبر تستمر في استخدام v1. هذا يعطي المستخدمين وقتًا للترقية دون كسر تجربتهم.

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

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

فرض التحديثات عند الضرورة

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

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

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

استخدم التكوين عن بُعد كشبكة أمان

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

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

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

إليك ما قد تبدو عليه حمولة التكوين عن بُعد الواعية بالإصدار:

{
  "config": {
    "new_checkout_flow": {
      "enabled": true,
      "disabled_versions": ["4.2.0", "4.2.1"]
    },
    "api_base_url": "https://api.example.com/v2",
    "legacy_api_base_url": "https://api.example.com/v1",
    "timeout_ms": 10000
  },
  "flags": {
    "dark_mode": true,
    "experimental_search": false
  }
}

يقرأ التطبيق قائمة disabled_versions ويتخطى تدفق الدفع الجديد للإصدارين 4.2.0 و 4.2.1، مع العودة إلى التدفق القديم. لا حاجة لتحديث التطبيق.

أعلام الميزات للاسترداد الطارئ

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

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

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

قائمة مراجعة عملية لإدارة الإصدارات

  • أرسل إصدار التطبيق مع كل طلب عبر عنوان مخصص
  • أنشئ لوحة تحكم تُظهر توزيع الإصدار في الوقت الفعلي
  • أبقِ نقاط نهاية API القديمة قيد التشغيل حتى تنخفض الإصدارات القديمة عن 5% من الاستخدام
  • حدد إصدارًا أدنى مدعومًا وفرضه باستخدام آلية تحديث إجباري
  • طبق التكوين عن بُعد لتغييرات سلوك الخادم دون تحديثات التطبيق
  • استخدم أعلام الميزات لتعطيل الميزات الإشكالية فورًا
  • أعلن عن مواعيد الإهمال النهائية من خلال الإشعارات داخل التطبيق قبل قطع الدعم

الخلاصة

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

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

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