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