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

كيف ظهرت المشكلة

أظهر متتبع الأخطاء في البيئة التجريبية رسالة واحدة لافتة للنظر: "undefined is not an object." أوحى العنوان بوجود خطأ مطبعي بسيط في JavaScript، لذا طارد الفريق مساراً برمجياً غير موجود. وعندما فحصوا البيانات الوصفية الخام، وجدوا أن 89% من تلك الحوادث كانت في الواقع بسبب انتهاء مهلة الشبكة (network timeouts). كانت لوحة التحكم قد أخذت أول خطأ وصل واستخدمته لتسمية الدفعة بأكملها، مما أخفى نوع الفشل الحقيقي.

الدرس 1 – عناوين لوحات التحكم قد تكون مضللة

إن لوحة التحكم التي تجمع الحوادث لا تفيد إلا إذا كان منطق التجميع فيها يعكس السبب الحقيقي لكل حدث. في هذه الحالة، أدى التجميع حسب الموقع بدلاً من سبب الخطأ إلى رسم صورة خاطئة عن وجود خطأ في جانب العميل (client-side bug). الخلاصة: لا تحاول أبداً إصلاح مشكلة بناءً على عنوان لوحة التحكم فقط. قم بسحب عينة من الأحداث الأساسية وتحقق مما يحدث حقاً قبل تخصيص الموارد.

الدرس 2 – القيم النائبة ليست قياسات

لتجنب تحميل بيئة التشغيل الضخمة للمستخدمين الذين لديهم روابط بطيئة، استعلم الكود من Network Information API وقرأ خاصية downlink التي تبلغ سرعة الاتصال بالميجابت في الثانية. عند الزيارة الأولى، غالباً ما تعيد Chrome قيمة نائبة (placeholder) بدلاً من قياس فعلي. تعامل المنطق البرمجي مع هذه القيمة النائبة على أنها اتصال سريع وتخطى عملية التحسين، مما أدى فعلياً إلى حجب المستخدمين الذين كان من المفترض مساعدتهم.

عامل أي قيمة افتراضية أو رمزية (sentinel value) على أنها "لا توجد بيانات". يجب أن تؤدي القيمة النائبة إلى تفعيل استراتيجية بديلة، لا أن تُفسر على أنها قراءة حقيقية للسرعة.

الدرس 3 – ظروف الشبكة تتغير، لذا فإن اللقطة الواحدة غير موثوقة

بعد حل مشكلة downlink، انتقل الفريق إلى فحص effectiveType الذي يصنف الاتصالات إلى "4g" و"3g" وما إلى ذلك. اجتاز اختبار مخبري سريع، ولكن عند إعادة نفس الاختبار بعد لحظات، فشل. الاتصالات المحمولة متقلبة؛ فقد يظهر المستخدم على اتصال 4G سريع في ثانية، ثم ينخفض إلى 3G أبطأ في الثانية التالية. إن فحص الاتصال عند تحميل الصفحة فقط هو مقامرة.

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

ما الذي غيره الفريق

  • تحميل على مرحلتين – تبدأ بيئة التشغيل الآن بملف تمهيدي (bootstrap) صغير جداً. إذا تم تحديد الاتصال على أنه بطيء، يقوم الملف التمهيدي بجلب بقية بيئة التشغيل في أجزاء صغيرة، مما يقلل من احتمالية الإلغاء الكامل للتحميل.
  • مراقبة مباشرة – بدلاً من قراءة واحدة لـ downlink ، يستمع الكود الآن لأحداث change ويعدل استراتيجية التحميل فوراً.
  • اختيار مصدر مستقر – في السابق، كان النظام يغير شبكات توصيل المحتوى (CDNs) في منتصف عملية التحميل عند ظهور نقطة نهاية أسرع، مما كان يؤدي في الروابط البطيئة إلى إعادة التحميل من الصفر، وهو ما يفاقم المشكلة. المنطق الجديد يقوم بتثبيت المصدر طوال مدة التحميل.
  • تأجيل عمليات الكتابة في ذاكرة التخزين المؤقت – عمليات التخزين المؤقت الثقيلة التي كانت تعمل قبل أن يصبح التطبيق قابلاً للاستخدام، يتم تأجيلها الآن إلى ما بعد بدء تشغيل بيئة التشغيل، مما يوفر عرض النطاق الترددي لعملية التحميل الحرجة.

المخاطر الأوسع

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

ما يجب مراقبته لاحقاً

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