رفتن به نوشته‌ها

Clean Code : قسمت چهارم – Comments، یه کامنت خوب یه کامنت نوشته نشده است

اول از همه باید در مورد ترجمه نکردن کلمه Comment در تیتر بنویسم. به نظرم این کلمه اگر ترجمه بشه معنای خودشو در برنامه نویسی از دست میده و میتونه با هزاران موضوع دیگه قاطی بشه. در نتیجه در تمام طول متن از Comment و یا کامنت استفاده خواهم کرد تا مشخص باشه که دارم در خصوص چه موضوعی صحبت میکنم. 

مقدمه

طبق معمول پست رو با یک توضیح کوتاه در مورد مطلب شروع میکنم که کلیدی‌ترین بخش هم هست و باقی مطالب تفسیر همین چند جمله هستند. عمو باب در چند خط اول این فصل این موضوع رو اشاره کرده که هیچ چیزی نمیتونه به اندازه یک کامنت با جایگذاری مناسب، خوب باشه.  در نقطه مقابل، هیچ چیزی نمیتونه به اندازه یک کامنت مسخره و بی‌معنی، یک ماژول برنامه‌نویسی رو تحت تاثیر منفی قرار بده و نهایتا هیچ چیز هم به اندازه یک کامنت قدیمی و دو پهلو نمیتونه دروغ و اطلاعات غلط پراکنده کنه. 

استفاده از کامنت در واقع به این معناست که شما نتونستید منظور خودتون رو از طریق نوشتن کد ابراز کنید. پس اگر احساس نیاز میکنید که یک کامنت برای قسمتی از کدتون بنویسید، یکبار دیگه به کدتون برگردید و ببینید که میتونید تمام اون چیزی که کامنت میخواد ارائه کنه رو از طریق کد هم بنویسید یا نه؟

چرا اینقدر به کامنت‌ها ایراد میگیریم؟ چون دروغ میگن. نه همیشه و نه از روی عمد اما تعداد این اتفاق زیاد هست. هرچقدر یک کامنت عمرش طولانی‌تر میشه میزان اطلاعات غلط و دروغ‌هاش هم بیشتر میشه. علت هم واضحه: برنامه نویس‌ها کامنت‌ها رو به خوبی Maintain یا اصطلاحا نگهداری نمیکنن. حقیقت کد در کامنت‌ها نیست بلکه تو خود کد نوشته شده. کامنت‌‌ها وظیفه اجرایی ندارند و این کد هست که خروجی نهایی رو ارايه می‌کنه، پس بهتره که تمرکز بر روی کد باشه.

کامنت عذری برای کد بد نیست

در پروژه‌ای وظیفه داشتم که اطلاعات حساسی رو بر روی یک سخت‌افزار مهم ایجاد و بعد در اختیار مشتری قرار بدم. وقتی که کد رو میخوندم در وسط کد با چیزی شبیه کد پایین مواجه شدم:



public String generatePassword(){
    //......
    return "4848";
 // I did not have time to fix this problem, please fix it! 
}

تصور کنید که متدی با اسم generatePassword داره یک عدد ثابت رو برمیگردونه و بعد از روی کامنت کد متوجه میشید که این کد از اول هم کار نمیکرده و برنامه نویس فقط یک عدد ثابت رو به عنوان کلید اصلی سخت افزار داره برمیگردونه. این کامنت چیزی رو در اشتباه برنامه‌نویس عوض نمیکنه. کد رو هم درست نمیکنه. در نتیجه بودن یا نبودنش تاثیری نداره! پس اگر فکر میکنید که دارید با نوشتن کامنت برای توضیح کد به افراد دیگه لطف میکنید یه بار دیگه به موضوع نگاه کنید، شما یه کد کثیف رو دارید به دیگران کثیف‌تر تحویل میدید.

کامنت خوب

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

کامنت حقوقی (Legal)

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


// Copyright (C) 2003,2004,2005 by Object Mentor, Inc. All rights reserved.
// Released under the terms of the GNU General Public License version 2 or later.

کامنت آگاهی‌رسان (Informative) 

