استقرار واجهة التطبيقات الثنائية (ABI)
مقدمة
واجهة التطبيقات الثنائية (ABI) هي طريقة للبرامج لاستدعاء الدوال واستخدام هياكل البيانات من برامج أخرى مُجمَّعة. إنها النسخة المُجمَّعة من واجهة برمجة التطبيقات (API). بعبارة أخرى، ملفات الرأس التي تصف الفئات والدوال وهياكل البيانات والتعدادات والثوابت التي تمكن التطبيق من أداء مهمة مرغوبة تتوافق عن طريق التجميع مع مجموعة من العناوين وقيم المعلمات المتوقعة وأحجام هياكل الذاكرة وتخطيطاتها التي تم تجميع مزود ABI بها.
يجب تجميع التطبيق الذي يستخدم ABI بحيث تتفق العناوين المتاحة وقيم المعلمات المتوقعة وأحجام هياكل الذاكرة وتخطيطاتها مع تلك التي تم تجميع مزود ABI بها. يتم ذلك عادةً عن طريق التجميع مقابل الرؤوس التي يوفرها مزود ABI.
نظرًا لأنه قد يتم تجميع مزود ABI ومستخدم ABI في أوقات مختلفة بإصدارات مختلفة من المُجمِّع، فإن جزءًا من مسؤولية ضمان توافق ABI يقع على عاتق المُجمِّع. يجب أن تنتج الإصدارات المختلفة من المُجمِّع، وربما المقدمة من بائعين مختلفين، نفس ABI من ملف رأس بمحتوى معين، ويجب أن تنتج كودًا للتطبيق الذي يستخدم ABI والذي يصل إلى API الموصوف في رأس معين وفقًا لاتفاقيات ABI الناتجة عن الوصف في الرأس. تتمتع المُجمِّعات الحديثة بسجل جيد إلى حد ما في عدم كسر توافق ABI للتطبيقات التي تقوم بتجميعها.
تقع المسؤولية المتبقية لضمان توافق ABI على عاتق الفريق الذي يحتفظ بملفات الرأس التي توفر API التي تؤدي، عند التجميع، إلى ABI الذي من المفترض أن يظل مستقرًا. يمكن إجراء تغييرات على ملفات الرأس، ولكن يجب تتبع طبيعة التغييرات عن كثب لضمان أنه عند التجميع، لا يتغير ABI بطريقة تجعل المستخدمين الحاليين لـ ABI غير متوافقين مع الإصدار الجديد.
استقرار واجهة التطبيق الثنائية (ABI) في Node.js
يوفر Node.js ملفات رأسية تحتفظ بها عدة فرق مستقلة. على سبيل المثال، تحتفظ فرق Node.js بملفات رأسية مثل node.h
و node_buffer.h
. يحتفظ فريق V8 بملف v8.h
، والذي على الرغم من تعاونه الوثيق مع فريق Node.js، إلا أنه مستقل وله جدوله الزمني وأولوياته الخاصة. وبالتالي، فإن فريق Node.js لديه سيطرة جزئية فقط على التغييرات التي يتم إدخالها في الرؤوس التي يوفرها المشروع. ونتيجة لذلك، اعتمد مشروع Node.js إصدارًا دلاليًا. يضمن هذا أن واجهات برمجة التطبيقات التي يوفرها المشروع ستؤدي إلى واجهة تطبيق ثنائية (ABI) مستقرة لجميع الإصدارات الثانوية والتصحيحية من Node.js التي تم إصدارها ضمن إصدار رئيسي واحد. من الناحية العملية، هذا يعني أن مشروع Node.js قد التزم بضمان أن الإضافة الأصلية لـ Node.js التي تم تجميعها مقابل إصدار رئيسي معين من Node.js سيتم تحميلها بنجاح عند تحميلها بواسطة أي إصدار ثانوي أو تصحيحي من Node.js ضمن الإصدار الرئيسي الذي تم تجميعه مقابله.
N-API
لقد نشأ طلب لتجهيز Node.js بواجهة برمجة تطبيقات (API) تؤدي إلى واجهة تطبيق ثنائية (ABI) تظل مستقرة عبر إصدارات Node.js الرئيسية المتعددة. دوافع إنشاء مثل هذه الواجهة البرمجية هي كما يلي:
ظلت لغة JavaScript متوافقة مع نفسها منذ أيامها الأولى جدًا، في حين أن واجهة التطبيق الثنائية (ABI) للمحرك الذي ينفذ كود JavaScript تتغير مع كل إصدار رئيسي من Node.js. هذا يعني أن التطبيقات التي تتكون من حزم Node.js المكتوبة بالكامل بلغة JavaScript لا تحتاج إلى إعادة تجميعها أو إعادة تثبيتها أو إعادة نشرها عند إسقاط إصدار رئيسي جديد من Node.js في بيئة الإنتاج التي تعمل فيها هذه التطبيقات. في المقابل، إذا كان التطبيق يعتمد على حزمة تحتوي على إضافة أصلية، فيجب إعادة تجميع التطبيق وإعادة تثبيته وإعادة نشره كلما تم إدخال إصدار رئيسي جديد من Node.js في بيئة الإنتاج. وقد أدى هذا التباين بين حزم Node.js التي تحتوي على إضافات أصلية وتلك المكتوبة بالكامل بلغة JavaScript إلى زيادة عبء صيانة أنظمة الإنتاج التي تعتمد على الإضافات الأصلية.
بدأت مشاريع أخرى في إنتاج واجهات JavaScript وهي في الأساس تطبيقات بديلة لـ Node.js. نظرًا لأن هذه المشاريع مبنية عادةً على محرك JavaScript مختلف عن V8، فإن إضافاتها الأصلية تأخذ بالضرورة بنية مختلفة وتستخدم واجهة برمجة تطبيقات مختلفة. ومع ذلك، فإن استخدام واجهة برمجة تطبيقات واحدة لإضافة أصلية عبر تطبيقات مختلفة لواجهة برمجة تطبيقات Node.js JavaScript من شأنه أن يسمح لهذه المشاريع بالاستفادة من نظام حزم JavaScript الذي تراكم حول Node.js.
قد يحتوي Node.js على محرك JavaScript مختلف في المستقبل. هذا يعني أنه، خارجيًا، ستظل جميع واجهات Node.js كما هي، ولكن سيغيب ملف الرأس V8. ستتسبب هذه الخطوة في تعطيل نظام Node.js البيئي بشكل عام، والإضافات الأصلية بشكل خاص، إذا لم يتم توفير واجهة برمجة تطبيقات مستقلة عن محرك JavaScript أولاً بواسطة Node.js واعتمادها بواسطة الإضافات الأصلية.
ولهذه الغايات، قدم Node.js N-API في الإصدار 8.6.0 ووضع علامة عليها كمكون مستقر في المشروع اعتبارًا من Node.js 8.12.0. يتم تعريف واجهة برمجة التطبيقات في الرؤوس node_api.h
و node_api_types.h
، وتوفر ضمانًا للتوافق الأمامي يتجاوز حدود إصدار Node.js الرئيسي. يمكن ذكر الضمان على النحو التالي:
سيكون الإصدار n المحدد من N-API متاحًا في الإصدار الرئيسي من Node.js الذي تم نشره فيه، وفي جميع الإصدارات اللاحقة من Node.js، بما في ذلك الإصدارات الرئيسية اللاحقة.
يمكن لمؤلف إضافة أصلية الاستفادة من ضمان التوافق الأمامي N-API من خلال التأكد من أن الإضافة تستخدم فقط واجهات برمجة التطبيقات (APIs) المعرفة في node_api.h
وهياكل البيانات والثوابت المعرفة في node_api_types.h
. من خلال القيام بذلك، يسهل المؤلف اعتماد إضافته من خلال الإشارة إلى مستخدمي الإنتاج إلى أن عبء الصيانة لتطبيقهم لن يزيد بإضافة الإضافة الأصلية إلى مشروعهم أكثر مما يزيد بإضافة حزمة مكتوبة بلغة JavaScript فقط.
يتم إصدار N-API لأنه تتم إضافة واجهات برمجة تطبيقات جديدة من وقت لآخر. على عكس الإصدار الدلالي، فإن إصدار N-API تراكمي. أي أن كل إصدار من N-API ينقل نفس معنى الإصدار الثانوي في نظام semver، مما يعني أن جميع التغييرات التي تم إجراؤها على N-API ستكون متوافقة مع الإصدارات السابقة. بالإضافة إلى ذلك، تتم إضافة واجهات N-API جديدة تحت علامة تجريبية لمنح المجتمع فرصة للتحقق منها في بيئة إنتاج. تعني الحالة التجريبية أنه على الرغم من الحرص على التأكد من أن واجهة برمجة التطبيقات الجديدة لن تضطر إلى تعديلها بطريقة غير متوافقة مع واجهة التطبيق الثنائية (ABI) في المستقبل، إلا أنها لم تثبت بعد بشكل كافٍ في الإنتاج لتكون صحيحة ومفيدة كما هو مصمم، وعلى هذا النحو، قد تخضع لتغييرات غير متوافقة مع واجهة التطبيق الثنائية (ABI) قبل دمجها أخيرًا في إصدار قادم من N-API. أي أن N-API التجريبية لم يتم تغطيتها بعد بضمان التوافق الأمامي.