گزارشی از Deprecate شدن یک متد در جاوا!

امروز می‌خواستم برنامه جیتسی رو از AUR دانلود کنم اما به یه دلیل جالب موفقیت‌آمیز نبود. اما مشکل چی بود؟ بیاید کمی عمیق‌تر نگاه کنیم.


در مورد AUR

یکی از قابلیت های دوست داشتنی توزیع‌های مبتنی بر arch linux، مخزن نرم افزاری AUR هست (مخفف arch user repository). همونطور که از اسمش پیداست، توسط کاربرا نگه‌داری می‌شود. هر کاربر می‌تونه برنامه دلخواهش رو بعلاوه روش نصب خودکارش توی AUR قرار بده تا کابرای دیگه بتونن استفاده کنن. مثلا لینک Jisit در AUR.

خوبیِ این مخزن اینه که به بسیاری از نرم‌افزار‌ها به سادگی و بدون نیاز به کامپایل کردن دستی سورس‌کد می‌شه دسترسی داشت. بدیش هم اینه که طبیعتا کسی این‌ها رو تایید نکرده و ریسک مخرب بودن وجود داره.

راستی، برای استفاده از AUR، باید برنامه مخصوص نصب کنید و با خود پکیج منجیر پک‌من، این قابلیت وجود نداره. معمولا به این برنامه‌ها AUR helpers می‌گویند. برنامه‌های زیبا و متعددی وجود دارد، من از yay استفاده می‌کنم که رابطی شبیه خود pacman دارد.

مشکل کامپایل نشدن Jitsi

دانلود برنامه از AUR چند بخش داره. اول فایل PKGBUILD دانلود می‌شه که در واقع روش نصب اون برنامه هست. بعدش طبیعتا باید یه سری فایل دانلود بشه که سورس‌کد هستند. در آخر طبق اون روش نصب کامپایل شده و نصب اتفاق می‌افته. معمولا مشکل نصب نشدن از AUR به خاطر تحریمه چون فایل دانلودی روی source forge قرار داره،، اما اینبار دانلود بدون مشکل انجام شد. هش‌ها هم با موفقیت چک شدن و همه‌چیز برای نصب درست بود.

همونطور که در تصویر می‌بینید، دانلود موفقیت‌آمیز بوده و مشغول باز کردن فایل زیپ شده.
همونطور که در تصویر می‌بینید، دانلود موفقیت‌آمیز بوده و مشغول باز کردن فایل زیپ شده.


مساله این بود که زمان کامپایل کردن سورس‌کد، کامپایل‌ارور داد و موفقیت‌آمیز نبود.

اما مشکل چی بود؟

زمانی که سورس‌کد را با آخرین نسخه جاوا (چون تا این لحظه ۱۵ روی مخازن نیومده، نسخه ۱۴) کامپایل می‌کردم یک سری کلاس رو پیدا نمی‌کرد، یک سری هم وارنینگ deprecate بودن می‌داد.

سوالی که پیش میاد اینه که Deprecate چیه.

در مورد Deprecate

توی برنامه نویسی هم مثل دنیای بیرون، همه چیز فانی است (!) و عمر بی‌نهایت وجود نخواهد داشت. هر محصول/زبان/فریم‌ورکی یک روز ساخته می‌شود، تا مدت کم یا زیادی پشتیبانی می‌شود و توسعه داده می‌شود و زمانی هم باید از بین برود.

شاید معروف‌ترین مثال این روز‌ها adobe flash بود که به دلیل مشکلات امنیتی و باگ‌های زیاد بالاخره تصمیم گرفته شد که در پایان سال ۲۰۲۰ برای همیشه نابود شود.

در برنامه‌نویسی هم خیلی از وقت‌ها یک تابع/متد به دلیل ضعف در پیاده سازی یا ناامن بودن یا آمدن راه‌های بهتر و سریع‌تر باید از دور خارج شوند اما این اتفاق یک‌باره اتفاق نمی‌افتد. بلکه شرکت سازنده در یک نسخه این کلاس/تابع را Deprecate اعلام می‌کند. به این معنی که با چیزهای بهتری جایگزین شده و بهتر است استفاده نشود و ممکن است در نسخه‌های آتی حذف شود.

