اذهب إلى المحتوى

أسلوب كتابة الشيفرات البرمجية وتحقيق سهولة قراءتها


أسامة دمراني

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

التعليقات

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

سجل الإصدارات

يجب على المبرمج أن يسهّل على من يقرأ برامجه معرفة التفاصيل الأساسية لكل ملف، مثل تاريخ إنشائه واسم مؤلفه وبيانات آخر تعديل فيه وإصداره ووصف عام لمحتوياته، وبقية المعلومات التي تدخل في سجل تغييراته، وهذه الكتلة النصية تُكتب في تعليق، بالشكل التالي:

#############################
# Module:   Spam.py
# Author:   A.J.Gauld
# Version:  Draft 0.4
'''
This module provides a Spam class which can be
combined with any other type of Food object to create
interesting meal combinations.
'''
###############################
# Log:
# 2015/09/01    AJG - File created
# 2015/09/02    AJG - Fixed bug in pricing strategy
# 2015/09/02    AJG - Did it right this time!
# 2016/01/03    AJG - Added broiling method(cf Change Req #1234)
################################
import sys, string, food
...

نرى في هذا المثال ملخصًا بسيطًا لما يحتويه الملف بمجرد فتحه، فنعرف ما الذي تغير فيه من ما قبله، ومن الذي نفذ هذه التغييرات ووقت إجرائها، وتبرز أهمية هذه المعلومات عند العمل على المشروع ضمن فريق، وذلك حين نحتاج إلى معرفة المسؤول عن التغيير الذي بين أيدينا أو تصميم البرنامج الذي تعمل عليه، وقد وضعنا الوصف بين زوج من علامات الاقتباس الثلاثية، وهذا أسلوب تتبعه بايثون يسمى سلسلة التوثيق، ويُستخدم لإضافة هذا التوثيق والوصف إلى الدالة help()‎ المضمَّنة فيها، كما سنرى بعد قليل.

من المهم ملاحظة وجود أدوات تعمل مثل مستودعات للشيفرات البرمجية، مثل Git وSubversion وCVS وRCS، إذ تستطيع الاحتفاظ بمعلومات تلقائيًا، مثل اسم المؤلف واسم الملف وتفاصيل سجل الإصدار وننصح بالنظر في خصائص التوثيق في تلك المستودعات وتعلمها، لأنها توفر الكثير من الوقت الضائع في التسجيل اليدوي لهذه التعليقات.

تعطيل الشيفرات الفاسدة

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

data = readData(datafile)
for item in data:
    results.append(calculateResult(item))
printResults(results)
######################
# تُعزل الشيفرة أدناه إلى حين إصلاح 
# calculateResult الزلة التي في 
# for item in results:
#     dataFile.save(item)
######################
print 'Program terminated'

ثم نحذف علامات التعليق إذا أصلحنا ذلك الخلل، لجعل الشيفرة نشطةً مرةً أخرى.

تحتوي العديد من المحررات البرمجية مثل IDLE، خاصيةً نستطيع فيها اختيار جزء من الشيفرة وتحويله إلى تعليق تلقائيًا، ثم إلغاء ذلك التحديد عند الحاجة، وسنجد هذه الخاصية في IDLE في القائمة Format ثم الخيار Comment Out Region.

سلاسل التوثيق

تسمح جميع اللغات البرمجية بإنشاء تعليقات لتسجيل ما تفعله الدالة أو الوحدة التي نكتبها، لكن قليلًا منها يزيد على ذلك بأن يسمح لنا بتوثيق الدالة بطريقة تستطيع اللغة أو البيئة نفسها أن تستفيد منها لتوفر لنا مساعدةً تفاعليةً أثناء البرمجة، ومن تلك اللغات: جافا وبايثون وSmalltalk، نستخدم هذه الخاصية في بايثون من خلال علامات الاقتباس الثلاثية التي على نمط """documentation""":

class Spam:
    """A meat for combining with other foods

    It can be used with other foods to make interesting meals.
    It comes with lots of nutrients and can be cooked using many
    different techniques"""

    def __init__(self):
       pass   # ie. it does nothing!

help(Spam)

لاحظ أننا نستطيع الوصول إلى سلسلة التوثيق باستخدام الدالة help()‎، وأن سلاسل التوثيق تصلح للوحدات والدوال والأصناف والتوابع، لننظر إلى الشيفرة التالية:

>>> import sys
>>> help (sys.exit)
Help on built-in function exit:

exit(...)
    exit([status])

    Exit the interpreter by raising SystemExit(status).
    If the status is omitted or None, it defaults to zero (i.e., success).
    If the status is numeric, it will be used as the system exit status.
    If it is another kind of object, it will be printed and the system
    exit status will be one (i.e., failure).