بعضی شکل‌های کامنت هستند که اطلاعات تکمیلی خیلی خوبی در مورد کد نوشته شده می‌دهند که بهتره طوری نوشته بشن که در طول زمان هم عملکرد ثابتی داشته باشند. 


// format matched kk:mm:ss EEE, MMM dd, yyyy Pattern timeMatcher = Pattern.compile(
"\\d*:\\d*:\\d* \\w*, \\w* \\d*, \\d*");

توضیح علت استفاده (قانع کردن)

اگر به عنوان برنامه‌نویس برای پیاده سازی راه حل یک مساله ۱۰ راه وجود داشته باشه و شما فقط یک بتونید یک راه رو انتخاب کنید، شاید توضیح اینکه چرا این روش رو انتخاب کردید، کامنت بدی نباشه. 


//This is our best attempt to get a race condition 
//by creating large number of threads. for (int i = 0; i < 25000; i++) { WidgetBuilderThread widgetBuilderThread = new WidgetBuilderThread(widgetBuilder, text, parent, failFlag); Thread thread = new Thread(widgetBuilderThread); thread.start(); }

در واقع با اینکار به افراد دیگه این آگاهی رو میدید که شما هم راه‌حل‌های دیگه رو در نظر گرفتید اما در بین اونها، این راه‌حل مناسب‌تر بوده. 

آگاه سازی از عواقب یک کد

اطلاع دادن به برنامه‌نویس‌های دیگه در خصوص عواقب یک کد از طریق کامنت شاید شیوه فوق العاده‌ای نباشه ولی کمک خیلی بزرگی به بقیه خواهد بود. به عنوان مثال کامنت زیر رو ببینید. 


// Don't run unless you
// have some time to kill.
public void _testWithReallyBigFile() {
       writeLinesToFile(10000000);
       response.setBody(testFile);
       response.readyToSend(this);
       String responseString = output.toString();
       assertSubString("Content-Length: 1000000000", responseString);         
       assertTrue(bytesSent > 1000000000);
}

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

کامنت‌های TODO

در پروژه‌آی درخواست بسیار غیر منطقی‌ای از طرف مشتری داشتم. به همین دلیل بالای قطعه کدی که وظیفه عجیب غریبی داشت، کامنت طولانی TODO ای گذاشتم که مشخص میکرد باید بعد از مدتی این کد حذف بشه. کامنت‌های TODO در زمانی باید استفاده بشن که فیچر یا قسمتی از کد حذف، تغییر یا بهتر و حتی ایجاد بشه اما زمان مناسبی برای اون نیست. اما همچنان اجازه ندارید کد بد رو با کامنت پوشش بدید. بعد از مدتی هم انتظار میره که تعداد این کامنت‌ها به صفر برسه. (اما بنا به تجربه این موارد فقط تعداشون افزایش پیدا میکنه!)

کامنت برای تاکید

کامنتی مثل کامنت زیر کمک میکنه که بر روی نحوه پیاده سازی کد تاکید بشه. 


String listItemContent = match.group(3).trim();
// the trim is real important. It removes the starting 
// spaces that could cause the item to be recognized
// as another list.
new ListItemWidget(this, listItemContent, this.level + 1);
return buildList(text.substring(match.end()));

کامنت‌های بد

تقریبا بیشتر کامنت‌‌هایی که در کدهای ما دیده میشن در این دسته قرار میگیرن. اما بگذارید یکبار همه این موارد رو با هم مرور کنیم. 

چرت و پرت گفتن!

فکر میکنم تیتر این قسمت خودش گویاست! کد جای شوخی، ارايه بدیهیات به شکل‌های مختلف نیست. همچنین اگر در جایی از کد احساس میکنید که باید کامنت بذارید اینکار رو انجام بدید اما همیشه قبل از اینکار از ضروری بودنش مطمئن بشید. 


public void loadProperties() {
    try {
        String propertiesPath = propertiesLocation + "/" + PROPERTIES_FILE; FileInputStream propertiesStream = new FileInputStream(propertiesPath);
        loadedProperties.load(propertiesStream);
        }
    catch(IOException e) {
    // No properties files means all defaults are loaded
        }
     }

