مقال

حين لا تعمل كل الأشياء: صمّم نظامك ليخسر المزايا لا القدرة على العمل

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

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

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

النظام المثالي ليس هدفًا واقعيًا دائمًا

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

صنّف الوظائف قبل أن تصمم الأعطال

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

الفشل يجب أن يكون محليًا

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

أخبر المستخدم بالحقيقة

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

الاستعادة أهم من لحظة الانقطاع

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

اختبر النظام وهو ناقص

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

المرونة ليست أن يعمل كل شيء دائمًا

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