يأتي Rails 6 مع وضعين للتحميل التلقائي: zeitwerk و classic. في طلب السحب هذا https://github.com/discourse/discourse/pull/8083، قمت بترقية Rails إلى الإصدار 6.0.0 باستخدام محمل الكود الكلاسيكي كمرحلة انتقالية. سيكون من المثير للاهتمام محاولة التبديل إلى Zeitwerk.
يعتبر Zeitwerk محمل كود فعال وآمن للمواضيع (thread-safe) لـ Ruby. طالما أن المشروع يتبع اتفاقيات التسمية، يمكن لـ Zeitwerk العثور على الملفات الصحيحة وتحميلها عند الطلب أو مسبقًا دون الحاجة إلى أي require أو require_dependency. علاوة على ذلك، قد يمنح ذلك دفعة أداء صغيرة للتطبيق وفقًا لهذا المقال https://weblog.rubyonrails.org/2019/2/22/zeitwerk-integration-in-rails-6-beta-2/
هناك عدة خطوات أحتاج إلى القيام بها لجعلها تعمل:
تغيير اسم بعض الفئات لتتوافق مع اتفاقية تسمية Rails. على سبيل المثال، يجب أن يحدد الملف canonical_url.rb فئة CanonicalUrl بدلاً من CanonicalURL. وبالمثل، يجب أن يحدد الملف ondiff.rb فئة Onpdiff بدلاً من ONPDiff. ستكون هناك نهج بديل وهو ربط مُعرِّف مخصص (custom inflector) بالمشروع، إلا أنني أعتقد أن اتباع الاتفاقية قد يكون خيارًا أفضل - https://github.com/fxn/zeitwerk#custom-inflector
وبالمثل، وفقًا للاتفاقية، يجب تغليف عمليات التحقق المخصصة (custom validations) الموجودة في مجلد validations بوحدة Validations. بالإضافة إلى ذلك، ترث بعض عمليات التحقق من EachValidator ويجب أن تكون قابلة للوصول بدون مساحة أسماء (namespace). أخطط لنقلها إلى مجلد منفصل وإضافتها إلى مسارات التحميل التلقائي.
إزالة جميع require_dependency والتأكد من عمل المشروع.
إزالة جميع require والتأكد من عمل Discourse.
التأكد من أن جميع الإضافات (plugins) يمكنها الوصول إلى التبعيات المطلوبة. لا أعرف كيفية تحقيق ذلك بعد. أريد أولاً جعل Discourse يعمل دون أي إضافات.
لقد حققت بعض التقدم فيما يتعلق بـ Zeitwerk، ومع ذلك، غيّرت نهجي. كان خططي الأصلي هو تغيير كل مكان لا يلتزم فيه Discourse باتفاقية تسمية الملفات الخاصة بـ Zeitwerk. بعد بعض الإصلاحات، أدركت أن هذا هو مجرد جزء بسيط من المشكلة، ولاحظت أنه إذا سرت في هذا المسار، فسيكون من الصعب قراءة طلب الدمج (pull request) ودمجه بثقة في الفرع الرئيسي (master). على سبيل المثال، يجب أن تحتوي جميع فئات الوظائف الموجودة في المجلدات العادية على مساحة اسم Regular، وكذلك Onceoff وScheduled.
قررت أن أرتد خطوة إلى الخلف قليلاً وأفكر في نهج تطوري أكثر من ثوري.
قررت أنه سيكون من الأفضل تقديم مُعرّف مخصص (custom Inflector) سيغطي جميع الملفات التي لا تتبع اتفاقية Zeitwerk. ستكون الفائدة الأكبر هي أننا سنتمكن من نشر هذا التغيير الصغير، وبمجرد أن نشعر بالرضا عن Zeitwerk ولا نواجه أي تدهور في الأداء، يمكننا البدء في إصلاح الاتفاقية ملفًا تلو الآخر في طلبات دمج صغيرة ومعقولة.
وجدت بعض المشاكل التي لا يمكن حلها بواسطة مُعرّف مخصص، لذا قمت بإصلاحات إضافية لجعلها تعمل.
لا يزال طلب الدمج قيد التقدم، ومع ذلك، في هذه المرحلة، يمكنني تشغيل Discourse مع Zeitwerk والإضافات الافتراضية، وتشغيل جميع الاختبارات (specs) وتشغيل المقاييس (benchmark) دون أي مشكلة.
أردت أولاً الوصول إلى حالة مستقرة حيث تمر جميع الاختبارات. الآن يمكنني أن أبدأ بثقة في إزالة جميع require_dependency واحدة تلو الأخرى، وكذلك اختبار الإضافات الرسمية. بمجرد أن يكون كل شيء جاهزًا، سأشارك معك نتائج المقاييس في هذا المنشور.
يمكننا تجربة طريقة أخرى لإجراء اختبار الأداء. ماذا تقول عن تكرارات أكثر، شيء يستغرق ساعة؟ بالإضافة إلى ذلك، بدلاً من أخذ أفضل نتيجة، قارن المتوسط من كل تجربة. قد يعطي ذلك أرقامًا أكثر اتساقًا. ما رأيك؟
@سام أعتقد أننا جاهزون، لقد قمت بإعادة التأسيس مع أحدث نسخة من الفرع الرئيسي (master) وأجريت تعديلاً بسيطاً على Webauthn.
لقد تحققت من ثلاث نقاط:
تشغيل الخادم محلياً وتجربة بعض الأزرار للتأكد من عمله كما هو متوقع
تشغيل الاختبارات (specs)
تنزيل جميع الإضافات الرسمية والتأكد من نجاح اختبارات هذه الإضافات (نحتاج أولاً إلى دمج التعديلات الخاصة بالإضافات)