واقعا نوشتن یک خط توضیح در قسمت catch هیچ کمکی به هیچ کس نکرده و حتی باعث گمراهی هم خواه شد که واقعا چه اتفاقی در قسمت try داره رخ میده که در قسمت catch باید توضیح داده بشه! 

کامنت‌های اجباری

در برخی از شرکت‌ها برخی قوانین عجیب در مورد کامنت وجود دارد که باعث ایجاد کامنت‌های نادرست و بد شکل در کد خواهند شد. مثلا مثال زیر:


/** *
* @param title The title of the CD
* @param author The author of the CD
* @param tracks The number of tracks on the CD
* @param durationInMinutes The duration of the CD in minutes */
public void addCD(String title, String author,int tracks, int durationInMinutes) {
        CD cd = new CD(); 
        cd.title = title; 
        cd.author = author; 
        cd.tracks = tracks; 
        cd.duration = duration; 
        cdList.add(cd);
}

کامنت‌های بالای متد addCD دارن برای حل چه مشکلی تلاش میکنند؟ یادمون باشه که استفاده بیش از حد از کامنت در کد نشانه ضعف ما در ارایه مطالب به صورت کد هست. 

کامنت‌های تاریخچه‌ای

سالها قبل از برنامه نویس شدن من، زمانی که سورس کنترل‌ها وجود خارجی نداشتند لازم بود تغییرات هر کلاس به صورت کامنت به فایل‌ها اضافه بشن اما امروز که این ابزارها وجود داره، نوشتن این رخدادها در کد به وسیله کامنت‌ها غیر ضروری و کد بد محسوب میشه. 


* Changes (from 11-Oct-2001)
* --------------------------
* 11-Oct-2001 : Re-organised the class and moved it to new package 
* 05-Nov-2001 : com.jrefinery.date (DG);
* 12-Nov-2001 : Added a getDescription() method, and eliminated NotableDate class (DG);

کامنت‌های مزاحم

استفاده بیش از حد از کامنت فقط باعث عدم خوانایی کد میشه. 


/*** Default constructor. */
protected AnnualDateRule() { }

نمونه‌های دیگری که نباید استفاده کنید

  • اگر میتونید کد بنویسید، کامنت رو جایگزینش نکنید!
  • خیلی از اوقات برنامه‌نویس‌های کم تجربه‌تر، کدهایی که کامنت شدن رو دوباره کامیت میکنن که این یکی از بزرگترین اشتباه‌ها در ایجاد کامنت هست. اینکار باعث میشه تا برنامه نویس بعدی از پاک کردن این کد اطمینان نداشته باشه، در نتیجه این کامنت تا مدت‌ها در سورس باقی می‌مونه. 
  • اطلاعاتی که مربوط به فضای بیرون سورس شماست وارد نکنید. 

/**
* Port on which fitnesse would run. Defaults to 8082. *
* @param fitnessePort
*/
public void setFitnessePort(int fitnessePort) {
    this.fitnessePort = fitnessePort; 
}
  •  
  • نام نویسنده کد رو به صورت کامنت وارد نکنید. هنوز هم بعضی از IDE ها این شیوه از کامنت‌ها رو به صورت template در هنگام ساختن کلاس اضافه می‌کنند که میتونید حذفشون کنید. اما در کل کمکی به کد نمیکنند. 

/* Added by Rick */

به طور کلی بهترین تصمیم، استفاده از کردن کامنت‌ها به صورت جزیی هست. به شکلی که با مرور زمان همچنان ثابت باشند و همیشه در خصوص بخش کوچیکی از کد توضیح بدن. البته کامنت‌ها همونطور که باید جزیی باشن، باید بسیار واضح و قابل رویت هم باشن که خواننده کد متوجه اون بشه. 

 

Photo by Markus Spiske on Unsplash

منتشر شده در clean codeرشته بلاگ

نظر

  1. سروش سروش

    مطلب بسیار خوبی بود علی جان، بنظرم اون آموزش جاوا که مد نظرت بود رو به همین صورت ادامه بدی خیلی‌ها استفاده می‌برند.

دیدگاه‌ها غیرفعال هستند.

Translate »