الفوضى في الواجهات الأمامية (Front-end entropy) حقيقة واقعة. فالقاعدة البرمجية لا تنهار بين عشية وضحاها، بل تتراكم تدريجياً. في يوم ثلاثاء ما، تضيف مكتبة لتنسيق التاريخ. وبعد ستة أشهر، يضيف شخص آخر مكتبة أخرى لأنه لم يجد الأولى. تتراكم ملفات الـ polyfills لمتصفحات لم تعد تدعمها، وتتراكم أدوات البناء فوق بعضها البعض. وفي نهاية المطاف، يتحول مجلد node_modules إلى ما يشبه درج الخردة الرقمي، حيث لا يمكنك التخلص من أي شيء دون خوف. تتوقف عن التحديث، ثم تتوقف عن البحث. وهنا يتحول كل تغيير صغير إلى مقامرة.
لقد واجهت هذا الجدار أثناء محاولتي تحديث Material UI في مشروع قديم. فتحت ملف package.json وبالكاد استطعت التعرف على نصف المدخلات. عشرات المكتبات كانت تقبع هناك، بعضها قديم منذ سنوات، وبعضها الآخر غامض لدرجة أنني اضطررت لاستخدام git blame لأعرف من أضافها ولماذا. قمت بتشغيل أمر التثبيت لإصدار Material UI الجديد، فامتلأت الشاشة بتحذيرات التبعيات المتعارضة (peer dependency warnings). الحزمة التي أردت تحديثها كانت سليمة، لكن النظام البيئي المحيط بها لم يكن كذلك. أدركت حينها أنني لا أقوم بعملية تحديث، بل كنت أقوم بالتنقيب في أطلال.
لماذا تكلف هذه الفوضى أكثر من مجرد كبرياء
تجاهل التبعيات ليس مجرد مشكلة شكلية، بل هو أمر يخلق مشاكل حقيقية ومكلفة.
المخاطر الأمنية هي التهديد الواضح. فالحزم المهجورة تحمل ثغرات أمنية تم الكشف عنها وتكتشفها أدوات الفحص أسبوعياً. والأسوأ من ذلك، أن المكتبات التي قمت بتثبيتها مباشرة قد تكون سليمة، بينما التبعيات غير المباشرة (transitive dependencies) التي سحبتها تلك المكتبات ليست كذلك. أنت ترث ديوناً تقنية لشخص آخر دون أن تدري.
تتضاعف التكلفة مع مرور الوقت. كلما انتظرت أكثر، اتسعت الفجوة بين الإصدارات. القفز عبر إصدار رئيسي واحد من React يعد عملاً شاقاً، أما القفز عبر ثلاثة إصدارات فهو مشروع هجرة برمجية قد يستغرق أسابيع. ستتوقف عن الحصول على إصلاحات الأخطاء، وتحسينات الأداء، والتوافق مع الأدوات الحديثة. وينتهي الأمر بالفريق ببناء حلول حول قيود لم تعد موجودة أصلاً.
المكتبات تموت. الحزمة التي لا يوجد لها مطورون نشطون تصبح "نسخة خاصة بك" (private fork) بشكل افتراضي. وعندما تتعطل، ستكون أنت الشخص الذي يقرأ كودها المصغر (minified source code) في منتصف الليل. لقد انتقل المجتمع إلى حلول أفضل، بينما يظل فريقك عالقاً في صيانة أثر من الماضي.
تنهار وتيرة العمل. يقضي المطورون الجدد أيامهم الأولى في تعلم واجهات برمجة تطبيقات (APIs) غريبة لأدوات تم استبدالها بمعايير الويب أو البدائل السائدة. وبدلاً من إطلاق الميزات الجديدة، يتحول مهندسو الفريق الكبار إلى مؤرخين، يشرحون لماذا لا يزال هذا المشروع يستخدم أداة تشغيل مهام (task runner) من عام 2015.
قم بالتدقيق قبل أن تلمس أي إصدار
الخطأ الأكبر هو إجراء تحديث شامل (blanket update) والأمل في أن تجتاز الاختبارات. ابدأ بعملية تدقيق. أمسك بملف package.json واستجوب كل مدخل فيه.
اطرح أربعة أسئلة:
- ما المشكلة التي تحلها هذه المكتبة؟
- أين نستخدمها بالضبط؟
- هل لا تزال ضرورية؟
- هل يوجد بديل أفضل الآن؟
ستجد تكراراً. ربما تشغل كل من moment و date-fns القائمة لأن مطورين اثنين حلا نفس المشكلة في أوقات مختلفة. ربما لا يزال هناك polyfill لمتصفح Internet Explorer رغم أن تحليلاتك تظهر عدم وجود أي حركة مرور من المتصفحات القديمة. ربما يمكن حذف غلاف مخصص (custom wrapper) حول fetch لأن المتصفحات الحديثة تتعامل مع الحالات الاستثنائية بشكل أصلي.
أحياناً يكون الاستبدال أفضل من التحديث. إن صراعك مع مكتبة رسوم بيانية مهجورة عبر ثلاثة أعوام من التغييرات الجذرية (breaking changes) قد يستغرق وقتاً أطول من استبدالها ببديل مستقر وإعادة بناء بعض المكونات. كن مستعداً للحذف.
الطبقة الخفية: التبعيات غير المباشرة والإصدارات الدلالية (Semver)
التبعيات المباشرة ليست سوى الجزء الظاهر من جبل الجليد. الكتلة الحقيقية تكمن تحت السطح في التبعيات غير المباشرة (transitive dependencies)، وهي الحزم التي تحتاجها حزمك. أنت لم تخترها، لكنها تُنفذ في عملية البناء الخاصة بك. إنها تضخم حجم الحزمة (bundle)، وتوسع نطاق الهجوم الأمني، وتتعارض أحياناً مع بعضها البعض بطرق تؤدي إلى أخطاء بناء غامضة.
عليك أن تفهم الإصدارات الدلالية (semantic versioning) لما تعنيه حقاً، وليس لما تأمل أن تعنيه.
- التحديثات الرئيسية (Major updates): هذه عمليات هجرة. تعامل معها كتغييرات جذرية (breaking changes) ما لم يثبت العكس. اقرأ سجل التغييرات (changelog)، وخصص وقتاً، واختبر بدقة.
- التحديثات الفرعية (Minor updates): هذه تضيف ميزات. يمكنها أيضاً تغيير السلوك بطرق دقيقة. لا تفترض أنها مجانية تماماً.
- تحديثات الإصلاح (Patch updates): هذه تعالج الأخطاء. عادة ما تكون آمنة، ولكن إذا كان كودك يعتمد على وجود الخطأ، أو إذا قام التحديث بتغيير جزء داخلي كنت تقوم بترقيعه (monkey-patching)، فقد يتسبب ذلك في تعطل الكود.
معرفة هذه القواعد تساعدك على تصنيف المخاطر قبل أن تلمس أي شيء.
استخدم أدواتك كالحرفي الماهر
إذا كنت تستخدم Yarn، فهناك العديد من الأوامر المدمجة التي تحول التخمين إلى عملية منظمة.
قم بتشغيل yarn outdated أولاً. سيعطيك لقطة لما أصبح قديماً...
