دفتر سليمان

مقال

عندما لا تسير الأمور كما خططت: كيف تبني نظامًا يستطيع الاستمرار؟

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

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

العالم الحقيقي ليس بيئة اختبار

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

صمّم الفشل بوصفه حالة، لا استثناءً

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

لا تكذب على المستخدم باللون الأخضر

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

  • توجد تغييرات لم تُحفظ.
  • جارٍ الحفظ.
  • تم الحفظ وتأكيده.
  • فشل الحفظ.
  • أُرسلت العملية لكن النتيجة غير مؤكدة.
  • تغيرت البيانات في مكان آخر ويوجد تعارض يحتاج إلى حل.

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

اجعل العودة ممكنة

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

قلّل حجم الفشل

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

النسخة الاحتياطية ليست ملفًا، بل قدرة على الاستعادة

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

نقاط الفشل ليست تقنية فقط

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

العمل دون اتصال ليس ميزة خاصة دائمًا

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

لا تجعل الأتمتة تلغي الطريق اليدوي دائمًا

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

المرونة ليست إضافة في نهاية المشروع

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

لا تبالغ في بناء الحماية

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

اجعل النظام قادرًا على شرح حالته

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

المرونة التنظيمية جزء من التصميم

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

صمّم من أجل يوم سيئ

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

النظام الجيد يعطيك خيارات

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

ابدأ من سؤال واحد هذا الأسبوع

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

ابنِ لما يحدث فعلًا

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

ضمن

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