(END)

إذا أردنا الخروج من وضع المساعدة الذي في المثال السابق عند رؤية END؛ التي تشير إلى نهاية التوثيق، فسنضغط على مفتاح Q في لوحة المفاتيح، وهو اختصار كلمة Quit؛ أما إذا كان التوثيق أكثر من صفحة، فسنضغط على مفتاح المسافة لتصفحه، ومن الجدير بالذكر أن كلمة END التي في نهاية التوثيق قد لا تظهر في بعض الطرفيات.

توجد دالة مساعِدة أخرى هي dir()‎، والتي تعرض جميع المزايا التي تعرفها بايثون عن كائن ما، فإذا أردنا معرفة الدوال أو المتغيرات الموجودة في وحدة sys مثلًا، فسنكتب ما يلي:

>>> import sys
>>> dir(sys)
[..... 'argv', 'builtin_module_names', 'byteorder', .... 'copyright', 
.... 'exit', ..... 'stderr', 'stdin', 'stdout', 'subversion', 
'version', 'version_info', 'warnoptions', 'winver']

بعد ذلك سنختار ما نريد منها، ونستخدم دالة help()‎ للحصول على مزيد من المعلومات، وقد أهملنا العديد من المدخلات في المثال أعلاه لتوفير المساحة، كما نستفيد من وظيفة الدالة dir()‎ عند استخدام وحدة ليس لها توثيق جيد أو كافٍ، فقد نتعامل مع وحدات ليس لها توثيق خارجي أصلًا.

إزاحة الكتل

ذكرنا عدة مرات أن إزاحة الأسطر مهمة في بايثون، وتتوقف عليها الإجراءات التالية للأسطر المزاحة، مع أن أكثر لغات البرمجة لا تهتم بإزاحة الأسطر، لذا يزيح المبرمجون الأسطر في برامجهم وشيفراتهم لتسهيل قراءتها وتمييز أجزائها لا أكثر، فقد صار لكل مبرمج تقريبًا أسلوبه الخاص في الإزاحة وفق ما يراه مناسبًا، وقد ولّدت كثرة الأهواء والآراء في هذا الشأن جدالات حامية الوطيس في البرمجة منذ زمن، بلغت حد إجراء بدراسات للوقوف على الجوانب التي تؤثر فيها إزاحة الأسطر سوى المظهر الجمالي، كأن تساعد في فهم الشيفرة البرمجية بطريقة أسرع وأسهل، لننظر في المثال التالي من VBScript مثلًا:

< script type="text/vbscript">
For I = 1 TO 10
    MsgBox I
Next
</script>

ثم لننظر إلى النسخة التالية منه، والتي لا تحوي إزاحات للأسطر:

< script type="text/vbscript">
For I = 1 TO 10
MsgBox I
Next
</script>

يكاد المثالان يتطابقان في نظرنا نحن البشر، والفرق بينهما هو أن النسخة الأولى أسهل في القراءة في نظرنا، أما في نظر مفسر VBScript فهما متطابقتان تمامًا ولا فرق بينهما، والشرط الحاكم للإزاحة هنا هو أن تعكس الهيكل المنطقي للشيفرة، فتتبع تدفق البرنامج في هيئتها المرئية، وقد أظهرت الدراسات التي أجريت على الشيفرات المزاحة أن الشيفرات المقسَّمة بصريًا إلى كتل تعكس البنية الكتلية المنطقية للبرنامج؛ أسهل في الفهم، وعلى ذلك تكون البنية التالية:

XXXXXXXXXXXXXXXXXXXX
    XXXXXXXXXXXXXXXX
    XXXXXXXXXXXXXXXX
    XXXXXXXXXXXXXXXX

أسهل في فهم مرادها ووظيفتها من هذه البنية:

XXXXXXXXXXXXXXXXXXXXX
  XXXXX
    XXXXXXXXXXXX
    XXXXXXXXXXXX
    XXXXXXXXXXXX
  XXXXX

قد لا تظهر أهمية الإزاحة في الأمثلة البسيطة التي أوردناها إلى الآن، لكن الفرق يتضح عند التعامل مع برامج تحتوي على مئات الآلاف من الأسطر البرمجية.