یکی از صدها وارنینگ زمان کامپایل!
یکی از صدها وارنینگ زمان کامپایل!

نتیجه استفاده از کلاس‌ها و متد‌های Deprecate شده چیست؟ در مرحله اول زمان کامپایل وارنینگی به شکل بالا دریافت می‌کنیم. اما این تمام اتفاق نیست. همانطور که گفتیم هدف Deprecate شدن، حذف و نابودی است بنابراین در نسخه‌های آتی برنامه ما اصلا کامپایل نخواهد شد چراکه آن کلاسی که استفاده کرده‌ایم حذف شده و دیگر اصلا وجود ندارد!

در این نسخه از Jitsi هم از چندین متد و کلاس Deprecate شده استفاده شده بود مثل تصویر بالا که این به تنهایی مشکل ایجاد نمی‌کند. مشکل از جایی شروع می‌شود که در نسخه‌‌ی جاوای من آن api حذف شده و دیگر قابل استفاده نیست. طبیعتا نتیجه کامپایل‌ارور خواهد بود.


مشکل چطور برطرف شد؟

برای برطرف کردن مشکل چند راه پیش رو داشتم، اول اینکه بیخیال نصب برنامه بشوم و به استفاده از اسکایپی ادامه بدهم! راه دوم اینکه سورس‌کد را باز کنم و آن قسمت‌ها را بازنویسی کنم.

اما در زمان کم چه فکری کردم؟ بله! استفاده از یک جاوای قدیمی‌تر. نسخه جاوای سیستمم را موقتا به jdk8 تغییر دادم و مشکل برطرف شد و به درستی نصب و کامپایل شد!


چرا این متد‌ها Deprecate شده‌بودند؟

من با کلاس اصلی‌ای حذف شده‌بود و باعث کامپایل‌ارور شده بود آشنا نبودم (شاید به همین دلیل که من تازه جاوا یاد گرفته‌ام و این کلاس سال‌هاست که برای استفاده مناسب نیست!)

اما مواردی که وارنینگ می‌داد و تصویرش را در بالا هم آوردم را می‌توانم توضیح بدهم!

کد زیر را در نظر بگیرید:


این wrapper‌ها همیشه توی جاوا مشکل‌ساز بودند! قضیه از این قرار است که که همه چیز توی جاوا شی است به جز داده های اولیه مثل int و long و char. اما بعضی جاها مثلا لیست (به طور عمومی‌تر جنریک‌ها)، ما نیاز داریم که با آبجکت کار کنیم (برخلاف تمپلیت توی cpp). پس برای تبدیل نوع داده‌های اولیه به کلاس، کلاس‌های wrapper برای نوع داده های اولیه تعریف کردند.

کدی که اینجا نوشته در قسمت new Integer(98) تلاش می‌کند از روی primitive، یک آبجکت wrapper تولید کند. اما ایراد چیه؟

چون استفاده از اعداد خیلی مرسومه و سرعت هم بسیار اهمیت دارد، برای بهینه‌سازی constructor معمولی را deprecate کردند و به جای آن استفاده از Integer.valueOf را معرفی کردند. چرا؟ چون به ازای هر استفاده از عدد (لزوما) یک آبجکت جدید ساخته نشود، بلکه برای بازه‌ی پر استفاده و کوچک (−۱۲۸ تا ۱۲۷) از آبجکت‌های کَش‌شده استفاده بشود تا سربار ساخت آبجکت جدید نداشته باشیم.

نتیجه‌گیری

۱- جاوا مستقل از سکو هست؟ معمولا بله ولی در صورتی بی‌دقتی شایدم نه، البته نه به دلیل تفاوت platform بلکه به دلیل تفاوت نسخه‌های جاوا.

۲- همیشه اخبار Deprecate شدن را جدی بگیریم و در برنامه خود از این متدها/کلاس‌ها استفاده نکنیم.

۳- هیچوقت توی کدی که به دست کاربر می‌دهیم، وارنینگ‌ها را به عنوان ارور در نظر نگیریم چون در صورتی که یک متد مورد استفاده ما بعدا Deprecate شود، برنامه کامپایل نمی‌شود در حالی که تا حذف شدن کامل آن هنوز چند نسخه‌ای باقی است.

۴- فعال باشید و از خواندن سورس‌کد نترسید.