Clean Code, Comments & The Clean The Ugly

التعليقات أو الـcomments في البرمجة هي شروحات أو تعليقات على الـ source code يمكن قراءتها بواسطة المبرمجين. يتم إضافتها بهدف جعل الكود أسهل لفهمه من قبل البشر، ويتم تجاهلها من قبل الـ  compilers و الـ  interpreters،
Clean Code, Comments & The Clean The Ugly

في هذه الصفحة

التعليقات أو الـcomments في البرمجة هي شروحات أو تعليقات على الـ source code يمكن قراءتها بواسطة المبرمجين. يتم إضافتها بهدف جعل الكود أسهل لفهمه من قبل البشر، ويتم تجاهلها من قبل الـ  compilers و الـ  interpreters، باختصار التعليقات هي ملاحظات يتركها المبرمجون في الكود لمساعدة المبرمجين الآخرين (وأنفسهم) في فهم ما يحدث في الكود.

ربما يتبادر في ذهنك -وهو من الأخطاء الشائعة ❌- هو أن كتابة تعليقات أكثر يساوي كود أفضل(أنظف).

لماذا أزعم أن كتابة التعليقات ليست دائمًا بالأمر الجيد مع أن الحدس يقول أن كتابة التعليقات من المفترض أنها تزيد من قابلية الكود للقراءة والفهم Readability 📖؟

في هذا المقال سوف نتعرف على كيفية استخدام التعليقات بشكل صحيح يُفيد ولا يضر، فهيا بنا نرى لماذا لا يجب أن تُكثر من استخدام التعليقات..

🤥التعليقات تكذب! 

“الاستخدام السليم للتعليقات هو لتعويض فشلنا في التعبير عن أنفسنا في الكود. لاحظ أنني استخدمت كلمة “فشل”. أقصد ذلك. التعليقات دائمًا ما تكون إخفاقًا. فنحن نستخدمها لأننا لا يمكننا دائمًا أن نفهم كيفية التعبير عن أنفسنا بدونها، ولكن استخدامها ليس سببًا للتباهي.” 

Robert C. Martin. 2008. Clean Code

من هذه المقولة نستنتج أننا نستخدم التعليقات لتقوم بشرح ما لم نتمكن من شرحه باستخدام الكود ولكن التعليقات كاذبة وهذا ليس دائمًا مقصودًا أو صحيح لكنه كثير!

فالكود في تغير مستمر ولكن التعليقات ليست كذلك، ففي الأغلب ستُغير الكود ولن تُغير التعليق أو تمسحه.

🔁لا تكرر نفسك 

(Don’t repeat yourself أو DRY)‏ أو مبدأ عدم التكرار في هندسة البرمجيات يهدف إلى الحد من تكرار المعلومات من جميع الأنواع.

للأسف، المعرفة ليست ثابتة. إنها تتغير، وغالبًا ما يكون التغير سريعًا. قد يتغير فهمك لمتطلب ما بعد اجتماع مع العميل أو تغيرت متطلبات الشركة وأصبح بعض من منطق العمل Business logic قديمًا. وقد تظهر الاختبارات أن الخوارزمية المختارة لن تعمل.

كل هذا التغيير يعني أننا سنقضي جزءًا كبيرًا من وقتنا في صيانة الكود وإعادة تنظيم وتحسين أنظمتنا. لذلك تمثيل المعرفة في أكثر من مكان في الكود هي مشكلة لأنك ربما تعدل في مكان وتنسي أخر، مبدأ الحاجة للتغيير في أكثر من مكان هو مشكلة بحد ذاتها لذلك مبدأ الـDRY مهم جدًا.

 

إحدى الانتهاكات لهذا المبدأ هو استخدام التعليقات، فعندما يكون التعليق يصف ما يقوم الكود بفعله فأنت هنا أمام قضية تكرار و انتهاك واضح لمبدأ الـDRY لذلك: 

  • تغيير الكود يتطلب تغيير التعليق كما وضحنا -وعادة ستنسى إزالة التعليق-.
  • عندما يكون التعليق يخالف الكود المكتوب يكون التعليق تعليقًا كاذبًا مٌضلًا، ولا تنسى مبدأ أن الحقيقة يمكن أن تُوجَد فقط في مكان واحد وهو الكود. فقط الكود يمكنه أن يخبرك بصدق بما يفعله. إنه المصدر الوحيد للمعلومات الدقيقة بالفعل. ثَمّ، مع أن التعليقات ضرورية في بعض الأحيان، فإننا سنبذل جهودًا كبيرة لتقليلها.

🤐التعليقات السيئة 

ربما تكون قد اقتنعت قليلًا بخطورة التعليقات، سنعطي أمثلة أكثر على التعليقات السيئة لتزداد يقينًا، اقرأ كل كود وحاول أن تفهم ما المشكلة قبل أن تقرأها..