يتبقى الآن أن ننظر في مقدار تلك الإزاحة، وهو أمر طال الخلاف حوله في مجال البرمجة، ويكمن الاختلاف بين استخدام المسافات spacebar للإزاحة أو استخدام زر الجدول tab. ومع أن استخدام زر الجدول أسهل لأنه يؤدي الغرض بنقرة واحدة؛ غير أن هذه النقرة الواحدة تساوي 8 مسافات، وهي إزاحة كبيرة، كما يصعب تحديد آلية الإزاحة الموجودة في شيفرة ما، فهل نتجت عن استخدام زر المسافة أم زر الجدول، لأننا لا نستطيع استخدامهما معًا، فإما هذا أو ذاك، وتظهر هذه المشكلة لمن يتعامل مع برنامج كتبه مبرمج غيره، ولتجنب هذه المعضلة من بداية تعلمنا للبرمجة، يُفضّل تجنب استخدام زر الجدول في الإزاحة، لأن بعض الدراسات أظهرت أن أفضل صورة للشيفرة -من حيث سهولة القراءة- تتحقق إذا كانت الإزاحة محصورةً بين مسافتين وخمس مسافات؛ أما مستخدمو بايثون فقد اصطلحوا على استخدام أربع مسافات في الإزاحة، على الرغم من صلاحية الأمثلة التي استخدمناها إلى الآن، والتي كانت إزاحاتها أقل من ذلك، لأنها توفر بعض المساحة على الشاشة.

أسماء المتغيرات

لم نستخدم أسماءً لها معانٍ للمتغيرات في الأمثلة التي أوردناها في ما سبق، لأننا لم نقصد إلا شرح بعض التقنيات البرمجية، لكن يُفضل أن تعكس أسماء المتغيرات ما تمثله في الشيفرة، من حيث الوظيفة التي تنفذها، فقد استخدمنا المتغير multiplier في تدريب جدول الضرب مثلًا؛ والذي سبق أن عرضناه مثل متغير يوضح الجدول الذي نريد طباعته. علمًا أن هذه التسمية أفضل من اختيار اسم عشوائي أو رمزي مثل m الذي لن يسبب مشاكل في تنفيذ الشيفرة، بل سيريحنا في الكتابة بما أنه حرف واحد، لكنه بلا معنىً، وسيتسبب في مشاكل مستقبلية إذا أردنا معرفة وظيفة هذا المتغير، أو أراد مبرمج آخر ذلك.

يُفضل في تسمية المتغيرات أن تكون مفهومةً على أن تكون سهلة الكتابة، وأفضل حل لأسماء المتغيرات هو أن تكون قصيرةً وذات معنىً في نفس الوقت، فالأسماء الطويلة مربكة وصعبة الكتابة، فمثلًا: نستطيع استخدام the_table_we_are_printing عوضًا عن multiplier، غير أن هذا الاسم طويل ويتجاوز المعقول في الكتابة البرمجية.

حفظ البرامج

ذكرنا سابقًا أننا نخسر كل شيء كتبناه في محث بايثون ‎>>>‎ بمجرد الخروج منه، فهو وإن كان ممتازًا في تجربة الأفكار بسرعة؛ إلا أنه غير مفيد على المدى البعيد، إذ نريد أن نكتب البرامج ونشغلها مرةً بعد مرة وقتما نشاء، فهذا هو المنطق، ولفعل ذلك في بايثون؛ ننشئ ملفًا نصيًا للبرنامج ونجعله بالامتداد ‎.py، وهو اصطلاح متبع، رغم أننا نستطيع استخدام أي امتداد نريده هنا، لكن يُفضل اتباع هذا الاصطلاح، ثم نستطيع تشغيل البرنامج من محث سطر أوامر النظام بكتابة ما يلي:

C:\WINDOWS> python spam.py

فيكون اسم برنامج بايثون هنا هو spam.py، ومحث نظام التشغيل هو C:\WINDOWS>‎.

إحدى مزايا استخدام هذه الطريقة في برامج بايثون أننا نستطيع تشغيل البرنامج بمجرد النقر عليه في مدير الملفات، مثل أي ملف تنفيذي يمثل برنامجًا بما أن ويندوز يربط امتداد ‎.py بمفسر بايثون، كما أن استخدام الملفات لتخزين البرامج يسمح بتصحيح أخطائها دون الحاجة إلى إعادة كتابة الجزء الخاطئ من البرنامج مرةً أخرى في محث بايثون، أو التحرك بالمؤشر في IDLE حتى نتجاوز الخطأ كي نعيد تحديد الشيفرة، لأن IDLE تدعم فتح الملف لتعديله وتشغيله من القائمة Run، ثم خيار Run module، أو باستخدام مفتاح F5 على لوحة المفاتيح.

لن نعرض محث بايثون ‎>>>‎ مرةً أخرى في الأمثلة البرمجية التي نشرحها، إذ سنفترض أنك تنشئ البرامج في ملف منفصل وتشغلها إما داخل IDLE أو من محث سطر الأوامر.

