خب رفقای راکتی سلام، امیدوارم سالم و سرحال باشین و تا اینجای کار از مطالب استفاده کرده باشین و براتون مفید بوده باشه، امروز میریم که ادامهی خلاصهی فصل دوم کتاب کد تمیز رو براتون بگیم.
توی بخش قبلی توضیح دادیم که چه نکاتی رو باید در زمان نامگذاری بهشون توجه کنین و تک تک توضیحشون دادیم ( اگه احیاناً فراموش کردین یه نگاه به پایین بندازین تا یادتون بیاد)
۱. استفاده از اسمهایی که منظور شما رو بیان کنند.
۲.از دادن اطلاعات اشتباه خودداری کنید.
۳.تفاوتهای معنادار ایجاد کنید.
۴.از اسمهای قابل تلفظ استفاده کنین.
۵.از اسمهای قابل جستجو استفاده کنین.
۶.از رمزگذاری دوری کنید.
۷.از mental mapping خودداری کنید. (به عبارتی استفاده از اسمهایی که برنامهنویسان قبلاً اونها رو با نام دیگری میشناسند)
۸. نام کلاسها.
۹.نام متدها.
۱۰.بانمک بازی درنیارین.
۱۱.برای هر مفهوم یک کلمه انتخاب کنین.
۱۲.ایهام ایجاد نکنید.
۱۳.از دامنه کلمات مرتبط با راهحل استفاده کنین.
۱۴.از دامنه کلمات صورت مسأله استفاده کنین.
۱۵.کانتکست با معنی اضافه کنین.
۱۶.کانتکست بیخودی اضافه نکنین.
تو بخش قبلی تا مورد ششم رو براتون گفتم و اما بریم که ببینیم در ادامه عمو باب چی گفته …
از mental mapping خودداری کنید
به طور کلی نباید از اسمهایی استفاده کنید که برنامهنویس در ذهنش اونها رو به اسمهای دیگهای که از قبل میشناسه ترجمه کنه.
این مشکل مربوط به متغییرهای تک حرفیه، به طور مثال i ، j یا k همیشه از قدیم به عنوان متغییر حلقه استفاده میشدند. البته با وجود این، انتخاب یک نام تک حرفی زیاد انتخاب جالبی نیست.
در کل برنامهنویسا آدمای خیلی باهوشی هستن و آدمای باهوش دوس دارن با نشون دادن تواناییهاشون میزان هوش خودشون رو به نمایش بزارن ( به عبارتی شواف یاshow off کنن).
اما تفاوت بین یک برنامهنویس هوشمند با یه برنامهنویس حرفهای این هست که حرفهایها میدونن که شفافیت چقدررر مهمه؛ پس حرفهایها از توانایی خودشون برای نوشتن کدی که دیگران بتونن به راحتی اون رو درک کنن استفاده میکنند.
نام کلاسها
کلاسها و آبجکتها باید اسمهایی مثل Account، WikiPage، Customer و AdressParser داشته باشن و نبایداز کلماتی مثل Data، Processor، Manager و Info برای نام کلاسها استفاده کنید. نام کلاس نباید یک فعل باشد.
نام متدها
برای نامگذاری متدها باید از فعل یا عبارات دارای فعل مثل DeletePage، postPayment یا save استفاده کنید. Accessorها، mutatorها، و predicateها رو هم باید با مقادیر خودشون نامگذاری کنید و طبق استاندارد javabean، از پریفیکسهای set، get و is استفاده کنید.
String name = employee.getName();
customer.setName("mike")
if (paychech.isPosted()) ...
وقتی که constructor متدها( متدهای سازنده) زیاد میشن، از factory method های استاتیک با اسمهایی که آرگومانها را توصیف میکنند استفاده کنید. به طور مثال این خط کد :
Complex FulcrumPoint = Complex.FromRealNumber(23.0);
از این خط کد بهتر هست :
Complex FulcrumPoint = new Complex(23.0);
بانمک بازی درنیارین
استفاده از اسمهایی که خیلی هوشمنداس،فقط در ذهن افرادی موندگار میشه که از نظر شوخطبعی شبیه به نویسنده اصلی باشن، البته اونم تا وقتی که اون شوخی رو به یاد بیارن. مثلاً یک فانکشن با اسم HolyHandGrenade دقیقاً چیکار می کنه؟خب اره بامزس اما قطعاً DeleteItems اسم خیلی بهتریه. اغلب این بامزگیا به صورت محاوره ظاهر میشن، مثلاً از ()whack به جای ()kill استفاده نکنین؛ همینطور استفاده از شوخیهای خاص مختص به یک فرهنگ مثل استفاده از eatMyShors به جای abort هم کار درستی نیست.
شفافیت رو انتخاب کنید نه سرگرمی!
برای هر مفهوم یک کلمه انتخاب کنین
برای هر مفهوم یک کلمه انتخاب کنین و تا آخر بچسبید به همون! به طور مثال استفاده از retrieve، fetch و get به عنوان اسم یک متد یکسان در کلاسهای متفاوت گیجکننده هست.
محیطهای ویرایشی مدرن مثل Eclipse و IntelliJ به شما context-sensitive clues ( یا به عبارتی سرنخهایی که به متن حساس باشن) میدن، اما توجه کنین که لیستی که به شما میده شامل کامنتهای مختلفی که برای اسم فانکشن و لیست پارامترهاتون نوشتید نمیشه. شما باید بتونید بدون جستجوهای اضافی به چیزی که میخوایید برسید.
یک واژه نامه متناقض میتونه لطف بزرگی به برنامهنویسهایی که باید از کد شما استفاده کنن باشه.
ایهام ایجاد نکنید
از استفاده از یک کلمه برای دو منظور متفاوت خودداری کنین، درواقع استفاده از یک اصطلاح یکسان برای دو ایدهی متفاوت ، ایجاد ایهام هست.
اگه از قانون بالا یعنی ( استفاده از یک کلمه برای هر مفهوم ) پیروی میکنین، به طور مثال میدونید که خیلی از کلاسها مثلاً یک متد مثل add دارن، خب تا وقتی که لیست پارامترها و مقادیر برگشتی ( return value ) در متدهای مختلف با نام add معنای یکسانی داشته باشن، همه چیز درسته؛ اما شاید یکی بیاد و تصمیم بگیره که از کلمه add برای مفهومی غیر از اضافه کردن استفاده کنه، مثلاً کلاسی داریم که دارای متدی هست که یک پارامتر جدید رو داخل یک کالکشن قرار میده، خب حالا باید اسم این متد رو add بزاریم؟
ممکنه متدهای دیگهای به اسم add داشته باشیم و این متد هم با اونا سازگار به نظر برسه ولی در این حالت، مفاهیم متفاوتی داریم. مثلاً میتونیم به جای add از insert یا append استفاده کنیم.
یه بار دیگه عرض میکنم : شفاف بنویسید، طوری که نیاز به مطالعه عمیق نداشته باشه و سریع قابل فهمیدن باشه.
از دامنه کلمات مرتبط با راهحل استفاده کنین
یادتون باشه که آدمایی که قراره کد شما رو بخونن،برنامهنویس هستند؛ بنابراین از اصطلاحات علوم کامپیوتر، نام الگوریتمها، اصلاحات ریاضی و موارد اینطوری استفاده کنین، عاقلانه نیست که هر اسمی رو از دامنه صورت مسأله انتخاب کنیم، چون نمیخواییم همکارانمون رو مجبور کنیم تا از مشتری سؤال بپرسه در صورتی که خودش مفاهیم رو با اسمهای دیگهای میشناسه.
مثلاً اسم AccountVisitor برای برنامهنویسی که با پترن VISITOR آشناست، خیلی پرمعنیه. چه برنامهنویسی هست که ندونه JobQueue چیه؟
انتخاب نامهای تکنیکال یا به عبارت دیگه فنی، برای موارد فنی زیادی که برنامهنویسان انجام میدن، معمولاً مناسبترین روش هست.
از دامنه کلمات صورت مسأله استفاده کنین
وقتی هیچ اصطلاح برنامهنویسی برای کاری که انجام میدین وجود نداره، از دامنه کلمات صورت مسأله استفاده کنید. حداقل این کار این هست که برنامهنویس میتونه از یک متخصص دامنه سؤال کنه که منظور فلان چیز چیه؟
جداکردن دامنه کلمات راهحل و صورت مسأله بخشی از کار یک برنامهنویس و طراح خوب هست. کدی که ارتباط بیشتری با مسائل مربوط به صورت مسأله داره، باید از نامهایی استفاده کنه از صورت مسأله گرفته شده باشه.
کانتکست با معنی اضافه کنین
خب میدونید که فقط یه سری از اسمها هستن که به خودی خود بامعنی هستن و بقیه اکثراً بیمعنین. در اینجا باید این اسمهارو در کلاسها، فانکشنها و … قرار بدین تا خواننده در جریان موضوع قرار بگیره.البته استفاده از پریفیکس هم یکی از راه حلهاست.
فکر کنین که متغییرهایی با اسمهای State، city، houseNumber، street، lastName، firstName و zipcode دارین، که همشون باهم یک آدرس رو تشکیل میدن. اما حالا فرض کنین که متغییر State رو تنها ببینین! آیا خودکار میفهمین که این بخشی از یک آدرس هست؟ خب میتونید به اونا پریفیکس اضافه کنین: addrState، addrLastName، addrFirstName و … و اینطوری حداقل خواننده میفهمه که این متغییر جز یک ساختار بزرگتره، البته راهحل بهتر این هست که یه کلاس به اسم Address درست کنین و بعد حتی کامپایلر هم میفهمه که متغییرها متعلق به یک ساختار بزرگتر هستن.
یک متد را در ( Listing 2-1 ) درنظر بگیرین؛ فکر میکنین متغییرها به یک ساختار بامعنیتر نیاز دارن؟ بعد از اینکه این فانکشن رو خوندید متوجه میشید که متغییرهای verb، number و pluralModifier بخشی از پیام "guess statistics" هستند. متأسفانه با اولین نگاه، معنی متغییرها مبهم هست و مفهوم اونها باید حدس زده بشه.
Listing 2-1 Variables with unclear context.
private void printGuessStatistics(char candidate, int count)
{
String number;
String verb;
String pluralModifier;
if (count == 0){
number = "no";
verb = "are";
pluralModifier = "s";
} else if (count == 1) {
number = "1";
verb = "is";
pluralModifier = "";
} else {
number = Integer.toString(count);
verb = "are";
pluralModifier = "s";
}
String guessMessage = String.format( "There %s %s %s%s", verb, number, candidate, pluralModifier );
print(guessMessage);
}
خب همونطور که میبینید این فانکشن یکم طولانیه، بنابراین اون رو به بخشهای کوچکتر تبدیل میکنیم و برای این کار یک کلاس GuessStatisticsMessage ایجاد میکنیم
و سه فیلد متغییر این کلاس رو میسازیم، و بعد هم یک متن واضح برای هر سه فراهم میکنیم. این سه متغییر به طور قطع بخشی از GuessStatisticsMessage هستند.
این کار (یعنی شکستن کد به قطعات کوچتر) باعث تمیزتر شدن و افزایش خوانایی کد میشه.
Listing 2-2 Variables have a context.
public class GuessStatisticsMessage{
private String number;
private String verb;
private String pluralModifier;
public String make(char candidate, int count){
createPluralDependentMessageParts(count);
return String.format( "There %s %s %s%s", verb, number, candidate, pluralModifier );
}
private void createPluralDependentMessageParts(int count{
if (count == 0){
thereAreNoLetters();
} else if (count == 1) {
thereIsOneLetter();
} else {
thereAreManyLetters(count);
}
}
private void thereAreManyLetters(int count) {
number = Integer.toString(count);
verb = "are"; pluralModifier = "s";
}
private void thereIsOneLetter() {
number = "1";
verb = "is";
pluralModifier = "";
}
private void thereAreNoLetters() {
number = "no";
verb = "are";
pluralModifier = "s";
}
}
کانتکست یا متن بیخودی اضافه نکنین
خب فرض کنین که یک اپلیکشین با اسم Gas Station Deluxe داریم، حالا اینکه بیاییم به همهی کلاسهامون پریفیکس GSD بدیم خیلی ایدهی بدیه. صادقانه بگم، با این کار واسه خودتون دردسر درست میکنین.
مثلاً کلاس MailingAddress رو با پریفیکس GSD بنویسید (GSDAccountAddress) و خب با این کار فقط یک سری کاراکتر بیخودی رو اضافه کردین. معمولاً تا زمانی که نامهای کوتاه واضح باشن، استفاده از نامهای طولانی کار بیهودهایه، پس هیچ وقت هیچ متنی بیشتر از اون چیزی که نیاز هست اضافه نکنین.
حرف آخر …
سعی کنین این قوانین رو دنبال کنین تا خوانایی کد خودتون رو بهبود ببخشید. از تغییر دادن اسمهاتون نترسید و بهترین چیزی که ممکن هست رو انتخاب کنین؛ مطمئن باشین بعد از یه مدت کوتاه نتیجه رو میبینید و در طولانی مدت هم این مسأله به شما کمک خواهد کرد.
خب فصل دوم تموم شد، امیدوارم که مفید بوده باشه، در پست بعدی فصل سوم رو شروع خواهیم کرد و درباره فانکشنها صحبت میکنیم و در نهایت از وقتی که گذاشتید ممنونم.
دیدگاه و پرسش
برای ارسال دیدگاه لازم است وارد شده یا ثبتنام کنید
ورود یا ثبتنامدر حال دریافت نظرات از سرور، لطفا منتظر بمانید
در حال دریافت نظرات از سرور، لطفا منتظر بمانید