خلاصه کتاب کد تمیز – فصل چهارم : کامنت‌ها

31 تیر 1400, خواندن در 9 دقیقه

آيا تاکنون درباره کامنت‌ها چیزی شنیده‌اید؟آیا از فواید و مضرات آن باخبرید؟ چه کامنتی خوب است و چه کامنتی بد؟ چرا وقتی کد هست کامنت میزاریم؟ ویژگی‌های یک کامنت خوب چیست؟ اگررر می‌خواهید یکی از ۱۰ کامنت نویس موفق دنیا باشید ما را دنبال کنید. (‌صرفا جهت مزاح :)))

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

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

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

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

حالا چرا بزرگوار با کامنت مخالف هستن؟ چون کامنت‌ها دروغ میگن:

Code never lies, comments sometimes do

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

کامنت‌ها برای کد بد ساخته نشدن

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

منظور خودت رو با کد برسون!

خب مطمئنا مواردی هست که کد وسیله‌ی قدرتمندی برای توصیف نیست ولی متاسفانه خیلی از برنامه ‌نویسا اینطور برداشت کردن که کد به ندرت میتونه راه خوبی برای توصیف باشه که این کاملا اشتباهه، میگین نه؟ خب خودتون قضاوت کنین دوست دارین کدوم رو ببینید؟ این:

// Check to see if the employee is eligible for full benefits
if ((employee.flags & HOURLY_FLAG) &&
	(employee.age > 65))

یا این؟

if (employee.isEligibleForFullBenefits()

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

خب حالا با تموم این حرفا شاید سوال بشه که پس آیا همه‌ی کامنت‌ها به درد نخورن؟ باید عرض کنم که خیر اینطوریام نیس، بیایین برای توضیح بیشتر این مسئله کامنت‌ها رو به دو گروه کامنت‌های خوب و بد تقسیمشون کنیم:

کامنت‌های خوب

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

کامنت‌های قانونی

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

// 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

کامنت‌هایی که حاوی اطلاعات مفید هستن

یکی دیگه از جاهایی که اگه کامنت بزارین جاتون وسط بهشته اینجاس! در واقع منظورم کامنت گذاشتن برای اطلاعات دادن یا سهولت در بدست آورن اطلاعات راجع به کد هست. مثلا اینو ببینید:

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

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

شرح نیت

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

public void testConcurrentAddWidgets() throws Exception {
	WidgetBuilder widgetBuilder =
	new WidgetBuilder(new Class[]{BoldWidget.class});
	String text = "'''bold text'''";
	ParentWidget parent =
	new BoldWidget(new MockWidgetRoot(), "'''bold text'''");
	AtomicBoolean failFlag = new AtomicBoolean();
	failFlag.set(false);
	//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();
	}
	assertEquals(false, failFlag.get());
}

شفاف سازی و هشدار دادن درباره عواقب یک کار

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

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

یه مثال از هشدار دادن به برنامه‌نویس (که ممکنه خودمون در آینده باشیم) بزنیم که بهتر جا بیفته:

// 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 کامنت میزاریم تا یادمون نره. این روزا IDE های مختلف امکانات مختلفی واسه یادآوری و گم نکردن این موارد ارائه میدن؛ ولی به هر جهت یادتون باشه که TODO هر چی که هست، نباید بهونه‌ای واسه نوشتن کد کثیف توی سیستم باشه!

مثال:

//TODO-MdM these are not needed
// We expect this to go away when we do the checkout model
protected VersionInfo makeVersion() throws Exception
{
	return null;
}

تقویت

ممکنه از کامنت برای بالا بردن اهمیت چیزی استفاده کنین که به نظر بقیه کم اهمیت می‌رسه :

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()));

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

کامنت‌های بد

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

کامنت‌های اضافی

