نامگذاری کلاسهای جاوایی
هر برنامهنویسی موافق است که نامگذاری کلاسها برای خوانایی کد بسیار مهم است. نامگذاری مناسب، زمان لازم جهت فهم کلی کد را کاهش میدهد. همچنین، بسیاری از توسعهدهندگان موافقند که نامگذاری کلاسها کار سادهای نیست. همواره جستوجوهای بسیار زیادی (نه فقط از سوی تازهکارها) در مورد بهروشهای (best practices) نامگذاری کلاسها صورت میگیرد.
هدف این مقاله، جمعآوری پاسخهای سوالات پرتکرار در زمینه استانداردها و قواعد نامگذاری کلاسها در جاوا به صورت یکجا است. در این مقاله، محدودیتها، قواعد و قراردادهای مرسوم و بهروشهای محبوب نامگذاری کلاس در زبان جاوا، پوشش داده میشود.
قواعد و محدودیتها
زبان جاوا از نظر محدودیتهای فنی برای نام کلاس، کاملا انعطافپذیر است. اما در حالت واقعبینانه، برنامهنویسان به ندرت از این انعطافپذیری استفاده میکنند.
حداکثر طول مجاز برای نام کلاس
طبق specification زبان جاوا، طول نام کلاس نامحدود است. اگرچه در عمل، اولین محدودیت از سوی JVM ناشی میشود. در JVM فعلی، محدودیت 65525 کاراکتری برای نام کلاس وجود دارد.
علاوه بر این، نام کلاس معمولا برابر با نام فایل است. به همین دلیل، یک فاکتور تاثیرگذار دیگر، حداکثر طول نام فایل است. در ویندوز و لینوکس، حداکثر طول نام فایل 260 کاراکتر است. با احتساب 5 کاراکتری که برای پسوند java. صرف میشود، 255 کاراکتر برای نام کلاس باقی میماند.
کاراکترهای مجاز در نام کلاس
طبق specification جاوا، نام کلاس باید مجموعهای از Java letterها و Java digitها باشد. همچنین، اولین کاراکتر حتما باید یک حرف (letter) باشد.
Java letter یا Java digit چیست؟
Java letter، مجموعهای از کاراکترهای یونیکد، کاراکتر underscore(_) و علامت دلار ($) است. Java digit هم مجموعه اعداد 0 تا 9 است. ایده مجاز بودن کاراکترهای یونیکد در نام کلاس، برای اجازه دادن به برنامهنویسی به زبان مادری توسعهدهندگان در سراسر دنیا است. اما خیلی از این قابلیت استفاده نمیشود و معمولا، برنامهنویسان خود را به الفبای انگلیسی محدود میکنند.
قراردادها و استانداردها
جاوا یک زبان برنامهنویسی نسبتا قدیمی است. در طول سالها، توسعهدهندگان چندین استاندارد مورد توافق برای نامگذاری کلاسها را به وجود آوردهاند. این استانداردها نسبت به محدودیتهای specification جاوا، بسیار سختگیرانهتر هستند. قواعد نامگذاری، باعث میشود که دیگران بتوانند کد شما را به آسانی بخوانند.
در ادامه پاسخ محبوبترین سوالات پیرامون قواعد نامگذاری را میتوانید ببینید.
عبارت اسمی یا فعلی؟
در برنامهنویسی شیگرا، یک کلاس، نشاندهنده یک موجودیت از دنیای واقع است (Classes describe things). صرفا به کلاسهای کلاسیکی مثل User و Message و Event فکر کنید.
البته میدانید که کلاسهای یک کلمهای این چنینی، بسیار کمیابند و ما معمولا از عبارتهای اسمی برای شرح بهتر اسامی کلاسها استفاده میکنیم. مانند AnonymousUser یا DirectMessage یا UserCreatedEvent. هر چه کلاس غیرانتزاعیتر باشد، جزییات بیشتری در نام آن کلاس ظاهر میشود.
باید فعلها را برای نام متدها رزرو کنید. زیرا متدها نشاندهنده عملیاتی هستند که توسط اشیا انجام میشود.
اسامی جمع یا مفرد؟
زمانی که به کلاس به عنوان یک قالب برای اشیا نگاه کنیم، انتخابمان واضح است. در اکثر موارد، اشیایی که میسازیم، نشاندهنده موجودیتهای مفرد است. در واقع تنها یک آیتم از چیزی هستند.
زمانی که با چندین نمونه (instance) کار میکنیم، معمولا از مجموعهها (collections) که در Java Class Library در دسترس هستند، استفاده میکنیم. نام مجموعهها معمولا مفرد است. مثل Map یا List یا Set. پس زمانی که با چندین نمونه از یک کلاس کار میکنیم، معمولا آنها را در قالب یک container با نام مفرد مورد استفاده قرار میدهیم.
اما چند ثانیه دست نگهدارید.
داخل JDK مثاهای نقضی برای این حرف وجود دارد. مثلا کلاسهایی مانند Objects، Arrays و یا Collections.
بر خلاف بیشتر کلاسهایی که ایجاد میکنیم، این کلاسهای JDK، نشاندهنده هیچ موجودیت خاصی نیستند. چیزی که در میان همه آنها مشترک است، این است که نمیتوانیم از آنها نمونهسازی کنیم. اگر باور نمیگمیئ، سعی کنید سازنده Objects را فراخوانی کنید. این کلاسها، صرفا Containerهایی برای متدهای استاتیک و utility هستند. این متدهای utility، به هیچ نمونه خاصی متعلق نیستند.
در آن روی سکه، JDK کلاس String را دارد که میتوان از آن نمونهسازی کرد و همچنین دارای تعداد زیادی متدهای استاتیک utility است. به نظر میرسد که تناقضی در طراحی JDK وجود دارد و شاید به همین دلیل است که همگی ما سردرگم شدهایم.
بنابراین، وقتی صحبت از متدهای استاتیک میشود، قضیه کاملا سلیقهای میشود. میتوانید چنین متدهایی را در یک کلاس با نام مفرد و یا در یک کلاس با نام جمع قرار دهید. در واقع در این مورد هیچ درست و غلطی وجود ندارد و تنها چیزی که اهمیت دارد، این است که با گروهتان هماهنگ باشید.
UserDao vs. UsersDao
این معضل احتمالا در بین غیرانگلیسیزبانان بیشتر وجود دارد و در ادامه همان مشکل قبلی (یعنی مفرد یا جمع بودن نام کلاس) است.
فرض کنید کلاسی دارید که چندین نمونه از انواع مختلف را نگهداری میکند. مانند کلاس repository برای لایه دسترسی به پایگاهداده. آیا در این مورد باید از نام مفرد استفاده کنید یا جمع؟
بگذارید با یک تصویر به این سوال پاسخ دهیم:
شما نام انگلیسی این وسیله را میدانید؟
نامش screwdriver (پیچگوشتی) است.
شما میتوانید چندین screw (پیچ) را با استفاده از screwdriver (پیچگوشی) screw کنید (بپیچانید). با این وجود، در نام این ابزار تنها یک کلمه مفرد پیچ وجود دارد. شباهتش با کلاس DAO را متوجه میشوید؟
نام کلاس مشابه نام فایل
کامپایلر جاوا انتظار دارد که نام کلاس با نام فایلی که در آن تعریف شده است تطابق داشته باشد. اگرچه، این نیازمندی تنها در مورد کلاسهای عمومی (public) مصداق دارد و از نظر فنی، میتوانید یک کلاس غیرعمومی را در یک فایل با نام متفاوت تعریف کنید و یا حتی چندین کلاس را در یک فایل قرار دهید. کامپایلر جاوا شما را از این کار منع نمیکند.
اما صرف اینکه میتوانید نام فایلها را متفاوت با نام کلاس بگذارید، به این معنی نیست که باید این کار را انجام دهید! برنامهنویسان جاوا معمولا موافقند که نام کلاس و نام فایل با هم یکسان باشد. همچنین، داشتن تنها یک کلاس در داخل یک فایل نیز یک استاندارد در نظر گرفته میشود. با چنین رویکردی، ساختار فایلی پروژه را بهتر میتوان درک کرد.
شروع نام کلاس با حرف بزرگ
همانطور که قبلا اشاره شد، بر اساس specification زبان جاوا، نام کلاس باید با یک حرف جاوایی شروع شود. اما در مورد بزرگ یا کوچک بودن آن حرفی نمیزند. بزرگ بودن حرف اول نام کلاس، صرفا یک توافق مرسوم بین برنامهنویسان جاوا برای افزایش خوانایی کد است. زمانی که کلاسی با چندین کلمه ایجاد میکنید، باید حرف اول تمام کلمات، بزرگ باشد. در واقع حرف بزرگ، نقش جداکنندهی کلمات را ایفا میکند.
وجود کاراکتر زیرخط (underscore) در نام کلاس؟
از نظر فنی، بله میتواند. اما هیچ دلیلی برای انجام این کار وجود ندارد. اگر از زیرخط در نام یک کلاس استفاده بشود، باید به عنوان جداکننده کلمات عمل کنند. در جاوا، ما با استفاده از روش camel case این جداسازی بین کلمات را انجام میدهیم. به این ترتیب، با استفاده از زیرخط، به شکلی غیرضروری صرفا طول نام کلاس را افزایش میدهیم.
بهروش طول نام کلاس
چه زمانی میتوان گفت که نام کلاس خیلی طولانی است؟
زمانی نام یک کلاس زیادی طولانی است که عبارت کوچکتری دقیقا با همان مفهوم وجود داشته باشد.
هیچ عدد دقیقی وجود ندارد که در ابزار تحلیل کد استاتیک خود وارد کنید تا طولانی بودن نام کلاس را تشخیص دهد. هدف اصلی نام کلاس، توصیف هدف و مقصود کلاس است. هرچه کلمات کوتاهتر و کمتری در نام کلاس به کار ببرید، خوانایی کد افزایش مییابد.
اما چرا داشتن نامهای کوتاه اینقدر بااهمیت است؟
وجود نامهای طولانی، بر روی خوانایی کد تاثیر منفی میگذارد. نه فقط برای کلاسها، بلکه برای متدها و متغیرها هم این مساله صدق میکند. اسکرول کردن افقی در IDE یا شکستهای خط، باعث حواسپرتی و کاهش تمرکز میشود. زیرا مغز ما خطوط متنی را با دستورات و ساختار برنامهنویسی وفق میدهد اما زمانی که یک دستور تا چند خط ادامه بیابد، از نظر بسیاری از برنامهنویسان، خواندن و دنبال کردن آن دستور دشوار میشود.
اختصار
تنها چیزی که برای کامپایلر مهم است، این است که نام کلاسها یکتا باشد. همین. در واقع کد نوشته میشود که توسط انسانها خوانده شود و نه کامپیوترها.
قبلا بحث کردیم که داشتن نامهای کوتاه، مهم است و استفاده از اختصار هم به نظر راهحلی برای این موضوع است. اما با این حال، اکثر برنامهنویسان ترجیح میدهند از اختصارنویسی اجتناب کنند.
اگرچه، برخی از تیمها بر روی اختصارات یک سری کلمات خاص با هم توافق کرده و در کدهایشان از آنها استفاده میکنند. مخصوصا اگر این کلمات در بسیاری از کلاسها با هدف یکسان به کار رفته باشند. Id یا Config میتواند نمونهای از چنین کلماتی باشد. اگر تیم شما هم از اختصارات استفاده میکند، حتما مطمئن شوید که در تمام کلاسها و در کل پروژه از قاعده یکسانی پیروی شود.
سرواژه
سرواژه کلمهایست متشکل از حرف اول تعدادی کلمه دیگر. تمام حروف در سرواژه، حروف بزرگ هستند. مانند HTML.
اما آیا زمانی که از سرواژه در نام کلاس استفاده میشود، باز هم باید تمام حروفش بزرگ باشد؟
متاسفانه، اگر قراردادهای موجود در Java Class Library را ببینید، با مثالهایی از هر دو رویکرد مواجه خواهید شد. به همین دلیل، برخی افراد به سادگی تصور میکنند که این موضوع اهمیت چندانی ندارد.
اما در کتاب Effectiv Java نوشته Joshua Bloch، توصیه میشود که برای سرواژهها هم از روش camel case استفاده شود. مثالی که مزیت این روش را بهتر نشان میدهد، زمانی است که نام کلاس شامل چند سرواژه باشد که در کنار هم آمدهاند. مانند HttpUrl. اگر همه حروف هر دو کلمه بزرگ باشند، نام کلاس به سختی خوانده خواهد شد.
بهروشهای نامگذاری کلاس
تا اینجا بر روی محدودیتهای فنی و قراردادهای مرسوم نامگذاری کلاسها در جاوا بحث کردیم. وقتش رسید که نکات مفیدی که کار نامگذاری کلاسها را برایتان راحتتر خواهد کرد را با هم ببینیم.
پیروی از اصل مسئولیت واحد
مهمترین توصیهای که در مورد نامگذاری کلاسها در جاوا میتوان کرد، این است که اصل مسئولیت واحد (Single Responsibility Principle) را به خوبی درک کرده و به کار ببرید. به طور خلاصه، این اصل به ما میگوید که یک کلاس، تنها یک دلیل برای ایجاد کلاس باید وجود داشته باشد و نام کلاس هم باید این دلیل را توصیف کند.
البته که تاثیر رعایت این اصل، فقط بر روی نامگذاری کلاس نیست. بلکه کل مسیر طراحی کدتان را تحث تاثیر قرار میدهد. زمانی که به تازگی شروع به کار با این کلاس میکنید، ممکن است به نظرتان ایجاد تعداد زیادی کلاسهای کوچک، عجیب و تکراری باشد. اما خوشبختانه، هر چه بیشتر با این اصل کار کنید، با فوایدش بیشتر آشنا خواهید شد.
شروع با یک نام موقت
اگر زمان ایجاد کلاس، نمیتوانید نام مناسبی برایش انتخاب کنید، فعلا یک نام موقتی مانند ClassX به آن داده و پیادهسازی بدنه کلاس را شروع کنید. به محض اینکه کار پیادهسازی تمام شد، هدف کلاس برایتان شفافتر خواهد بود و نامگذاریاش دیگر کار سختی نباید باشد.
اما حواستان باشد:
اگر از ابتدا هدف شفافی برای کلاستان نداشته باشید، به سادگی ممکن است یک God Object ایجاد کنید. در واقع اگر پس از پیادهسازی کلاس، به دلیل اینکه کلاستان چندین کار مختلف را انجام میدهد، در نامگذاریاش باز هم مشکل داشته باشید، نشونهای است که باید کلاستان را به چند کلاس کوچکتر بشکنید.
پرهیز از مترادفها
خیلی ممکن است پیش بیاید که شما چندین کلاس با هدف یکسان اما در زمینههای (context) متفاوت داشته باشید. برای مثال، کلاسهایی که مسئول ایجاد اشیای متفاوتی هستند. چنین کلاسی را میتوانیم Creator یا Constructor یا Factory بنامیم.
کلمهای که برای توصیف هدف کلاس انتخاب میکنید، ترجیح شخصی شماست. اما باید در سطح کلی اپلیکیشن، به انتخابتان وفادار باشید. افراد جدیدی که به تیمتان وارد میشوند، وقتی با یک نگاه بتوانند متوجه قراردادها شوند، از شما متشکر خواهند بود.
نامگذاری کلاسهای پیادهسازیکننده واسطها
اگر واسطی که دارید که تنها یک کلاس آن را پیادهسازی کرده است و نام آن کلاس هم دقیقا مشابه نام واسط به اضافه Impl است، باید بدانید که یک جای کار ایراد دارد. به احتمال خیلی زیادی، این واسط بیاستفاده است و اگر کل کدتان در داخل یک کلاس ساده با همان نام قرار داشته باشد، کدتان خواناتر است.
زمانی که کلاسی واسطی را پیادهسازی میکند، احتمالا دارای ویژگیهای خاصی است که در نامگذاریاش میتوانید استفاده کنید. مثلا به لیست پیادهسازیهای واسط List نگاه کنید. نام این کلاسها مثل ArrayList و LinkedList، به سادگی یک دید کلی در مورد تفاوت این دو پیادهسازی به شما میدهد.
قراردادهای نامگذاری کلاس Helper و Util
باز هم تنها چیزی که اهمیت دارد، این است که در داخل پروژهتان یکنواخت و یکشکل عمل کنید.
داشتن کلاسهایی با نامهای AccountUtils و Accounts و AccountUtilites، صرفا خوانندهها را گیج میکند. یکی از آنها را انتخاب کرده و در کل پروژه به همان شکل عمل کنید.
جمعبندی
با مطالعه این مقاله، با قراردادها، استانداردها و بهروشهای نامگذاری کلاسها در زبان جاوا آشنا شدهاید. ابتدا در خصوص محدودیتها و رویکردهای مورد توافق و مرسوم صحبت کرده و سپس تعدادی نکته جهت نامگذاری صحیح و راحت کلاسها را با شما در میان گذاشتیم.
آدرس کانال تلگرام: JavaCupIR@
آدرس اکانت توییتر: JavaCupIR@
آدرس صفحه اینستاگرام: javacup.ir
آدرس گروه لینکدین: Iranian Java Developers