بدلاً من إعادة كتابة تطبيق كامل بلغة Rust، تقترح Lily Mara، وهي مهندسة Staff Engineer في Discord، نقل الوظائف الأكثر استهلاكاً للموارد تدريجياً من لغة ديناميكية مثل Python إلى Rust، وربط التنفيذين داخل العملية نفسها. عرضت Mara هذه المنهجية في جلسة منشورة عبر InfoQ، مستندة إلى خبرتها في بناء أنظمة موزعة لإرسال عشرات المليارات من الإشعارات يومياً إلى مستخدمي Discord، وإلى كتابها Refactoring to Rust.
الفكرة الأساسية ليست استبدال لغة بأخرى لمجرد أن Rust أسرع، بل تحديد أجزاء ضيقة من النظام تحقق أكبر أثر عند تحسينها. وتسمح هذه المقاربة بتقليص نطاق التغيير، واختبار السلوك الجديد مقابل القديم، والاحتفاظ بالتنفيذ الأصلي في الحالات التي يصعب فيها ضمان تطابق النتائج.
لماذا لا تكون إعادة الكتابة الكاملة نقطة البداية؟
ترى Mara أن الحماس لإعادة بناء نظام قديم بالكامل بلغة أحدث مفهوم، لكنه يحمل مخاطر عملية كبيرة. فمشروعات إعادة الكتابة قد تتجاوز المواعيد، وتصبح أكثر تعقيداً مما كان متوقعاً، أو تعيد إدخال أخطاء سبق للنظام القديم أن عالجها. كما أن الشيفرة القديمة لا تكون معقدة دائماً بسبب عمرها؛ فقد تعكس قيوداً وتفاصيل تراكمت من واقع الاستخدام ومن معرفة مؤسسية يصعب نقلها إلى مشروع جديد.
وتحذر الجلسة أيضاً من اختزال مشكلة الأداء في لغة البرمجة وحدها. فقد يكون سبب البطء في مخطط قاعدة البيانات، أو أنماط الاستعلام والتخزين المؤقت، أو تصميم الخدمات، وليس في تكلفة تنفيذ السطر البرمجي. لذلك لا تعني الاستفادة من Rust أن إعادة الكتابة ستعالج تلقائياً الاختناقات المعمارية.
ما المقصود بإعادة الهيكلة عبر FFI؟
تستخدم المنهجية ما تسميه Mara FFI refactoring، أي إعادة كتابة وظيفة أو جزء صغير من الوظائف بلغة أخرى وربطه بالتطبيق القائم عبر واجهة الربط بين اللغات. وفي المثال المعروض، يستمر تطبيق Flask في استقبال طلب HTTP وفك ترميز JSON، ثم يرسل البيانات إلى وظيفة إحصائية مكتوبة بـRust، قبل إعادة النتائج إلى Python وإرسال الاستجابة.
يعتمد الربط على واجهة C، التي تعمل عملياً كلغة مشتركة بين كثير من الأنظمة واللغات. وفي حالة Python، يوفر مشروع PyO3 أدوات لإنشاء وحدة قابلة للاستيراد من Python، فيما يمكن استخدام Maturin لبناء هذه الوحدة. وتحوّل السمات البرمجية مثل pyfunction وpyclass الوظائف وهياكل البيانات في Rust إلى واجهات يمكن استدعاؤها من Python.
اختيار الوظيفة المناسبة وقياس الأثر
تنصح التجربة بالبحث عن الوظائف التي تجمع بين كثرة الاستدعاء أو ارتفاع تكلفة الاستدعاء. فقد تكون الوظيفة رخيصة نسبياً في كل مرة، لكنها تعمل مع كل طلب، مثل منطق التحقق الموجود أمام معالجات API. وفي المقابل، قد تكون هناك عمليات نادرة لكنها مكلفة جداً. المعيار هو الأثر التراكمي على وقت المعالج، لا الانطباع بأن وظيفة بعينها تبدو بطيئة.
في المثال الإحصائي، كان تنفيذ Rust أسرع بقليل من مئة مرة عند قياس الوظيفة نفسها عبر Python، رغم أن الاختبار شغّل التطبيقين من خلال مفسر Python. لكن عند قياس معالج HTTP كاملاً، بما يشمل Flask وتسلسل JSON وفك تسلسله، بلغ التحسن نحو 15% فقط. وبلغ زمن تنفيذ النسخة الأصلية من الوظيفة حوالي 86 ميكروثانية، وهو زمن صغير منفرداً، لكنه قد يتحول إلى تكلفة مهمة عند تكراره على نطاق واسع.
هذه الفجوة بين القياس الجزئي والقياس الكلي هي من أهم دروس الجلسة: لا يكفي تسجيل تسارع الوظيفة، بل يجب إجراء اختبارات كلية تمثل مسار الاستخدام الفعلي وتضم الشبكة أو إطار الويب وتسلسل البيانات عند الحاجة.
التوافق الوظيفي والاختبارات والقيود
أظهرت إعادة تنفيذ المثال اختلافاً بين نتائج مكتبة الإحصاء في Python ومكتبة Rust. فإحدى المكتبتين حسبت الربيعات بدقة، بينما استخدمت الأخرى تقديرات مناسبة لمجموعات ضخمة، كما ظهرت فروق طفيفة في التقريب العشري. لذلك لا ينبغي افتراض أن استبدال المكتبة يحافظ تلقائياً على السلوك نفسه.
إذا كان التطابق ضرورياً، يمكن البحث عن مكتبة أخرى، أو إعادة تنفيذ الخوارزمية الأصلية في Rust، أو إبقاء الجزء الحساس في Python. وتكمن فائدة النقل على مستوى الوظيفة في إمكانية المزج بين اللغتين داخل العملية نفسها، بدلاً من فصل المكون في خدمة مستقلة وإضافة اتصالات شبكية وتكاليف تشغيلية جديدة.
أما الاختبارات، فتشمل اختبارات Rust المباشرة، واختبارات Python القائمة لمعالجات Flask، واختبارات تقارن نتائج التنفيذين، إضافة إلى اختبار عشوائي للخصائص عند ملاءمته. ومع ذلك، تفرض إضافة كود أصلي تعقيدات تشغيلية: حاجة بيئات التطوير إلى مترجم Rust أو ثنائيات متوافقة مع نظام التشغيل والمعمارية، وتعقيداً أكبر في النشر، واحتمال ظهور أخطاء جديدة.
عملياً، تقدم هذه المنهجية مساراً محدود المخاطر نسبياً لتحسين أجزاء مختارة من الأنظمة القائمة، لكنها لا تلغي الحاجة إلى تحليل معماري واختبارات توافق وقياسات كلية. فالتوفير الحقيقي لا يثبت إلا عندما ينعكس التحسن في مسار الخدمة الكامل، لا في benchmark معزول للوظيفة.
كيف أعددنا هذا الخبر؟
اعتمد الخبر على المصدر الأصلي الموضح أعلاه. قد نستخدم أدوات آلية للمساعدة في الاستخراج والتصنيف والصياغة،
لكن النشر يخضع لقواعد تمنع المحتوى المكرر والقصير أو الروتيني منخفض القيمة.
اقرأ سياستنا التحريرية.