چه لزومی داره وقتی کد گویای همه چیز هست بیای دوباره تو کامنت بنویسی؟ اضافه کاری دوست داری؟ خیلی وقتا این جور کامنت‌ها به جای اینکه مفید باشه فریب دهنده هست چون دقتشون به اندازه کد نیست و اطلاعات اشتباه منتقل میکنن؛ واسه ملموس‌تر شدن قضیه یه نگا به این کامنت‌‌ها بندازین :

Listing 4-2

ContainerBase.java (Tomcat)

public abstract class ContainerBase
        implements Container, Lifecycle, Pipeline,
        MBeanRegistration, Serializable {
        /**
        * The processor delay for this component.
        */
        protected int backgroundProcessorDelay = -1;
        /**
        * The lifecycle event support for this component.
        */
        protected LifecycleSupport lifecycle =
        new LifecycleSupport(this);
        /**
        * The container event listeners for this Container.
        */
        protected ArrayList listeners = new ArrayList();
        /**
        * The Loader implementation with which this Container is
        * associated.
        */
        protected Loader loader = null;
        /**
        * The Logger implementation with which this Container is
        * associated.
        */
        protected Log logger = null;
        /**
        * Associated logger name.
        */
        protected String logName = null;
        /**
        * The Manager implementation with which this Container is
        * associated.
        */
        protected Manager manager = null;
        /**
        * The cluster with which this Container is associated.
        */
        protected Cluster cluster = null;
        /**
        * The human-readable name of this Container.
        */
        protected String name = null;
        /**
        * The parent Container to which this Container is a child.
        */
        protected Container parent = null;
        /**
        * The parent class loader to be configured when we install a
        * Loader.
        */
        protected ClassLoader parentClassLoader = null;
        /**
        * The Pipeline object with which this Container is
        * associated.
        */
        protected Pipeline pipeline = new StandardPipeline(this);
        /**
        * The Realm with which this Container is associated.
        */
        protected Realm realm = null;
        /**
        * The resources DirContext object with which this Container
        * is associated.
        */
        protected DirContext resources = null;
}

Mandated Comments

نکنه میخوای مثه جاواداک بیای واسه همه چی هی کامنت بزاری؟

/**
*
* @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);
}

کامنت‌های ژورنالی

دیده شده بعضی از برنامه‌نویسام میان تغییراتی که ایجاد میکنن رو با تاریخ و ساعت کامنت میکنن، دفتر خاطراتت که نیست برادر/خواهر من، پس سورس کنترل رو برا چی ساختن؟

Changes (from 11-Oct-2001)
--------------------------
* 11-Oct-2001 : Re-organised the class and moved it to new package
* com.jrefinery.date (DG);
* 05-Nov-2001 : Added a getDescription() method, and eliminated NotableDate
* class (DG);
* 12-Nov-2001 : IBD requires setDescription() method, now that NotableDate
* class is gone (DG); Changed getPreviousDayOfWeek(),
* getFollowingDayOfWeek() and getNearestDayOfWeek() to correct
* bugs (DG);
* 05-Dec-2001 : Fixed bug in SpreadsheetDate class (DG);
* 29-May-2002 : Moved the month constants into a separate interface
* (MonthConstants) (DG);
* 27-Aug-2002 : Fixed bug in addMonths() method, thanks to N???levka Petr (DG);
* 03-Oct-2002 : Fixed errors reported by Checkstyle (DG);
* 13-Mar-2003 : Implemented Serializable (DG);
* 29-May-2003 : Fixed bug in addMonths method (DG);
* 04-Sep-2003 : Implemented Comparable. Updated the isInRange javadocs (DG);
* 05-Jan-2005 : Fixed bug in addYears() method (1096282) (DG);

کامنت‌های نویز دار

این کامنتا فقط سرو صدا دارن، مثل اینا :

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

یا این:

        /** The day of the month. */
        private int dayOfMonth;

و حتی این:

/**
        * Returns the day of the month.
        *
        * @return the day of the month.
        */
        public int getDayOfMonth() {
                return dayOfMonth;
        }

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

