اكتشف فريق يقوم بشحن بيئة تشغيل Python بحجم 5.5 ميجابايت إلى المتصفحات أن 69% من الأخطاء التي تم تسجيلها خلال دورة تطوير (sprint) أخيرة تندرج تحت عنوان واحد مضلل، وأن 89% من تلك الأخطاء كانت في الواقع بسبب انتهاء مهلة الشبكة (network timeouts). أدى هذا التقرير الخاطئ إلى توجيه المطورين نحو مسار تصحيح أخطاء غير صحيح، وترك شريحة كبيرة من المستخدمين يواجهون حالات فشل صامت في التحميل — وهي مشكلة يمكن لأي تطبيق ويب يتضمن أصولاً (assets) كبيرة أن يواجهها قريباً.
لوحة البيانات كانت مضللة
يقوم نظام تتبع الأخطاء تلقائياً بتجميع الحوادث بناءً على موقع الكود الذي ظهرت فيه لأول مرة. بدا العنوان الناتج وكأنه خطأ بسيط في محمل بيئة التشغيل (runtime loader)، لذا استُهلكت دورة التطوير في البحث عن مسارات برمجية لم تتعرض أبداً لانتهاء المهلة. وعندما قام الفريق بفحص البيانات الوصفية (metadata) الأساسية، ظهرت الصورة الحقيقية: معظم الإخفاقات لم تكن أخطاء برمجية على الإطلاق، بل كانت اتصالات شبكة متوقفة أدت إلى انتهاء المهلة.
الخلاصة: عنوان الخطأ هو وسيلة للتسهيل وليس تشخيصاً. يجب التعمق دورياً في البيانات الخام للتحقق مما يمثله العنوان فعلياً.
واجهة برمجة تطبيقات اتصال المتصفح أعطت قيمة مؤقتة
لتجنب إرهاق المستخدمين ذوي الاتصال البطيء بتحميل ملف بحجم 5.5 ميجابايت، استشار المطورون واجهة برمجة تطبيقات معلومات الشبكة في المتصفح (navigator.connection). أبلغت الواجهة عن عرض نطاق ترددي (bandwidth) ثابت قدره 1.7 ميجابت في الثانية لكل زائر جديد.
تُصدر المتصفحات قيمة افتراضية عندما لا تتوفر لديها بيانات تاريخية لمستخدم جديد. هذه القيمة الافتراضية هي مجرد إشارة وليست سرعة مؤكدة. عندما تظهر نفس القيمة المؤقتة في كل جلسة جديدة، فهذا يشير إلى أن واجهة برمجة التطبيقات لم تتم معايرتها بعد لتناسب هذا الجمهور.
الخلاصة: تعامل مع أي إشارة شبكة لا تتغير أبداً كخيار احتياطي (fallback)، وليس كمقياس نهائي.
اللقطات الفردية غير موثوقة
بعد استبعاد إشارة عرض النطاق الترددي غير الموثوقة، انتقل الفريق إلى إشارة مختلفة بدت وكأنها تعمل في مجموعة الاختبارات الخاصة بهم. نجحت عملية اختبار واحدة، ولكن عند تكرار الاختبار ثلاث مرات، حدثت إخفاقات في كل مرة. سرعة الشبكة تتقلب باستمرار. لقد أخذ الكود لقطة واحدة (snapshot)، واتخذ قراراً دائماً، ثم استمر في العمل حتى لو تغير الاتصال بعد لحظة واحدة.
الخلاصة: لا تبنِ إجراءً دائماً على قراءة واحدة لهدف متحرك. اشترك في أحداث التغيير (change events) بدلاً من الاستعلام (polling) لمرة واحدة.
الإصلاحات العملية التي طبقها الفريق
- الاشتراك في تغييرات الاتصال. بدلاً من قراءة
navigator.connectionمرة واحدة، يستمع الكود الآن لحدثchangeويتفاعل إذا انخفض عرض النطاق الترددي أو ارتفع أثناء التحميل. - إضافة "مراقب" (watchdog) لعدم التقدم. يقوم مؤقت بإلغاء أي طلب لا يحرز أي تقدم بعد فترة قصيرة، مما يتيح للمتصفح إعادة المحاولة أو الانتقال إلى خيار احتياطي.
- التوقف عن تبديل شبكات توصيل المحتوى (CDNs) أثناء التحميل. يؤدي تبديل مصدر ملف كبير عبر رابط بطيء إلى إعادة بدء عملية النقل من الصفر، مما يهدر البايتات التي تم استلامها بالفعل. أصبح التحميل الآن يلتزم بـ CDN المختار في البداية طوال مدته.
- تأجيل عمليات التخزين المؤقت الثقيلة. يتم تأجيل المهام التي تكتب كميات كبيرة من البيانات في ذاكرة التخزين المؤقت إلى ما بعد انتهاء تحميل بيئة التشغيل، مما يحافظ على قصر المسار الحرج.
إذا كانت لوحات البيانات الخاصة بك ترسم صورة منظمة بشكل مريب، فابحث بعمق أكبر. إذا كان قياس الشبكة لا يتحرك أبداً، فتعامل معه كقيمة مؤقتة. وإذا كانت لقطة واحدة هي التي تقرر مصير تحميل بحجم عدة ميجابايتات، فأنت تراهن على سراب. تظهر هذه الرهانات في شكل إخفاقات صامتة تؤدي إلى تآكل ثقة المستخدم — وهو أمر لا يمكن لأي قدر من الكود الذكي إصلاحه بالكامل بعد فوات الأوان.
