معرفی ابزارهای خط فرمان ماژولار، بومی سیستم ماژول و سازگار با ایجنت برای توسعه مدرن جاوا (Java)
نوشته دنی توماس (Danny Thomas)، تیم اکوسیستم جاوا (JVM)
تلاشهای اخیر روی زبان جاوا برای هموارسازی مسیر ورود، شروع یک برنامه جاوا و توسعه آن را با استفاده از تمام قابلیتهای زبان و پلتفرم آسانتر از همیشه کرده است. در انتهای آن مسیر، اکوسیستم ساخت و مدیریت وابستگی جاوا قرار دارد که میتواند نرمافزار را به مقیاس و پیچیدگی عظیمی برساند.
آن اکوسیستم با توسعه مدلهای قوی برای پروژهها، وابستگیها و ساختها به بلوغ رسید. وقتی سیستم ماژول جاوا (Java Module System) فرا رسید، آن مدلها در حال حاضر به استثنای موارد خاصی به توسعهدهندگان خدمت میکردند. در نتیجه، توصیفگر ماژول صرفاً به توصیف دیگری از پروژه تبدیل شد که باید هماهنگ نگه داشته میشد.
ما بسیار هیجانزده هستیم که نسخه پیشنمایش ابزار ja و خانواده ابزارهای قابل ترکیب آن را اعلام کنیم که بر روی قابلیتهای سیستم ماژول جاوا ساخته شدهاند تا یک تجربه توسعه خط فرمان مدرن را برای جاوا فراهم کنند. ما توصیفگر ماژول را میگیریم و آن را به توصیفی کامل از یک پروژه تبدیل میکنیم، به طوری که نسخههای وابستگی به طور طبیعی در کنار دستورات requires و متادیتای ماژول ارائهشده از طریق تگهای مستندات قرار میگیرند:
/**
* @mainClass com.example.application.Main
*/
module com.example.application {
requires com.example.framework; // @1.2.3
}
در ترکیب با ارگونومی خط فرمان که در زبانهای دیگر به آن عادت کردهاید، ایجاد و مصرف ماژولهای جاوا هرگز به این آسانی نبوده است.
ابزارهای قابل ترکیب (Composable Tools)
توسعهدهندگان جاوا مدتهاست که به خوبی توسط ابزارهای گرافیکی پشتیبانی میشوند. یک محیط توسعه یکپارچه (IDE) سورس را قالببندی میکند، بین تعاریف و کاربردها ناوبری میکند، مستندات API را نمایش میدهد و نمای کامپایلشدهای از پروژه را حفظ میکند. این تجربه به قدری کامل بوده است که جاوا کمتر نیاز داشته است تا قابلیتهای مشابه را از طریق ابزارهای کوچک و قابل ترکیب خط فرمان ارائه دهد. هنگامی که ایجنتهای کدنویسی با زبان جاوا کار میکنند، این خلأها به سرعت آشکار میشوند و ایجنتها اغلب برای یافتن وابستگیها، مستندات و سورسها دچار مشکل میشوند.
ابزار ja تنها ارگونومی خط فرمان و ارکستراسیون ابزار را فراهم میکند و هر ویژگی توسط یک ابزار مستقل پشتیبانی میشود. برای بهرهمندی از مزایای این ابزارها نیازی به استفاده کامل از ja ندارید، بلکه میتوانید آنها را به هر طریقی که انتخاب میکنید ترکیب کنید:
- ابزار jig وضوح نسخه ماژول، کامپایل و مونتاژ را انجام میدهد و استدلالهای استاندارد سیستم ماژول را برای استفاده با ابزارهای دیگر خروجی میدهد. این ابزار همچنین پلی به مخازن میون (Maven) و از آنها است که یک پروکسی ماژول مستقل و دستورات انتشار را فراهم میکند.
- ابزار jfmt با استفاده از قراردادهای کد برای زبان برنامهنویسی جاوا، که برای زبان مدرن جاوا تطبیق داده شده است، سورس را قالببندی میکند. این ابزار از فاصله سفید، توربندی، ترتیب ایمپورت و ارجاعات کلاس واجد شرایط بسیار رایج که در کد نوشتهشده توسط ایجنت معرفی میشوند، جلوگیری میکند.
- ابزار jist جستجوی نماد آگاه از سورس را فراهم میکند و یک رابط به سبک گرپ (grep) برای درک فایلهای کلاس و سورسهای مرتبط با آنها ارائه میدهد. این ابزار به ایجنتهای کدنویسی دسترسی به نمادها و سورسها را بدون نیاز به ایندکس کردن، LSPها یا MCPها میدهد و در عین حال از طریق یک قرارداد فایل آرگومان با سایر ابزارهای ساخت تعامل دارد.
- ابزار jdocserver مستندات API قابل مرور محلی را سرو میکند.
این پروژهها از قابلیتهای کشف و اجرای ابزار پلتفرم استفاده میکنند و در نظر گرفته شدهاند که همراه با ابزارهای استاندارد در JDK شما نصب شوند. همه آنها رابط Tool یا ToolProvider را پیادهسازی میکنند که به آنها اجازه میدهد در داخل فرآیند (in-process) اجرا شوند.
این همچنین مدل کشف و اجرای ابزار برای ja است. در آنجا ما از OptionChecker و متادیتای سفارشی اختیاری استفاده میکنیم تا بفهمیم کدام گزینههای سیستم ماژول پشتیبانی میشوند تا بتواند آرگومانها را از طرف ابزار حل کند. این امر یک انتقال یکپارچه از ماژولهای مسیر سورس شما به ابزارهای استاندارد JDK مانند jdeps، jlink و jshell را فراهم میکند.
میون (Maven) به عنوان پایه و اساس
در یک نظرسنجی اخیر از ۱۰۰۰ آرتیفکت محبوب در مخزن مرکزی میون (Maven Central)، تنها ۲۳۲ مورد دارای تعاریف ماژول صریح بودند و ۲۴۸ مورد دیگر نامهای ماژول خودکار را اعلام کردند. ۵۲۸ مورد باقیمانده هیچ نظری درباره نام ماژول جاوا ابراز نکردند. سیستم ماژول همچنین هیچ فرقی بین فضای نام (namespace) و نام ماژول قائل نمیشود، بنابراین ابزارهای ماژولمحور نیازمند راهحلی برای نامگذاری ماژول و مکان آن در مخازن موجود هستند.
خوشبختانه، Maven Central قبلاً به آرتیفکتهای منتشر شده یک فضای نام تأیید شده داده است. ناشران کنترل شناسههای گروه دامنه معکوس را ثابت میکنند که منعکسکننده استدلال دیرینه سوناتایپ (Sonatype) برای فضاهای نام در مخازن عمومی بازبینی است.
ما از این قراردادها برای ایجاد یک مختصات ماژول متعارف میون استفاده میکنیم که یک فضای نام DNS قابل تأیید را با نام کامل ماژول جفت میکند، به عنوان مثال pkg:maven/com.netflix/com.netflix.tools.ja. برای ماژولهای موجود، نویسندگان تصمیم میگیرند یک پم جابجایی تکی میون را در مختصات متعارف منتشر کنند تا امکان کشف مختصات اصلی فراهم شود.
هنگامی که هیچکدام در دسترس نیستند، نامزدها از ریشه فضای نام با استفاده از قراردادهای رایج آرتیفکت میون پیمایش میشوند و مختصات را از نامهای ماژول استنتاج میکنند. ما همچنین لیست کوتاهی از نامهای مستعار را برای محبوبترین ماژولهایی که از نام ماژول DNS معکوس استفاده نمیکنند بستهبندی میکنیم، اما پیشنهاد میکنیم نویسندگان همیشه برای ماژولهای خود فضای نام تعیین کنند. پروکسی ماژول در jig ماژولهای حلشده را با استفاده از قراردادهای مبتنی بر نام فایل برای نامگذاری ماژول نمایش میدهد و حتی ماژولهای خودکار بدون نامهای پایدار را در صورت استفاده با این ابزارها ایمن میسازد.
این قراردادها و استراتژیهای مکانیابی به اکثریت آرتیفکتهای موجود اجازه میدهد تا فقط با استفاده از نام و نسخه ماژول کشف شوند.
یکپارچگی به صورت پیشفرض (Integrity by Default)
عبارت ALL-UNNAMED به دلیل استفاده سنگین از کلاسپث (class path)، متأسفانه در گزینههای دسترسی جاوا رایج شده است. این امر منبع بدهی فنی را که برنامهها با اجازه دادن به چنین دسترسیهایی متحمل میشوند پنهان میکند و با حرکت جاوا به سمت یکپارچگی به صورت پیشفرض (Integrity by Default) اهمیت بیشتری پیدا میکند. به عنوان مثال، آمادهسازی برای قطعی کردن کلمه کلیدی final از برنامهها میخواهد که ماژولهای مجاز برای تغییر فیلدهای final را به طور صریح تأیید کنند.
ما به الزامات دسترسی زمان اجرا اجازه میدهیم به عنوان متادیتای ماژول اعلام شوند و در طول چرخه عمر ماژول همراه با توصیفگر ماژول حمل شوند. به عنوان مثال، یک کتابخانه ممکن است دسترسی مورد نیاز خود را ثبت کند:
/**
* @enableFinalFieldMutation com.example.framework
*/
module com.example.framework {
}
با این حال، برنامه مصرفکننده کنترل را حفظ میکند و باید فریمورک را به طور صریح تأیید کند تا در زمان اجرا در دسترس باشد:
/**
* @mainClass com.example.application.Main
* @enableFinalFieldMutation com.example.framework
*/
module com.example.application {
requires com.example.framework; // @1.2.3
}
رابط خط فرمان برای ja به وابستگی و مجوز اجازه میدهد تا با هم اضافه شوند:
ja require com.example.framework@1.2.3 \
--enable-final-field-mutation com.example.framework
بدون آن مجوز، وضوح وابستگی با عدم رضایت نیاز دسترسی شکست میخورد. دسترسی بومی (Native access) از همان مدل از طریق @enableNativeAccess پیروی میکند و صادرات و باز شدنهای واجد شرایط نیز پشتیبانی میشوند.
یکپارچگی ماژول توسط هشهای مداوم وابستگیهای باینری حل شده در یک فایل module-info.hash تضمین میشود، وضوح متوالی آن هشها را بررسی میکند و آرتیفکتی را که تغییر کرده است رد میکند.
ما همچنین یک قدم فراتر از بهبودهای اخیر در امنیت پردازنده انوتیشن (annotation processor) برمیداریم و پردازش انوتیشن را به عنوان یک مرحله صریح تولید کد در نظر میگیریم. سورسهای حاصل در کنار سورس ماژول معمولی قرار میگیرند و آنها را در بررسی کد قابل مشاهده میکنند و به یک ماژول اجازه میدهند بدون اجرای کد تولیدکننده مونتاژ شود.
ماژولها را پیشفرض خود قرار دهید
ما معتقدیم که هر پروژه جاوا باید ماژولار باشد، صرف نظر از ابزار ساختی که استفاده میکنید. اگر شما یک نویسنده کتابخانه هستید که ماژولهای خودکار تولید میکنید، شما را تشویق میکنیم که از پکیجهای تقسیمشده اجتناب کنید و ماژولهای صریح تولید کنید.
شما میتوانید امروز با ابزارهای ما و با استفاده از راهنمای نصب ما شروع کنید.
منبع: netflixtechblog.com