وقتی میتونین از یک فانکشن یا متغییر استفاده کنین از کامنت استفاده نکنین

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

// does the module from the global list <mod> depend on the
// subsystem we are part of?
if (smodule.getDependSubsystems().contains(subSysMod.getSubSystem()))

حالا این کد رو بدون این دو جلد تفسیر تصور کنین، بله یعنی این:

ArrayList moduleDependees = smodule.getDependSubsystems();
String ourSubSystem = subSysMod.getSubSystem();
if (moduleDependees.contains(ourSubSystem))

Position Markers

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

// Actions //////////////////////////////////

کامنت‌هایی که نشون دهنده‌ی بستن آکولاد هاست

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

یک نمونه از این کامنت‌ها :

public class wc {
        public static void main(String[] args) {
                BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
                String line;
                int lineCount = 0;
                int charCount = 0;
                int wordCount = 0;
                try {
                        while ((line = in.readLine()) != null) {
                                lineCount++;
                                charCount += line.length();
                                String words[] = line.split("\\W");
                                wordCount += words.length;
                        } //while
                        System.out.println("wordCount = " + wordCount);
                        System.out.println("lineCount = " + lineCount);
                        System.out.println("charCount = " + charCount);
                } // try
                catch (IOException e) {
                        System.err.println("Error:" + e.getMessage());
                } //catch
        } //main
}

Attributions and Bylines

/* Added by Fatemeh */

به این عزیزانی که میان بالای یه کد اسم خودشونو میزنن باید بگیم داداش زحمت نکش توروخدا گیت هست ما میفهمیم تو بودی که اینو نوشتی :))))))

کامنت‌کردن کد

یه موقع‌هاییم هست میاییم یه عالمه کدو کامنت میکنیم، که اکثرا هم موقع این کار به این فکر میکنیم که شاید بعدا نیاز بشه و خب اگه یه بنده خداییم بیاد پروژه رو ببینه میترسه به اینا دست بزنه که نکنه مشکلی پیش بیاد. نباید اینارو کامنت کنین تا یه گوشه واسه خودشون خاک بخورن؛ پاک کنین بره و بازم تاکید میکنم که در این موارد دوست خوبمون گیت یاری دهنده است.

Nonlocal Information

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

اطلاعات بیش از اندازه

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

مثال:

/*
        RFC 2045 - Multipurpose Internet Mail Extensions (MIME)
        Part One: Format of Internet Message Bodies
        section 6.8. Base64 Content-Transfer-Encoding
        The encoding process represents 24-bit groups of input bits as output
        strings of 4 encoded characters. Proceeding from left to right, a
        24-bit input group is formed by concatenating 3 8-bit input groups.
        These 24 bits are then treated as 4 concatenated 6-bit groups, each
        of which is translated into a single digit in the base64 alphabet.
        When encoding a bit stream via the base64 encoding, the bit stream
        must be presumed to be ordered with the most-significant-bit first.
        That is, the first bit in the stream will be the high-order bit in
        the first 8-bit byte, and the eighth bit will be the low-order bit in
        the first 8-bit byte, and so on.
*/

و در آخر …

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

چه امتیازی به این مقاله می دید؟
خیلی بد
بد
متوسط
خوب
عالی

دیدگاه‌ها و پرسش‌ها

برای ارسال دیدگاه لازم است، ابتدا وارد سایت شوید.

در حال دریافت نظرات از سرور، لطفا منتظر بمانید

در حال دریافت نظرات از سرور، لطفا منتظر بمانید

آفلاین
user-avatar
فاطمه شیرزادفر @Fatemeh.shirzadfar
تجربه کلمه‌ای هست که همه برای توصیف اشتباهاتشون ازش استفاده میکنن، و من همیشه دنبال اشتباهات جدیدم! برنامه‌نویس هستم و لینوکس‌ دوست
دنبال کردن

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

بخشی برای حل مشکلات برنامه‌نویسی و مباحث پیرامون آن وارد شو