لماذا نضع حالات التسابق في المواصفات لا في متتبع الأخطاء
معظم الأخطاء التي نُستدعى لإصلاحها بعد أن يشحن فريق آخر عمله ليست أخطاء منطقية. المنطق سليم. ما ينقص هو إجابة عن سؤال لم يكتبه أحد: ماذا يحدث لو تشغّل هذا مرتين، أو بترتيب خاطئ، أو لم يتشغّل أصلًا؟
الأسئلة الخمسة التي نطرحها قبل كتابة أي نموذج
كل نموذج، وكل طلب، وكل حالة يمكن أن تتغيّر أثناء طلب قيد التنفيذ، يمرّ بنفس الأسئلة الخمسة قبل كتابة أي سطر تنفيذي:
- ماذا لو أرسل المستخدم النموذج مرتين؟ نقرة مزدوجة، أو شبكة بطيئة تجعل الزر يبدو غير مستجيب فيُنقر عليه مجددًا — إن لم يُمنع الإرسال الثاني، ستحصل على سجلّين، أو أسوأ من ذلك، رسالة خطأ لطلب نجح فعليًا.
- ماذا لو وصلت الاستجابة بترتيب خاطئ؟ اكتب استعلامي بحث بسرعة، وقد يُحلّ الطلب الأول بعد الثاني. دون حارس تسلسل، تعرض الواجهة نتائج استعلام تخليت عنه فعلًا.
- ماذا لو أُزيل المكوّن أثناء الطلب؟ تغيير المسار، إغلاق نافذة منبثقة، الانتقال إلى تبويب آخر — الطلب لا يعرف أن يتوقف، واستدعاء
setStateعلى مكوّن أُزيل إما يحذّر بصوت عالٍ أو يفسد حالة أخرى بصمت. - ماذا لو كانت القائمة فارغة، أو تحتوي عنصرًا واحدًا بالضبط؟ حالة الصفر وحالة الواحد تكسران عناصر التمرير والقوائم المنسدلة والترقيم أكثر من أي مدخل آخر.
- ماذا لو فشلت الشبكة في منتصف الطريق؟ ليس "فشل الطلب" فحسب — بل في المنتصف. نموذج متعدد الخطوات حفظ الخطوتين الأولى والثانية على الخادم لكنه فشل في الثالثة يحتاج مسار استرداد محدد، لا شاشة خطأ عامة تُلغي كل شيء.
كيف يبدو هذا في الكود
في هذا المشروع، تدفق إرسال حاسبة التكلفة هو إجابة مباشرة على السؤالين ١ و٣: كل إرسال ينشئ AbortController، يُخزَّن في مرجع، ويُلغيه تأثير تنظيف إذا أُزيل المكوّن قبل اكتمال الطلب. إجراء SUBMIT_START في المخفّض لا يفعل شيئًا إذا كان هناك إرسال قيد التنفيذ بالفعل — فحالة النقر المزدوج لا تصل إلى الشبكة أصلًا.
عارض شهادات العملاء يجيب مباشرة على السؤال ٤: يُعرض بشكل صحيح سواء كانت هناك صفحة واحدة أو ست، وأزرار السابق/التالي ببساطة لا تُعرض إن لم يكن هناك ما يُتصفّح، بدلًا من البقاء في حالة معطّلة لكن مرئية.
لا شيء من هذا غريب. الفرق هو معاملة "تعامل مع الحالة الاستثنائية" كتعليق في مراجعة الكود مقابل معاملتها كقيد تصميمي يشكّل بنية الحالة منذ أول التزام. النهج الثاني أبطأ في اليوم الأول، وأسرع في كل يوم بعده.