مشکل رابط دودویی شکننده
مشکل رابط باینری یا FBI به یک نقص در برخی از کامپایلرهای زبانهای برنامهنویسی شیءگرا است گفته میشود، که در آن تغییرات داخلی به یک کتابخانهٔ کلاس پایه میتواند باعث شود کتابخانهها یا برنامههای ساخته شده از آن به درستی کار نکنند. مشکل رابط باینری شکننده، نمونهای از شکنندگی نرمافزار است.
این مشکل اغلب به نام «مشکل کلاس پایهٔ شکننده» یا FBC خوانده میشود. با این حال، این اصطلاح معنای گستردهتری دارد.
دلایل[ویرایش]
این مشکل به دلیل «میانبر» استفاده شده توسط کامپایلرها برای بسیاری از زبانهای متداول شیءگرا به وجود میآیند. یک ویژگی طراحی است که وقتی زبانهای شیءگرا در حال تکامل از زبانهای ساختیافته و غیرشیءگرای پیشین مانند C و Pascal به ارث بردهاند.
در این زبانها هیچ «شیء»ای به معنای مدرن آن وجود ندارد، با این حال ساختاری مشابه آن موجود است که به عنوان یک رکورد (یا "struct" در C) شناخته میشود و انواع مختلفی از اطلاعات مرتبط را در یک قطعه از حافظه نگه میدارد. با ردیابی محل شروع رکورد، و دانستن آفست آن از نقطهٔ شروع تا قسمت مورد نظر، میتوان به دادهٔ موجود در یک رکورد خاص دسترسی پیدا کرد. به عنوان مثال، یک رکورد "person" ممکن است دارای یک نام، نام خانوادگی و نام میانی باشد. برنامهنویس برای دسترسی به دادهٔ نام میانی، چیزی مشابه thisPerson.middleInitial
مینویسد که کامپایلر آن را به چیزی شبیه a = location(thisPerson) + offset(middleInitial)
تبدیل میکند. پرداندههای مدرن معمولاً شامل دستورالعملهایی برای این نوع عملیات متداول هستند.
هنگامی که برای اولین بار کامپایلرهای زبانهای شیءگرا ساخته میشدند، بیشتر فناوریهای کامپایلرهای موجود در آن زمان مورد استفاده قرار گرفت و اشیاء به استفاده از مفهوم رکورد ساخته شدند. در این زبانها ارجاع به اشیاء با استفاده از نقطهٔ شروع آنها انجام شده و دادههای عمومی آنها «معروف به «فیلد»)، از طریق آفستشان قابل دسترسی بودند. در حقیقت تنها تغییر نسبت به رکوردها، اضافه کردن یک فیلد جدید به آن بود که به یک جدول متدهای مجازی تغییرناپذیر برای هر کلاس اشاره کند. به این ترتیب رکورد جدید هم دادهها و هم متدها (توابع) را توصیف میکند. هنگام کامپایل، از آفستها برای دسترسی به دادهها و کدها استفاده میشود (از طریق جدول متد مجازی).
علائم[ویرایش]
این مسئله در برنامههای بزرگتر که کتابخانهها ساخته شدهاند باعث ایجاد مشکل میشود. اگر نویسندهٔ کتابخانه اندازه یا چیدمان فیلدهای عمومی را در درون شیء تغییر دهد، آفستها دیگر معتبر نیستند و برنامه دیگر کار نمیکند. این مشکل FBI است.
اگرچه انتظار می رود که تغییرات در پیادهسازی برنامه باعث ایجاد مشکلاتی شود، اما مورد دردسرساز در بارهٔ FBI این است که هیچ چیزی واقعاً تغییر نکرده است. تنها چیدمان حافظهٔ اشیاء (پنهانسازی شده در یک کتابخانهٔ از پیش کامپایل شده) تغییر کرده است. به عنوان مثال با تغییر doSomething
به doSomethingElse
انتظار میرود مشکلاتی به وجود بیاید؛ اما در مورد شکنندگی باینری، بدون ایجاد هیچگونه تغییری درdoSomething
ممکن است مشکل بهوجود بیاید. حتی میتوان به راحتی و صرفاً با تغییر ترتیب خطوط کد این مشکل را به وجود آورد. از همه بدتر این که برنامهنویس تقریباً هیچ کنترلی روی چیدمان نهایی تولید شده توسط کامپایلر ندارد؛ و این باعث پنهان ماندن این مسأله میشود.
در برنامهها یا کتابخانههای پیچیدهٔ شیءگرا، کلاسها در بالاترین سطح ممکن است از دهها کلاس دیگر مشتق شده باشند. هر یک از این کلاسهای پایه میتوانند از صدها کلاس پایهٔ دیگر ارث برده باشند. این کلاسهای پایه «شکننده» هستند زیرا تغییر کوچکی در یکی از آنها میتواند برای هر کلاسی که از آن به طور مستقیم یا از طریق کلاس دیگر ارث برده است؛ مشکلاتی ایجاد کند. این میتواند باعث شود که کتابخانه مانند یک خانهٔ پوشالی متلاشی شود زیرا تعداد زیادی از کلاسها با یک تغییر در کلاس پایه آسیب میبینند. در صورتی که درخت ارثبری پیچیده باشد، هنگام ایجاد تغییرات ممکن است این مشکل جلب توجه نکند. در واقع، توسعهدهندهای که کلاس پایه را تغییر میدهد، عموماً از اینکه کدام کلاسها (توسعه داده شده توسط دیگران) از آن استفاده میکنند، ناآگاه است.
راه حل ها[ویرایش]
زبانها[ویرایش]
یک راه حل برای مشکل شکنندگی باینری، نوشتن زبانی است که از وجود این مشکل آگاه بوده، و در وهلهٔ اول اجازه نمیدهد که شکنندگی به وجود بیاید. اکثر زبانهای شیءگرا که به صورت سفارشی نوشته شدهاند، بر خلاف آنهایی که از زبانهای قبلی تکامل یافتهاند، تمام جدولهای افست خود را در زمان لود میسازند. تغییرات در چیدمان کتابخانه در آن مرحله قابل تشخیص است. سایر زبانهای شیءگرا مانند Self، همه چیز را در زمان اجرا با کپی کردن و اصلاح اشیاء موجود در کتابخانهها میسازند، بنابراین در واقع کلاس پایهای ندارند که شکننده باشد. برخی از زبانها، مانند جاوا، مستندات گستردهای در مورد ایمنی ایجاد تغییرات جهت پرهیز از ایجاد مشکلات FBI دارند.
راه حل دیگر ایجاد پروندهٔ واسطهای است که آفستها و سایر اطلاعات مرحلهٔ کامپایل را در قالب اَبَرداده در بر دارد. سپس لینکر از این اطلاعات برای اصلاح خود در هنگام بارگیری كتابخانه در برنامه استفاده میكند. پلتفرمهایی مانند .NET این کار را انجام میدهند.
با این حال، بازار، زبانهای برنامهنویسی مانند C++ را نیز انتخاب کرده است که در حقیقت «وابسته به موقعیت» هستند و بنابراین مشکل FBI دارند. در این موارد هنوز راهحلهای معدودی برای حل مشکل وجود دارد. یکی از این روشها مسئولیت را بر عهدهٔ نویسندهٔ کتابخانه میگذارد تا توسعهدهنده با وارد کردن تعدادی اشیاء «مکاننگهدار» به کلاس، امکان اضافه کردن قابلیتهای اضافی در آینده را فراهم کند. (کاربرد این روش را میتوان در structهای مورد استفاده در کتابخانهٔ DirectX مشاهده کرد). این راه حل تنها تا زمانی خوب کار میکند که حافظهٔ جانگهدارها تمام شوند. از طرفی افزودن تعداد زیادی جانگهدار مطلوب نیست زیرا حافظه را بیجهت اشغال میکند.
زبان Objective-C در نسخهٔ 2.0 با افزودن یک سطح اضافی دسترسی به متغیرها، نوع متغیرهای غیرشکننده را فراهم میکند.
یک راه حل مقطعی دیگر استفاده از الگوی Bridge است که گاهی با نام " Pimpl " (اشارهگر به پیادهسازی) شناخته میشود. فریمورک Qt نمونهای از این نوع پیادهسازی است. هر کلاس فقط یک عضو داده را تعریف میکند، که اشارهگری به ساختار نگهدارندهٔ دادههای پیادهسازی است. اندازهٔ اشارهگر به خودی خود بعید است تغییر کند (روی یک پلتفرم ثابت)، بنابراین تغییر دادههای پیادهسازی بر اندازهٔ کلاس عمومی تأثیر نمیگذارد. با این وجود، این روش از شکنندگی تغییرات دیگر مانند افزودن متدهای مجازی به كلاسی كه متد مجازی نداشته، یا تغییر ساختار وراثت جلوگیری نمیكند.
پیونددهندهها[ویرایش]
راه حل دیگر نیز وجود دارد که نیازمند لینکر هوشمندتری است. در نسخهٔ اصلی Objective-C، فرمت كتابخانه وجود نسخههای مختلف از یک كتابخانه را پشتیبانی کرده و امکان انتخاب كتابخانهٔ مناسب در هنگام فراخوانی را فراهم میکند. با این وجود استفاده از این ویژگی همیشه ضروری نیست؛ زیرا آفست فقط برای فیلدها مورد نیاز است و آفست متدها در زمان اجرا محاسبه شده، بنابراین نمیتواند باعث FBI شود. از آن جایی که متدها بیشتر از فیلدها تغییر میکنند، در وهلهٔ اول ObjC مشکلات FBI بسیار کمی داشت و این مشکلات با سیستم نسخهگذاری قابل اصلاح بودند. Objective-C نسخهٔ 2.0 یک «رانتایم مدرن» اضافه کرد که مشکل FBI را برای فیلدها نیز حل کرد. علاوه بر موارد مذکور، زبان TOM از آفستهای محاسبهشده در زمان اجرا در همهجا استفاده کرده و FBI را ناممکن میسازد.
استفاده از کتابخانههای استاتیک به جای كتابخانههای پویا در صورت امكان، راه حل دیگری برای FBI به شمار میرود. زیرا تغییر این نوع کتابخانهها بدون کامپایل مجدد برنامه و به روز كردن آفستهای مورد استفاده ممکن نیست. با این وجود کتابخانههای استاتیک مشکلات خاص خود را دارند. مانند حجم بالاتر باینری نهایی و عدم امکان استفادهٔ «خودکار» از نسخههای جدیدتر کتابخانه در هنگام انتشار.
معماری[ویرایش]
در این زبانها مشکل با الزام وراثت یگانه کاهش مییابد (زیرا این کار پیچیدگی درخت ارثبری را کاهش میدهد)، همچنین استفاده از رابطها به جای کلاسهای پایه با متدهای مجازی، باعث کاهش مشکل میشود. زیرا «رابط» حاوی کد نبوده و تنها ضمانتی است که تمام متدهای اعلان شده توسط هر شیءای که رابط را پیادهسازی میکند، فراهم شود.
روش توزیع[ویرایش]
اگر کد منبع کتابخانهها در دسترس باشد، تمام مشکل از بین میرود. در این صورت یک کامپایل مجدد به سادگی مشکل را حل میکند.
همچنین ببینید[ویرایش]
پیوند به بیرون[ویرایش]
This article "مشکل رابط دودویی شکننده" is from Wikipedia. The list of its authors can be seen in its historical and/or the page Edithistory:مشکل رابط دودویی شکننده. Articles copied from Draft Namespace on Wikipedia could be seen on the Draft Namespace of Wikipedia and not main one.