1- التعليقات المكررة 

def is_bad_comment(self) -> bool:
	"""
	This function checks whether the given comment
	is bad or not.
	raises an exception if the comment is empty.
	"""
	# if the comment is empty raise an exception
	if self.is_empty():
		raise Exception('Empty Comment %s' % self)

	# if the comment is redundant return True
	if self.is_redudant():
		return True

return False # return False if passed all checks

المشكلة

هذا المثال تعليقات لا قيمة لها، هذا الكود لا يحتاج إلي هذه التعليقات كلها بل أن التعليقات تأخذ وقتًا وجُهدًا أكبر من قراءة كود نفسه!

الحل

ببساطة احذف التعليق.

2- الكود المحذوف

#def not_used_function() -> None:
#	"""
#	Deleted function not used any more
#	but may be used in the future wo knows?
#	"""
#	return None

المشكلة

هذا الكود غير مستخدم، هو فقط مصدر للتشتيت

الحل

حذف التعليق وفي حالة الحاجة إليه يمكن استخدام ضبط النسخ vcs مثل git.

3- استخدام التعليق لإيضاح كود معقد

# Function to calculate the sum of squares of even numbers in a list
def sum_of_squares_even_numbers(numbers):

    sum = 0
    for number in numbers:
        if number % 2 == 0: # checks if the number is even
            sum += number ** 2 # square the number
    return sum

المشكلة

لديك كود مع الكثير من التعليقات. التعليقات مقترنة بالتنفيذ (coupled) وصعبة التحديث.

الحل

استخدام الدوال functions لجعل الكود أفضل وأكثر قابلية للقراءة هكذا:

def is_even(number):
    return number % 2 == 0

def square(number):
    return number ** 2

def sum_of_squares_even_numbers(numbers):
    sum = 0
    for number in numbers:
        if is_even(number):
            sum += square(number)
    return sum

4- التعليقات المهمشة

هي تعليقات يتم تجاهلها أو نسيانها أو أنها لم تعد صحيحة 

def get_price_after_discount(price: int) -> int:
# TODO: check if the price is greater than 1000, then the discount is only 200
return price * 0.9

المشكلة

لديك تعليقات لم تعد صحيحة.

الحل

استخدام الاختبارات Tests عوضًا عن ذلك فالاختبار سيفشل وسيكون بمثابة إنذار لتذكرة الفريق لحل هذا التعليق حتي، لا ينسي هكذا:

def get_price_after_discount(price: int) -> int:
    return price * 0.9

# Test case for get_price_after_discount function
@pytest.mark.xfail(reason="Implementation for discount logic is not yet completed")
def test_get_price_after_discount():
    # Test case 1: Asserting the price after discount for a price less than or equal to 1000
    result = get_price_after_discount(800)
    assert result == 800 * 0.9  # Expected price after discount should be 90% of the original price

    # Test case 2: Asserting the price after discount for a price greater than 1000
    result = get_price_after_discount(1500)
    assert result == 1500 - 200  # Expected price after discount should be the original price minus 200

    # Test case 3: Asserting the price after discount for a price equal to 1000
    result = get_price_after_discount(1000)
    assert result == 1000 * 0.9  # Expected price after discount should be 90% of the original price

test_get_price_after_discount()

😇التعليقات الجيدة

بعد جرعة من التعليقات السيئة هيا نري أمثلة يكون استخدام التعليقات بها فعلاً مفيدًا:

1- التعليق الشارح 

يمكن كتابة تعليق لتوضيح بعض القرارات المهمة أو غير الحدسية كهذا المثال:

def comment_explaining_code():
	 value = XMLTokener(xml_string).next_value();
     # Note that XMLTokener.next_value() may return a None value.
		if value is None:
	    return None
		# rest of code

def comment_explaining_decision():
	# The entire locale directory is  backed up (using `mv` rather than `shutils`,
	# or else the owner & permissions are reset to docker's).

2- من أين لك هذا؟

توفير المصدر الأصلي للكود الذي أخذت، فهذا سيكون مصدر جيد لو أراد أن يفهم سياق هذا الحل.

# https://stackoverflow.com/a/23796376/9260982
class RevokeChainRequested(Exception):
    def __init__(self, message, return_value=None):
        Exception.__init__(self, "Revoke chain requested")

        self.message = message
        self.return_value = return_value

في الختام

 يجب أن نتعامل مع التعليقات بحذر ونسعى لتحسين الكود نفسه ليكون واضح ومفهوم دون الحاجة إلى الاعتماد الكبير على التعليقات.

 

المصادر

اشترك الآن بنشرة اقرأ-تِك الأسبوعية

لا تدع أي شيء يفوتك. واحصل على أحدث المقالات المميزة مباشرة إلى بريدك الإلكتروني وبشكل مجاني!