15 Sep 2005
رحلتي في مجال البرمجة بدأت قبل تسع سنوات، عندما كنت في الرابعة عشرة من عمري، وشملت كلا من Visual Basic وC وC++ وJava وPerl وPHP وJavaScript وPython، وأنا لا أتحدث هنا عن مرور الكرام، بل قمت بالعديد من المشاريع في كل منها ولا زالت قدراتي بكل هذه اللغات جيدة، وأستطيع استخدام أي منها إذا اقتضت الحاجة ذلك، لكن إذا كان الخيار متاحا لي في كل مرة، لاخترت Python لكل مشروع أعمل عليه.
والسبب؟ سهولة قراءة شفرات البرامج المكتوبة بها!
سهولة قراءة الشفرات؟
قد يبدو الأمر خروجا عن المألوف في البداية، أن تكون سهولة قراءة شفرات البرنامج هي أهم ميزة في لغة البرمجة المستخدمة لكتابته، فغالبية النقاشات حول لغات البرمجة كانت تتمحور عادة حول سرعة التنفيذ أو كثرة المكتبات البرمجية المتوفرة لها، أما المقارنة بين اللغات بناءا على شكل أوامرها أو بساطة جملها البرمجية فطالما بدا لي أمرا سطحيا، وكنت أعتقد بأنك بمجرد أن تتعلم كيفية كتابة الجمل بصورة صحيحة والتعود على اللغة فإن ذلك لم يحدث فرقا كبيرا.
لكن الحقيقة هي أن استخدامي للغة Python جعلني أغير وجهة نظري هذه.
السبب في ذلك يبدو بسيطا وبديهيا بالنسبة لي الآن، وهو أن الغالبية العظمى من الوقت الذي أقضيه في إنشاء برنامج ما يكون في قراءة شفرات هذا البرنامج وإعادة قرائتها مرة تلو الأخرى، والغالبية العظمى من التعديلات التي أحتاج للقيام بها على برنامج ما تعتمد على فهمي للشفرة الحالية للبرنامج التي أعتزم تعديلها، ولذلك فإنه كلما كان الوقت والجهد اللذان أحتاج اليها لقراءة شفرات البرنامج وفهمها أقصر، كانت عملية البرمجة أسرع، وكلما كان فهمي للشفرة الحالية أدق، أصبحت عملية تطوير البرنامج باستمرار أسهل.
هذه المزايا في Python مهمة في عصر البرمجة الحالي.
في السابق، كانت الشركات تصرف الكثير من الوقت والجهد في هندسة المنتج ككتلة واحدة ضخمة وتحديد الكيفية التي سيتم فيها تطبيق كل جزء منه وكيفية تفاعل هذه الأجزاء مع بعضها البعض، قبل أن يكون هنالك حتى سطر برمجي واحد من البرنامج، أي أنّ البرنامج يكون في غالبية عمره مجرد حبر على ورق، وتكون المصيبة عندما تأتي أخيرا للتطبيق لتكتشف بأن فكرة البرنامج الأصلية كانت فاشلة.
مشاريع البرمجة هذه الأيام تسير باتجاه أساليب انتاج برامج عاملة بأسرع وقت ممكن وبالحد الأدنى المطلوب من المزايا، وبعد ذلك تتم اضافة المزايا واحدة تلو الأخرى بناءا على الحاجات الفعلية والمباشرة لمستخدمي البرنامج، لا بناءا على تخمينات وضعت قبل سنوات من الاطلاق الفعلي للبرنامج، وهذا الأسلوب في البرمجة يتطلب أن تكون عملية تعديل البرامج الحالية سريعة جدا، لذا فإنك بحاجة لأن تنظر إلى شفرة البرنامج التي كتبتها قبل بضعة أشهر فتستطيع أن تحدد بسرعة وبدقة ما الذي تقوم به هذه الشفرة، لتتمكن بالتالي من تحديد التغييرات التي يجب القيام بها لإضافة الميزة التي تريدها إلى البرنامج.
إضافة إلى ذلك، فهنالك بالطبع الحاجة لفهم البرامج التي كتبها الآخرون، خاصة مع توفر شبكة الانترنت وكمية هائلة من الشفرات التي يمكن استخدامها كقوالب تعدل عليها لتحصل على المنتج الذي تريده، هذه الشفرات إذا لم تكن سهلة القراءة والفهم فإنها لن تفيد في شيء، وقد يستغرق فهمك لها وقتا أطول بكثير من كتابة البرنامج بنفسك دون الاعتماد على شيء جاهز وموجود على الشبكة.
اللغات الأخرى مثل C تحاول حل مشكلة صعوبة قراءة شفراتها بوضع التعليقات على الشفرات، وقد تبدو هذه الفكرة جيدة نظريا، لكن ما يحدث عمليا هو أن هذه اللغات صعبة القراءة لدرجة أن كل سطر منها يحتاج إلى سطر من التعليقات لشرح معناه، وعندما تقوم بذلك، أي تقوم بوضع تعليق فوق كل سطر من أسطر البرمجة، فإن ما ينتج عن ذلك هو أن تكون لديك نسختان من برنامج، واحدة مكتوبة بلغة البرنامج المعقدة التي لا يفهمها حتى كاتبها والأخرى مكتوبة بلغة بشرية، وكل تعديل تقوم به على واحدة من هاتين النسختين يجب أن تقوم به فورا على الأخرى، وإلا فإن التعليقات ستتحول من نعمة إلى نقمة.
إن اجراء اي تعديل على برنامج مثل هذا سيكون بمثابة كابوس، لدرجة أن من الأمور العادية جدا بالنسبة لمبرمجي C أن يحذفوا كل الشفرات التي كتبوها لمشروع ما سابقا ويعيدوا برمجة كل شيء من الصفر، لأن ذلك يكون في الكثير من الأحيان أسهل بكثير من محاولة تعديل الشفرة الحالية.
إذا كانت لديك سنوات من الخبرة في مجال البرمجة بهذه اللغات، فإنك قد تظن بأن البدء من الصفر في البرمجة أمر اعتيادي وليست مشكلة كبيرة، بل ربما تكون لديك قناعة بأنه أمر صحي ومفيد وضروري لشفرة برنامجك، لكنه في الحقيقة مضيعة للوقت، كما أن الشفرة البرمجية الغير مجربة معرضة بصورة أكبر للأخطاء البرمجية، على العكس من الشفرة التي تكون موجودة لديك منذ فترة وتكون التجربة وكثرة الاستخدام قد صقلتها وخلصتها من كل الأخطاء البرمجية والمنطقية.
لكن هل يعقل أن يكمن الحل لكل المشاكل السابقة في لغة البرمجة؟ الإجابة التي أقدمها لك من واقع خبرتي هي: نعم! لغة البرمجة هي الحل، وسهولة القراءة هي السبب.
ما الذي يجعل Python سهلة القراءة؟
هنالك مجموعة من المزايا المهمة في لغة Python التي تجعلها سهلة القراءة، ومن المفيد لك أن تعرف هذه الأمور حتى تستطيع الاستمرار في تطبيقها على البرامج التي تكتبها أنت في Python.
سهولة القراءة جزء من الثقافة التي حول Python. وأقصد بالثقافة التي حول Python كل شيء من مطوري اللغة الأصليين إلى كتاب التعليمات والمتطوعين للإجابة عن أسئلة المبتدئين إلى المبرمجين الذين يستخدمون اللغة، كلهم مهتمون بأن تكون Python سهلة القراءة، لذا فإن أي تعديل على اللغة يدرس ويناقش لدرجة كبيرة من قبل كل من هو مهتم قبل أن تتم الموافقة على اضافته إلى اللغة، بعد التأكد من أنه لن يؤدي إلى برامج غير مفهومة الشفرة، وهذا الأمر مهم جدا، لأنه لا فائدة من إنشاء لغة جميلة وتقبيحها بعد ذلك بالتدريج بإضافة المزايا لها بصورة عشوائية ومن كل مكان، كما حدث مع لغات مثل Perl وPHP.
بساطة ونقاوة بنية اللغة. إذا كنت تبرمج باللغات التي تشبه C فأنت تعلم بالتأكيد بأن الجمل البرمجية تنتهي بالفاصلة المنقوطة (;) وأن المقاطع البرمجية تكون محصورة بين الأقواس المجعدة { و }، أما في Python، فالجمل البرمجية تنتهي بنهاية السطر، أي كل جملة توضع في سطر، أما المقاطع البرمجية فلا تحاط بأقواس أو شيء مميز، وانما هي عبارة عن مجموعة من الأسطر (الجمل البرمجية) التي تتساوى في حاشيتها عن بداية السطر، وحتى تفهم ما أعنيه، قارن بين المقطعين التاليين من الشفرة، الأول بلغة C والثاني بلغة Python:
لاحظ الفرق في مقدار الرموز الغريبة التي تحتاجها في C ولا تحتاجها في Python، هذا الأمر يجعل برامج Python أسهل بكثير في القراءة، خاصة وأنها تشجع المبرمج على كتابة الشفرة بصورة واضحة وجميلة، على العكس من لغة C التي لا تهتم لذلك، فيمكن مثلا كتابة السطر السابق من C كالتالي:
بينما يعد القيام بشيء مشابه في Python صعبا جدا، بل ربما يكون مستحيلا، وهذا الأمر يفيد كثيرا في تسهيل قراءة البرامج.
"يجب أن تكون هنالك طريقة واحدة واضحة، ويفضل أن تكون واحدة فقط، للقيام بأمر ما". هذه العبارة مهمة وتذكر كثيرا في ثقافة Python، والمقصود بها هو أنك إذا واجهت مشكلة ما وأردت حلها بلغة Python فيجب أن تكون هنالك طريقة واضحة وضوح الشمس لحل هذه المشكلة، وأن تكون الطريق معبدة أمامك لحل هذه المشكلة بهذه الطريقة فقط، وما ينتج عن ذلك هو أنه لو كان هنالك أكثر من مبرمج يريدون حل المشكلة نفسها، فإنهم سيكتبون شفرات شبه متطابقة، أي أن المبرمجين كلهم سيفكرون بالطريقة نفسها، وبالتالي سيكون من السهل عليهم أن يفهموا شفرات بعضهم البعض.
هذه الميزة تذكر عادة في مقارنة Python باللغات الأخرى التي توفر عشرات الحلول للمشكلة نفسها، مثل Perl التي تفتخر بذلك، وعندما تكون اللغة ضخمة وتحتوي على الكثير من الأوامر والطرق المختلفة للقيام بالشيء نفسه، فإن كل مبرمج من مبرمجي اللغة سيتعلم جزءا من أوامر وقدرات اللغة ليحقق به ما يريده, وعندما تأتي بعد ذلك لأكثر من مبرمج وتطلب منهم أن يكتبوا نفس البرنامج بهذه اللغة فإن البرامج ستبدو مختلفة إلى درجة أنها قد تبدو أحيانا كما أو أنها كتبت بلغات مختلفة، وهذا يعني بأنك في كل مرة تريد أن تقرأ بها شفرة لمبرمج آخر ستحتاج لعمل تعديلات كبيرة على طريقة كتابتك للبرامج، وعندما تعمل على مشروع كبير فإنك قد تتأثر به لدرجة كبيرة، بحيث أنك عندما تعود إلى البرامج التي كتبتها أنت قبل فترة من الزمن، ستجدها غريبة عليك وغير مألوفة!
الأمور السحرية ممنوعة. لعل أفضل مثال على اللغات التي تستخدم الأمور السحرية مرة أخرى هي Perl، ولعل أفضل مثال في Perl على الأمور السحرية هي المتغيرة $_، فهذه المتغيرة تعتبر سحرية لأنها المتغيرة الافتراضية للكثير من العمليات، فهي المتغيرة التي تذهب إليها معلومات الملف إذا قمت بجلبها دون أن تحدد المتغيرة التي تريد أن تضع هذه المعلومات فيها، وهي المتغيرة التي تستخدم بصورة افتراضية عند تطبيق عمليات التعابير القياسية (Regular Expressions) دون تحديد متغيرة معينة، وهي المتغيرة الافتراضية عند طباعة المعلومات دون تحديد متغيرة ما، وهذا الأمر يجعل بالامكان كتابة برنامج يقوم مثلا بفتح ملف ما واستخلاص معلومات منه ثم طباعة هذه المعلومات دون استخدام أية متغيرات، أو بالأصح، باستخدام متغيرة سحرية دون الحاجة لتحديدها في البرنامج.
بشكل عام، الذي أعنيه عندما أقول بأن الأمور السحرية ممنوعة، هو أن Python تفضل الافصاح عن المقصود عند كتابة الشفرة (explicit) على الأمور التي تكون مفهومة ضمنيا أو من السياق (implicit)، وهذا الأمر يجعل فهم المقصود من الشفرة بقرائتها أسرع بكثير.
عدم وراثة الأمور الخاطئة من اللغات الأخرى. الكثير من مصممي لغات البرمجة الحديثة نقلوا إلى لغاتهم الكثير من الأمور من اللغات القديمة كطريقة لتسويق اللغة للمبرمجين على أنها مشابهة للقديمة، وحتى تبدو عملية الانتقال إلى اللغة الجديدة سهلة نسبيا، وتنتج بسبب ذلك لغة غير متناسقة ترث الكثير من الأمور التي كان من الممكن حلها وتصحيحها بعد مرورها بالتجربة في اللغة القديمة، ولعل من أفضل أمثلة ذلك هو دوال PHP التي ورثتها بنفس الاسم ونفس المعطيات من مكتبات C المختلفة، أما Python فهي لا تهتم بالتوافق مع اللغات الأخرى، فإذا كانت هنالك أفكار جيدة في الخارج فإن Python تتبناها بعد أن تصبح متوافقة مع بقية أجزاء Python، أما إذا كانت سيئة فمجرد تعود الآخرين على استخدامها لا يعد مبررا كافيا لدى Python لادخالها على اللغة.
من أمثلة ذلك حلقات for وwhile وdo..while في C التي تقوم بالأمر نفسه تقريبا مع اختلافات بسيطة في كيفية ترتيب الشروط وغيرها، أما في Python فستجد بأن هذه الأنواع الثلاثة من الحلقات اختزلت في الحلقة while (هنالك طريقة واضحة واحدة للقيام بأمر ما)، وهنالك أيضا نوع آخر من الحلقات في Python يختلف اختلافا كليا عن أنواع الحلقات الثلاثة في C، واسم هذه الحلقة في Python هو for، لكن لا يوجد أي تشابه بينها وبين حلقة for التي في C.
عدم وراثة الأمور الخاطئة من الاصدارات السابقة. فلغة Python جريئة في التخلي عن أي ميزة يتضح بأنها تؤدي إلى مشاكل أو عندما يتم ايجاد طريقة أفضل لتحقيق الشيء نفسه، ففي نفس الوقت الذي تسير به اللغة بإضافة المزايا ببطئ فإنها تعمل أيضا على ازالة المزايا القديمة ببطئ، ويمكن القول بحق بأن Python لغة تتطور وتتكيف على العكس من اللغات الأخرى التي تتراكم فيها المزايا واحدة فوق الأخرى حتى تخرج عن السيطرة.
وهذا الأمر يعني يضمن استمرارية الميزة التي ذكرتها سابقا، وهي أن هنالك طريقة واحدة واضحة للقيام بأمر ما، لأن مطوري Python حتى إذا توصلوا إلى طريقة أفضل للقيام بأمر ما، فإنهم لن يكتفوا بإضافة الطريقة الأفضل، بل سيعملون أيضا على إزالة الطرق السابقة حتى تصبح الطريقة الجديدة هي الطريقة الوحيدة للقيام بذلك الأمر.
لا توجد معاملة خاصة لتطبيقات معينة. واحدة من الأمور الاعتيادية التي تقوم بها الكثير من لغات البرمجة مثلا هي البحث في النصوص عن أنماط ما باستخدام التعبيرات القياسية (Regular Expressions)، وللقيام بذلك، توجد عادة دالة في اللغة تأخذ التعبير القياسي والنص الذي تريد البحث فيه عن المقاطع المطابقة لهذا التعبير وتعيد لك هذه المقاطع، لكن مبرمجي Perl أحسوا بأن هذا الأمر مهم جدا، فلم يكفيهم أن يتم ذلك عبر دوال عادية، حالها حال القيام بأي أمر آخر، بل قاموا بعمل تعابير برمجية خاصة بالقيام بهذه العملية.
المشكلة هنا هي أن Perl أخذت تطبيقا خاصا بمجال محدد وهو مجال معالجة النصوص وأدخلته في صلب اللغة، والسؤال الذي يطرح نفسه في هذا المجال هو لماذا يتم ادخال هذه الميزة المتعلة بمعالجة النصوص ولا يتم ادخال مزايا أخرى في صلب اللغة، مثل مزايا عمل الواجهات الرسومية وغيرها؟
هذه الأمور من الممكن أن تكون جزءا من صلب اللغة في اللغات المتخصصة، مثل لغة PHP، المصممة لعمل برامج ويب، أما اللغات التي تسعى لأن تكون لغات برمجة عامة فإنها تستطيع توفير كل هذه بطرق أخرى موحدة مثل الدوال والمكتبات البرمجية، الأمر الذي يجعل قراءة هذه الأمور أسهل بكثير لأنها تخضع للقوانين العامة للغة.
خلاصة القول
خلاصة القول هي أن Python تتميز بمجموعة من الصفات تجعلها شفراتها من أسهل الشفرات فهما ووضوحا، وهو أمر يجعلها ممتازة للمشاريع التي يعمل عليها أكثر من شخص وتتطلب تحديثا مستمرا، وهذه هي متطلبات المشاريع الكبيرة في هذا العصر.
ماذا عن Ruby؟
في بداية هذا المقال، أشرت إلى عدد من اللغات وقلت بأنني أعرفها جيدا، لكن هنالك لغة مثيرة للاهتمام لم أشر إليها، وهي لغة Ruby، التي اشتهرت مؤخرا كلغة لإنشاء مواقع الويب التفاعلية باستخدام هيكلية اسمها Ruby on Rails.
الكثير يقارنون بين Ruby وPython، فاللغتان متشابهتان كثيرا من الخارج، ولو أنهما تختلفان أيضا في الكثير من المفاهيم الجوهرية، أهم ما هو مشترك بين Ruby وPython برأيي هو ثقافة التركيز على تسهيل القراءة وفهم الشفرة ووضعهما على رأس سلم الأولويات.
خبرتي العملية في استخدام Ruby لم تتعدى الشهرين في مقابل Python التي أستخدمها منذ أكثر من ثلاثة سنوات، لكن انطباعي عنها إلى الآن ممتاز، وحدسي يقول لي بأنها ستشارك Python كلغة مفضلة ثانية بالنسبة لي.