ملاحظة لمستخدمي ويندوز

يمكن إعداد ربط الملفات التي تنتهي بامتداد ‎.py داخل مدير الملفات، مما يسمح بتشغيل برامج بايثون بالنقر المزدوج على أيقونة الملف، والمفترض أن مثبت بايثون قد نفذ هذا الإجراء بالفعل، وللتحقق من ذلك؛ ابحث عن ملف بامتداد بايثون وجرب تشغيله، فإذا نجحت يكون الربط جاهزًا على حاسوبك، حتى لو أخرج لك رسالة خطأ.

المشكلة التي قد تواجهها هنا هي أن الملفات التي أيقونتها شعار بايثون نفسه؛ إذ ستشَغل في صندوق DOS ثم تغلَق بسرعة بحيث لا تكاد تراها، ويمكن حل هذا بكتابة السطر التالي في نهاية البرنامج:

input("Hit ENTER to quit")

سيعرض هذا السطر رسالةً تخبرك أن تضغط زر ENTER للخروج، وينتظر حتى يحدث ذلك؛ أما في إصدارات بايثون الأخيرة فهناك أداة إضافية في ويندوز ستساعدك على تشغيل بايثون دون مشاكل، وهي py.exe، فإذا كتبنا:

 C:\WINDOWS> py spam.py

فستبحث هذه الأداة عن بايثون، وتشغل الشيفرة تشغيلًا صحيحًا، كما تستفيد من أي سطر كامل المسار shebang line داخل الملف لتعرف أي إصدار تستخدمه من بايثون -إذا وُجد أكثر من إصدار مثبت على حاسوبك-.

ملاحظة لمستخدمي يونكس

يجب أن يحتوي أول سطر في ملف سكربت بايثون على التسلسل ‎#!‎ متبوعًا بالمسار الكامل لبايثون على حاسوبك، ويُعرف سطر المسار الكامل هذا أحيانًا باسم شيبانك shebang باللغة الإنجليزية، وهو السطر الذي يجعل شيفرة بايثون قابلةً للتنفيذ عبر مفسر بايثون المحدد بالمسار، والذي نعثر عليه بكتابة السطر التالي في محث الصدفة shell prompt:

$ which python

وقد يبدو ذلك المسار كما يلي:

#!/usr/local/bin/python

مما يسمح لنا بتشغيل الملف دون استدعاء بايثون، بعد إعدادها لتكون قابلةً للتشغيل من خلال chmod كما تعلم:

$ spam.py

يمكن استخدام ‎/usr/bin/env python بدل معلومات المسار، مثل أسلوب أفضل يمكن تنفيذه على أغلب أنظمة يونكس، بما فيها جميع توزيعات لينكس:

#!/usr/bin/env python

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

أما سطر ‎#!‎ فلا يسبب مشاكل في نظامي ويندوز أو ماك لأنه سيبدو تعليقًا، لذا لا بأس بكتابته عند استخدام هذين النظامين، وذلك تحسبًا لاحتمال تشغيل الشيفرة على حاسوب يونكس يومًا ما، أو استخدام مطلِق py.exe الذي لا يتجاهل سطر المسار الكامل shebang.

جافاسكربت وVBScript

لا يحتاج من يبرمج مستخدمًا جافاسكربت وVBScript إلى الملاحظات التي ذكرناها أعلاه، لأن هذه البرامج تُحفظ في ملفات.

خاتمة

تعلمنا في هذا المقال ما يلي:

  • استخدام التعليقات لعزل جزء من الشيفرة مؤقتًا عند الاختبارات أو تنقيح الشيفرة debugging، وكذلك استخدامها لتوفير ترويسة توضيحية يُذكر فيها سجل إصدارات الملف.
  • كيفية استخدام سلاسل التوثيق في توفير معلومات فورية runtime-information عن وحدة ما، والكائنات التي داخلها.
  • فائدة إزاحة كتل الشيفرات في توضيح الترتيب المنطقي لهيكل الشيفرة البرمجية، وتسهيل تتبع عين القارئ لذلك التسلسل المنطقي.
  • حفظ برامج بايثون في ملفات لإعادة تشغيلها في أي وقت، بدلًا من كتابتها في محث بايثون ‎>>>‎ ثم ضياعها عند الخروج منه، وذلك بكتابة ‎$ python progname.py في سطر الأوامر، أو بتشغيل الملف في مدير الملفات بالنقر عليه.

ترجمة -بتصرف- للفصل الثامن: Coding Style من كتاب Learning To Program لصاحبه Alan Gauld.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...