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

سنتحدث في هذا الدليل حول دراسة علوم الحاسوب كطالب مبتدئ سواء كنت تريد البدء في دراستها أو تفكر في نيل شهادة جامعية فيها أو حتى بدأت رحلتك الدراسية بالفعل، وهو خلاصة خبرة أكثر من 40 عامًا لكاتبه برايان "بيج جورجينسن" هول Brian “Beej Jorgensen” Hall، حيث تعلمها ذاتيًا قبل الجامعة ثم أضاف لها عشرين سنة من العمل في السوق، ثم 8 أعوام أخرى في تدريسها للطلبة، وقد بنى الشرح المذكور هنا على الملاحظات التي جمعها من مراقبته للطلاب أثناء ارتكابهم لأخطاء شتى في تعلمهم لتتجنب أنت الوقوع فيها.

الجمهور المستهدف

لقد أعُد هذا الدليل خصيصًا لطلبة الجامعات الذين بدؤوا تعلم البرمجة حديثًا لكنه يصلح أيضًا لطلبة المراحل الثانوية أو أي شخص يرغب في تعلم البرمجة عمومًا.

الهدف الرئيسي

يتعلم الطلاب في الجامعات كيفية البرمجة باللغات المختلفة مثل Flutter و React و Rust وجافاسكربت و C++ و C وباسكال و LISP وفورتران FORTRAN وكوبول COBOL وغيرها من اللغات والتقنيات البرمجية، لكن هنا تبرز المشاكل التالية:

  • هناك العديد من التقنيات التي يصعب تغطيتها في أربع سنوات.
  • كل هذه اللغات ستُستبدل عاجلًا أم آجلًا وتحل محلها لغات وتقنيات أحدث، كما في حالة لغة كوبول المشار إليها أعلاه.

إن التصرف المنطقي لك كطالب في هذه الحالة هو صرف وقتك وجهدك في تعلم كيفية حل المشاكل البرمجية سواء كنت تعرضت لتلك المشاكل من قبل أو لا، بدلًا من السعي خلف تعلم التقنيات التي لا حصر لها إذ لن تستطيع تعلمها جميعًا، فليس المهم أن تتعلم كيف تصبح مطور تطبيقات آيفون أو أندرويد أو مطور لغة Go إذ أن هذا تحصيل حاصل إذا تعلمت الهدف الأساسي وهو "حل المشاكل البرمجية".

وصحيح أنك لن تتعلم لغة Go في الجامعة لكن ستتعلم كيفية تعلمها بنفسك، فهذه المهارة -أي التعلم الذاتي- مطلوبة في مجال تطوير البرمجيات إذ يستبعد أن تكون وظيفتك الأولى هي استخدام تقنيات استخدمتها في الجامعة من قبل، بل في الواقع قد يستغرب بعض الخريجين الجدد حين يرون أن التقنيات التي استخدموها في الجامعة لا تُستخدم في الوظيفة الأولى لهم.

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

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

عقلية النمو

هذه النقطة قد تكون صعبة، خصوصًا لمن لا يتقبّل الفشل. فبعض الناس يتوتر جدًا لدرجة تؤثر على معدته، وقد يبالغ في لوم نفسه وينتقدها بقسوة أكثر مما ينتقد الآخرين، حتى لو كان يعلم أن القسوة في النقد لا طائل منها، وإن كان الأولى هو التوازن بين اللامبالاة والقسوة المفرطة على النفس، أو ما تسميه عالمة النفس كارول دويك Carol Dweck مصطلح “عقلية النمو Growth Mindset”، وملخصه فيما يلي:

  • المهارات الشخصية قابلة للتطوير مع التدريب المستمر
  • التعلم عملية مستمرة مدى الحياة
  • التحديات هي فرص للنمو
  • تعلم من النقد والفشل
  • لا تستسلم أبدًا

هذا على النقيض من الشخصية التي تقسو على نفسها قسوة تضر بها، كأن تستغرق في اللوم والتقريع على فشل في محاولة لعبة مثلًا، وهذا النوع من الشخصيات هو ما تطلق عليه كارول “العقلية الثابتة Fixed Mindset”، وهو الاعتقاد الخاطئ أنه مهما لعبت فستصطدم بحدود قدراتك الذاتية التي لن تتجاوزها أبدًا حتى لو درست 500000 ساعة، لكن من المستحيل عمليًا لأي شخص ناضج عاقل أن يقضي نصف مليون ساعة في أمر ما ولا يتعلم منه شيئًا.

Quote

اخسر أول 50 مباراة لك بأسرع ما يمكن. مثل شهير من لعبة Go (لعبة استراتيجية مثل الشطرنج)

إذا كان هذا في حال نصف مليون ساعة، فكيف بخمسين ألف ساعة أو 50 ساعة، أو خمس ساعات فقط؟ سترى إن تفكرت في الأمر أن أي قدر من الممارسة سيؤدي حتمًا إلى التحسن، حتى لو شعرت أنك عالق في مكانك فإنك على الحقيقة لا تزال تستكشف طرقًا ومسارات ولو تبين أنها مسدودة، فعلى الأقل تعلمت أنها مسدودة.

Quote

إنما العلم بالتعلم، وإنما الحِلم بالتحلُّم، ومن يتحرَّ الخير يُعطه

تعلم فليس المرء يولد عالمًا، وليس أخو علمٍ كمن هو جاهلُ

بقدر الكد تُكتسب المعالي، ومن طلب العلا سهر الليالي

مع المحبرة إلى المقبرة

وهكذا فكل نجاح هو تجربة تعلم، وكل فشل هو تجربة تعلم كذلك، وكل تجربة تعلم تطور مهاراتك، فلا تخش الفشل بل استخدمه لتطوير مستواك.

الإصرار

Quote

لقد فشل المحترف مرات أكثر مما حاول المبتدئ أصلًا

ستيفن ماكريني Stephen McCranie

يرى برايان أن المثال هذا هو أحد سمات من يصل لمرحلة التميز في أي شيء، فمن تظن أنه سيتقدم في حياته، من يستسلم بعد الفشل أم الذي يفشل ويفشل ويفشل ولا يزال ينهض بعد فشله ليحاول مرة أخرى؟

هذا هو الفرق بين المطورين الأكفاء ومن سواهم، فهؤلاء الأكفاء فشلوا مرات ومرات لكن لم يستسلموا، بل أعادوا المحاولة مرة بعد مرة حتى تمكنوا من حل المشكلة التي بأيديهم في النهاية وقد تعلموا شيئًا جديدًا في كل مرة فشلوا فيها.

Quote

لم أفشل، بل وجدت 10000 طريقة لا تصلح.

توماس إديسون

قد يغيب عن الطالب حقيقة أن المعلِّم فشل مرات لا حصر لها، فإذا نفذ المعلم مثلًا عملية حذف عنصر من قائمة مترابطة Linked List أثناء شرح درس برمجي ونجح الأمر معه من أول محاولة فهذا لا يعني أن تلك أول محاولة له على الحقيقة، بل لعلها كانت المرة المائة التي ينفذ فيها هذه العملية، فإذا تدرب الطالب على عملية كهذا من الصفر مائة مرة ستنجح معه كذلك من أول محاولة إذ يكون قد تعلم دروسًا لا حصر لها في كل مرة.

فلو تسرب اليأس إلى نفسك لأنك ترى مادة ما مستحيلة على الفهم مع رؤيتك للمعلم يبسطها كأنها أمر تافه وحدثتك نفسك أن هذا المعلم أو هؤلاء الزملاء قد ولدوا بموهبة للبرمجة ليست لديك، فاعلم أن هذا صوت العقلية الجامدة Fixed Mindset التي تريد أن تظل في مكانك دون تطور، لكن تيقن أن لا شيء يميز المعلم عنك سوى عدد مرات الفشل التي تجرعها.

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

الدافع للتعلم

حين أراد برايان -كاتب الدليل- نيل درجة الدكتوراة نصحه مشرفه قائلًا “لابد أن يكون لديك دافع لنيل هذه الدرجة العلمية” لأن الحصول عليها يتطلب جهدًا كبيرًا لا بد له من سبب يدفع المرء لبذل الوقت والجهد الذي تحتاج إليه شهادة كهذه، وتنطبق هذه النصيحة على علوم الحاسوب عمومًا فهناك الكثير من الأمور الصعبة التي تحتاج إلى فهم عميق، مما يتطلب وجود دافع قوي لتعلمها.

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

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

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

عملية التعلم ليست سهلة

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

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

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

حل المشكلات

يقتبس هذا القسم فكرته من كتاب How to Solve it لمؤلفه جورج بوليا George Pólya، وهو كتاب يتناول كيفية التعامل مع المشاكل الرياضية، وذلك أن علوم الحاسوب في جوهرها إنما هي فرع من أفرع الرياضيات، فيمكن تطويع قواعد حل المشكلات الرياضية لتناسب علوم الحاسوب، وتتلخص منهجية الكتاب فيما يلي:

  1. فهم المشكلة
  2. التخطيط لكيفية حلها
  3. كتابة الحل برمجيًا
  4. مراجعة الحل لتحسينه

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

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

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

فهم المشكلة

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

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

ستعرف أنك أتممت خطوة "فهم المشكلة" إذا استطعت شرح المشكلة لشخص آخر، ذلك أنه يصعب كتابة وصف كامل لمشكلة ما إذا لم تستوعبها بنفسك أولًا، وستجد أثناء دراستك أو عملك أن توصيفات المشاكل التي تقابلك لا بد أن يعتريها وجه أو أكثر من وجوه النقص، فأكاد أجزم أنك لو حاولت أن تكتب قواعد لعبة بسيطة مثل XO ستجد فيما كتبت تفصيلًا نسيته هنا أو هناك، وهنا تبرز أهمية الأسئلة الاستيضاحية.

يضرب برايان مثلًا على هذا بمشروع عمل عليه من قبل حيث تولى مهمة برمجة الواجهة الأمامية Front-end فيه، بينما تولى شخص آخر مهمة الواجهة الخلفية، وكان بينهما مستند يصف بدقة آلية العمل بين الواجهتين، حيث نصت إحدى آليات العمل على إرسال نتيجة عملية حسابية، مع مثال يوضح النتيجة بصيغة ست عشرية Hexadecimal كما يلي: إذا كانت المدخلات هي abc و xyz فتكون النتيجة هي الرقم f319c2c6dcfb.

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

وضع خطة الحل

Quote

البرمجة هي أن تخبر إنسانًا آخر بما تريد من الحاسوب أن يفعله

دونالد نوث Donald Knuth، عالم حاسوب

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

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

  • كيف ستتدفق البيانات في النظام وكيف تتحول من مدخلات معروفة إلى المنتج النهائي المطلوب؟
  • ما هي الأنظمة الفرعية التي ستنفذ كل خطوة أثناء عمليات التحول تلك؟
  • ما هي التقنيات التي ستحتاجها لتنفيذ هذه الخطوات؟
  • ما هي المجاهيل المعروفة، أي الأمور التي تدرك أنك لا تملك لها إجابة بعد؟

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

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

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

كتابة الحل البرمجي

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

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

  • إتقان قواعد اللغة البرمجية التي تستخدمها
  • معرفة المكتبات البرمجية المتاحة والتي يمكن استخدامها
  • تجنب الوقوع في الأخطاء البديهية أو الصغيرة
  • الالتزام بخطة الحل الموضوع بدقة

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

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

المراجعة والتحسين

Quote

البرمجة حرفة، فافتخر بما صنعته يداك

برايان هول (مؤلف الدليل)

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

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

ونؤكد هنا أن عليك حل المشكلة بنفسك أولًا قبل النظر في مساعدة خارجية لتحسينها، فالهدف من التدريب أثناء الدراسة هو نفسه الهدف من التدريب الرياضي، أي ممارسة التمرين والحصول على الفائدة الرياضية للجسد وتقييم الأداء، لا أن يقوم شخص آخر بأداء التمرين بدلًا منك.

قد تمتلئ الشيفرة البرمجية بالأخطاء bugs أو تفتقر للكفاءة أو التنسيق الجيد، أو قد تكون صعبة القراءة، فينبغي الانتباه هنا إلى أن الشيفرة البرمجية يجب أن تكون سهلة القراءة والفهم من قبل غيرك من المبرمجين كي تكون سهلة الصيانة، وهذا يعني أن يكون مظهر الشيفرة البرمجية منسقًا، ذلك أن شكل الشيفرة قد لا يهم بالنسبة للمصرِّف compiler، لكن لا ينبغي أن نعذب البشر بقراءة طلاسم صعبة الفهم.

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

وتكون مرحلة المراجعة في بيئة العمل أثناء جلسات تحليل ما بعد المشروع، حيث يجتمع العاملون على المشروع لدراسة ما تم فيه بشكل صحيح وما كان ينبغي تجنبه أو تحسينه.

توقع أخطاء المستخدمين

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

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

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

تطبيق هذه المبادئ في مقابلات العمل

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

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

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

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

وقد تتفاجأ إذا علمت كثيرًا ممن يجرون مقابلات التوظيف البرمجية يهمهم رؤيتك تفكك مشكلة بطريقة منهجية وفعالة أكثر من وصولك للإجابة الصحيحة، بل إن إعطاء إجابة صحيحة دون إظهار مهاراتك وكيف وصلت إلى تلك الإجابة قد يتسبب في استبعادك من تلك الوظيفة.

يضرب كاتب الدليل مثلًا على هذا بمقابلة أجراها في شركة Activision حيث فشل في الوصول إلى حل صحيح لسؤالين، لكنه واصل التفكير بصوت عالي وبذل قصارى جهده لتوضيح كيفية تفكيره في المشكلة التي أمامه، ونال تلك الوظيفة في النهاية، وكان السؤالان اللذان أخفق فيهما هما "ما هي أسرع طريقة لعكس ترتيب البتات داخل البايت الواحد؟" و"حسِّن كفاءة عملية حسابية تبني شبكة مسافات بين جميع لاعبي كرة القدم في الملعب".

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

تكلفة كل مرحلة

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

أما عند الوصول إلى المرحلة الثالثة، وهي مرحلة البرمجة Coding، فهنا تكون التعديلات عالية التكلفة، فقد تكتشف أن عليك التخلص من شيفرات برمجية تكلف تطويرها آلاف أو ملايين الدولارات، ثم إعادة كتابتها مرة أخرى، رغم أن مثل هذه الحالات يرد حدوثها كثيرًا في الشركات، لكنها تلجأ إلى مثل هذه العملية بعد إجراء تحليل عميق للتكلفة مقابل القيمة Cost-Benefit لترى إن كان التعديل يستحق.

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

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

تفكيك المشكلات

Quote

ما خفي كان أعظم

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

  • صناعة الطاولة
  • تثبيت أرجل الطاولة في القرص العلوي
    • صناعة القرص العلوي للطاولة
    • صناعة أرجل الطاولة

وحتى هذا التفصيل قد لا يكون كافيًا، فكيف نصنع أرجل الطاولة؟ وكيف نصنع القرص العلوي لها؟ ستكون التفاصيل وفقًا لهذه الأسئلة كما يلي:

  • صناعة الطاولة
    • تثبيت أرجل الطاولة في القرص العلوي
      • صناعة القرص العلوي
        • صنفرة سطح القرص العلوي
          • لصق حواف جانبية للقرص العلوي
            • قص الجزء العلوي الأساسي
              • تعلم كيفية استخدام منشار الطاولة
            • قص حواف الجزء العلوي
      • صناعة أرجل الطاولة
        • قص الأرجل
        • استخدم المخرطة لصناعة الشكل النهائي للأرجل
          • تعلم استخدام المخرطة

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

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

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

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

الشيفرة الوصفية Pseudocode

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

Quote

 ابحث عن المكان الصحيح في القائمة
أدخل القيمة هناك

لكن هذه الخطوات لا تصف المطلوب بدقة، لذا سنفككها أكثر:

Quote

ابحث عن المكان الصحيح في القائمة

ابحث عن أول عنصر أكبر من القيمة الجديدة

أدرج القيمة هناك

أزح جميع القيم الأكبر إلى اليمين

ضع القيمة الجديدة في المكان الذي فرغ للتو

هكذا تكون الصورة قد اتضحت قليلًا، لكن لا زال يمكن تحسينها كما يلي:

Quote

ابحث عن المكان الصحيح في القائمة

ابحث عن أول عنصر أكبر من القيمة الجديدة

أنشئ حلقة تكرارية‫ Loop تمر على العناصر

أوقف الحلقة حين تعثر على عنصر أكبر

أدرج القيمة هناك

أزح جميع القيم الأكبر إلى اليمين

ضع القيمة الجديدة في المكان الذي فرغ للتو

لا زال لدينا مرحلة أخرى من التحسين على هذه الخطوات:

Quote

ابحث عن المكان الصحيح في القائمة

ابحث عن أول عنصر أكبر من القيمة الجديدة

أنشئ حلقة تكرارية‫ Loop تمر على العناصر

أوقف الحلقة حين تعثر على عنصر أكبر

سجّل الفهرس الذي يسبق هذا العنصر

أدرج القيمة هناك

أزح جميع القيم الأكبر إلى اليمين

ضع القيمة الجديدة في المكان الذي فرغ للتو

اضبط قيمة العنصر عند ذلك الفهرس لتكون هي القيمة الجديدة

هكذا نكون قد اقتربنا كثيرًا من تحويل شيفرتنا الوصفية إلى شيفرة حقيقية، فمثلًا لا تزال الآلية الخاصة بإزاحة القيم غير واضحة وربما ينبغي أن نفككها أكثر.

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

بناء النموذج الأولي Proof of Concept

إلى هنا نكون قد فهمنا المشكلة الأصلية التي نريد حلها وقسمناها إلى أجزاء أصغر منها تمثل مشكلات فرعية، لكننا لا نعرف بعد إن كانت تلك المشكلات الفرعية قابلة للتنفيذ أصلًا أم لا، فهل تستطيع مثلًا معالجة صورة في عنصر canvas في HTML ثم حفظ تلك الصورة مباشرة إلى معرض الصور في هاتف محمول؟

لعلك لم تنفذ هذه العملية من قبل، ولا تعرف هل يمكن تنفيذها تقنيًا أم لا، وهنا تبرز أهمية بناء نموذج أولي proof of concept يثبت إمكانية تنفيذها، وتطبيقًا على مثال الصورة هنا، سننشئ صفحة ويب ونضيف عنصر canvas ثم نرسم فيه شكلًا بسيطًا مثل مربع أو مستطيل، ثم نضيف الشيفرة التي تحمّل هذا الشكل كصورة إلى المعرض عند النقر على زر التحميل.

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

  1. أن الفكرة يمكن تنفيذها عمليًا
  2. أننا عرفنا كيف نكتب الشيفرة الحقيقية المطلوبة لتنفيذها

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

Quote

التخلص من إحدى النسخ أمر حتمي

فريد بروكس Fred Brooks، كتاب The Mythical Man-Month

تصلح شيفرة النموذج الأولي في عرض شكل المنتج النهائي أو كيفية عمله للآخرين، ذلك أن المطورين يكتبون نماذج محاكاة mock implementation للتطبيق أو البرنامج الذي يعملون عليه، لا يعمل فيه إلا جزء صغير فقط من واجهة المستخدم لكنه يعطي فكرة عامة عن آلية عمل البرنامج مستقبلًا.

استخدام الأداة المناسبة

Quote

ما هي أفضل لغة برمجة؟

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

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

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

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

وبإسقاط هذا المثال على مجال البرمجة سترى أن أفضل المطورين يتقنون أدوات كثيرة، ويعرفون متى يستخدمون كلًا منها، فإذا حدثتك نفسك بالابتعاد عن لغة ما لأنك تكره أمرًا فيها، فابحث عن الحالات التي تُستخدم فيها تلك اللغة وتصلح لها فهي لم تُبتكر عبثًا، فإذا عرفت حالات استخدامها عرفت مدى أهميتها لرحلة تعلمك ومتى يتعين عليك استخدامها تحديدًا، فإذا سألت مطورًا خبيرًا عن لغته المفضلة ربما يقول لك أنها Rust، أو بايثون، أو C أو جافاسكربت أو SQL أو AWK أو Bash، لكن دقة هذه الإجابة تتوقف على حالة الاستخدام التي تسأل عنها.

تبني الآراء التقنية

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

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

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

كن صاحب رأي كذلك في الخوارزميات التي تختارها، بنفس منطق الفقرتين السابقتين فستجد الكثير من الخوارزميات التي يمكن استخدامها، فانظر أيها تخدم حالتك أو تحل مشكلتك وبناء على ذلك تستطيع اتخاذ قرار باستخدام خورازمية فرز الدمج Mergesort مثلًا أو الفرز بالإدراج Insertion sort، وبالمثل هل الأفضل أن نستخدم البحث الثنائي Binary search أم البحث الخطي Linear search.

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

  • كفاءة تلك التقنية في حل المشكلة التي لديك وأداؤها مقارنة بغيرها
  • سهولة قراءة الشيفرة الخاصة بالتقنية أو الخوارزمية أو لغة البرمجة وصيانتها مستقبلًا
  • الوقت المستغرق في كتابتها وتطويرها
  • تكلفة الأداة أو التقنية نفسها
  • التقنيات المستخدمة بالفعل في المشروع ومدى توافق الأداة الجديدة معها

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

نصائح للتعلم

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

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

حالة التركيز العميق

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

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

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

القراءة المسبقة

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

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

نسخ الحلول الجاهزة

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

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

قاعدة 30 دقيقة

قد يحدث أن تحاول الوصول إلى حل في مشكلة ما دون جدوى وعندئذ لا بأس من الاستعانة بأحد الحلول الجاهزة، لكن تأكد أنك قد حاولت أكثر من طريقة وقضيت فيها نصف ساعة على الأقل، يضرب برايان -كاتب الدليل- مثلًا على هذه النقطة بكتاب هيكلة وتفسير برامج الحاسوب The Structure and Interpretation of Computer Programs وهو أحد كتب تعلم البرمجة، إذ حدد لنفسه ست ساعات لحل كل مشكلة برمجية مذكورة في الكتاب لا ينظر إلى الحل فيها قبل نهاية ذلك الوقت.

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

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

الخروج للتنزه

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

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

اشرح المشكلة لغيرك

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

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

تدوين الأسئلة

ستتعرض لنوعين من الأسئلة عند تعمقك في قراءة وصف مشكلة ما أو عند تعلم لغة أو أداة جديدة:

  • أسئلة معيقة Blocking Questions: وهي الأسئلة التي تعيق تقدمك بحيث لا تستطيع إنجاز شيء آخر قبل معرفة إجابتها
  • أسئلة غير معيقة: وهي أمور تثير فضولك أثناء عملك على المشكلة، لكن تستطيع مواصلة العمل دون معرفة إجابتها في الوقت الحالي

قد تكون الأسئلة غير المعيقة على شاكلة هل تدعم هذه اللغة تفكيك الكائنات destructuring assignments؟ أو هل توفر هذه المكتبة أرقامًا عشوائية داخل نطاق أرقام صحيحة؟ أو ما هي بروتوكولات الشبكة الأخرى المدمجة في المكتبة القياسية؟ وهذه أسئلة لا تؤثر معرفة إجابتها على سير عملي الحالي لكنها قد تطرأ على ذهنك أثناء العمل فالأفضل تدوينها الآن ثم العودة لاحقًا للإجابة عنها.

بناء النسيج المعرفي

قد تشعر في بداية تعلمك للبرمجة أنك في وسط عالم شاسع غير مستكشف بعد، ربما تكون قد نجحت في طباعة عبارة Hello World! على الشاشة، لكن تشعر أنك بعيد عن المستوى الحقيقي لسوق العمل أو للمطور المحترف، فلا يدفعك هذا إلى اليأس بل إلى محاولة رسم تضاريس هذا العالم الجديد حيث ستكتشف وجود الدوال والمتغيرات وعمليات الإدخال والإخراج I/O، وستدرك كيف تترابط هذه العناصر ثم تتعرف إلى الشبكات وعلاقتها بنظم الإدخال والإخراج في نظم التشغيل.

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

Quote

لديك مجموعة من 10 أشخاص مرقمين من 0 إلى 9، ويصطفون جميعًا أمام نافذة في بنك ما، تريد أن تحاكي عملية ترتيبهم عشوائيًا بدون تكرار في الوقت الفعلي O(n)‎، كيف تكتب شيفرة تحل هذه المشكلة؟

ربما تكون قد كتبت برنامجًا من قبل يخلط أوراق اللعب باستخدام خوارزمية Fisher-Yates، فهذه مشكلة قد تشبه التحدي الذي لدينا هنا، فربما نجرب إنشاء قائمة بهؤلاء الأشخاص من 0 إلى 9 ثم خلط هذه القائمة تمامًا كأوراق اللعب، فهي نفس المشكلة عند التفكر فيها.

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

مراجعة الشيفرات البرمجية

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

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

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

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

الانضمام إلى المجتمعات البرمجية

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

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

تنقيح الأخطاء البرمجية Debugging

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

النموذج الذهني

يقصد بالنموذج الذهني هنا أن تستطيع كمطور أن تتخيل ما سينتج عن الشيفرة التي تقرؤها، مثال:

def foo(n):
    i = 0

    while i < n:
        i = i + 1 + (i % 2)

    print(i)

foo(5)

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

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

إذا اتبعت هذه الخطوات مرة بعد مرة ستتطور لديك مهارة المحاكاة الذهنية.

إعادة إنتاج الخطأ

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

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

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

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

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

وهكذا فإن الوصول إلى الحد الأدنى من الخطوات اللازمة لحدوث الخطأ يساعدك في تحديد مكانه بدقة أكبر ويجعل اختبار الإصلاح الذي تنفذه أسهل كذلك لأنك ستوفر وقتًا كان سيذهب هدرًا في إعادة إنتاج الخطأ في كل مرة.

العثور على الخطأ

لنفترض الآن أنك عرفت بوجود خطأ ما لأنك تحصل على مخرجات لم تكن تتوقعها من المدخلات التي أعطيتها لشيفرتك، لكن كل ما تعرفه إلى الآن هو أن هناك خطأ ما بين 10000 سطر برمجي وأنك إذا أعطيت الشيفرة الرقم 2 ينبغي أن تخرج لك الرقم 3490 لكنها أعطتك 299792458 بدلًا منها، إذًا لا بد أن يكون الخطأ في مكان ما بين المدخلات والمخرجات.

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

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

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

يزعم برايان -كاتب الدليل- أن الخطأ لا يكون مكتشَفًا حتى تفهم سلوكه فهمًا تامًا، أي عندما تفهم كيف أنتج برنامجك القيمة 299792458 بدلًا من 3490، ثم تصلح الخطأ جذريًا وفقًا لهذا الفهم. وهذا الأسلوب له عدة فوائد منها مثلًا:

  • تصبح أكثر ثقة أنك أصلحت الخطأ إصلاحًا جذريًا
  • تتعلم كيفية تمييز الأنماط التي أدت إلى حدوث هذا الخطأ لتتجنبها في المستقبل أو تدركها مبكرًا
  • تصقل مهارتك في حل المشكلات أثناء معالجتك للخطأ وفهمه

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

التنقيح باستخدام أوامر الطباعة

تعتمد طريقة التنقيح بأوامر الطباعة Print Debugging أو printf debugging كما يسميها مبرمجو لغة C على توزيع أوامر الطباعة توزيعًا مدروسًا داخل الشيفرة لمعرفة حالة البرنامج في لحظة معينة، وهي الطريقة الكلاسيكية لفحص البرمجيات أثناء التشغيل ويكثر استخدامها في حالتين مشهورتين:

  1. التحقق من مسار التدفق: حيث نجعل البرنامج يطبع أي شيء في لحظة ما لنرى إن كانت الشيفرة تعمل عند ذلك الجزء.

 

print("A")

x = foo()

print("B")

if x == 3:
    print("C")
    x *= 2
else:
    print("D")
    bar()

print("E")

لاحظ هنا أننا نستطيع عند تشغيل البرنامج تحديد المسافة التي وصل إليها قبل أن ينهار crash ومعرفة إذا كانت قيمة x تساوي 3 أم لا بناء على المحارف المطبوعة على الشاشة.

      2. فحص القيم: بأن نطبع قيم متغيرات معينة لرؤيتها ومعرفة ما هي، في المثال أدناه نحصل على بيانات من مستشعر sensor داخل حلقة تكرارية، ونشك أن بعض           هذه البيانات مغلوطة لكن لا نعرف إن كان المستشعر هو السبب فهنا نطبع البيانات على الشاشة لنرى ما نحصل عليه:

while not done:
    data = get_sensor_data()

    print(f"Got sensor data: {data}")

    process_sensor_data(data)

    done = data < 0

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

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

print("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");

فهي جملة تظهر بوضوح على الشاشة وإذا رآها العميل فلن تعدو كونها أكثر من مجرد هفوة أو خطأ كتابي لا أكثر.

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

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

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

المنقحات Debuggers

المنقحات هي أدوات تساعدك على العثور على الأخطاء البرمجية، وتشترك جميعها رغم تعدد أنواعها في مزايا جوهرية:

  • إضافة نقاط التوقف breakpoints التي تأمر البرنامج أن يتوقف عندها لتتحكم أنت في عملية التنقيح
  • التنفيذ خطوة خطوة Single step الذي يمرر البرنامج سطرًا واحدًا في كل مرة
  • فحص قيم المتغيرات

إضافة إلى مزايا أخرى تشمل ما يلي:

  • الدخول إلى الدالة Step into لتتبع ما يحدث فيها
  • الخروج من الدالة Continue out للرجوع إلى الشيفرة المستدعاة بعد فحص الدالة
  • تجاوز الدالة Step over لتنفيذ الدالة كاملة والانتقال لما بعدها دون دخول تفاصيلها
  • ضبط قيم المتغيرات، حيث تستطيع تعديل البيانات أثناء التشغيل لتجربة سيناريوهات مختلفة
  • فحص مكدس الاستدعاءات Call Stack لمعرفة تسلسل الدوال التي أدت إلى الوصول إلى النقطة الحالية
  • نقاط التوقف المشروطة التي لا توقف البرنامج إلا عند تحقق شرط معين

توجد منقحات أخرى تسمى منقحات "السفر عبر الزمن" Time-travel debuggers وإن كانت نادرة، وهي تسمح لك بالذهاب لنقطة متقدمة في شيفرتك أو الرجوع إلى الخلف فيها، وهذا مفيد جدًا إذا تجاوزت النقطة التي حدث عندها الخطأ وأردت العودة إليها.

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

تعلم لغات برمجية جديدة

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

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

وهناك ركنان أساسيان ينبغي اعتبارهما عند تعلم لغة جديدة لها نمط paradigm تعرفه مسبقًا، كأن تكون لغة إجرائية procedural أو كائنية التوجه object oriented أو وظيفية functional:

  1. تعلم القواعد syntax مثل كيفية كتابة تعليمات if و while وكيفي التصريح عن المتغيرات والدوال
  2. تعلم المكتبات القياسية، وهي الوظائف المدمجة التي تستطيع استخدامها كقراءة الملفات وكتابتها أو الطباعة على الشاشة أو الاتصال بخادم ويب

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

تعلم قواعد اللغة البرمجية

أفضل طريقة لتعلم قواعد اللغة هي اقتحام المجال مباشرة بأن تتابع درسًا تعليميًا وتكتب برنامج وإن كان لتوضيح المثال فقط، أي تتمرن بها على جانب ما من اللغة التي تتعلمها، على سبيل المثال، كيف تصيغ التعليمات الشرطية في لغة Rust؟ لم لا تكتب برنامجًا بسيطًا للتدرب على هذا:

fn main() {
    if (1 == 2) {
        println!("هناك خطأ فادح");
    } else {
        println!("هذا صحيح");
    }
}

فتمرين بسيط كهذا يجعلك تتفكر إن كانت هذه الأقواس حول تعليمة if ضرورية، دعنا نتحقق:

$ rustc foo.c
  warning: unnecessary parentheses around `if` condition

تبين أنها ليست ضرورية! هذا هو الهدف من التعلم بمثل هذه التمارين البسيطة، من المفيد أيضًا أن تبحث عن كيفية تطبيق المفاهيم التي عرفتها من لغتك الأولى في اللغة الجديدة التي تتعلمها، مثل الدالة الرئيسية والمتغيرات والتعليمات الشرطية وحلقات التكرار والأصناف Classes وغيرها.

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

تعلم المكتبات القياسية

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

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

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

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

تعلم نموذج برمجي جديد

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

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

وتوجد طريقتان مختلفتان لحل المشكلة، إما بنمذجتها كسلسلة خطوات أو ككائنات، ونسمي هذه النماذج المختلفة نماذج برمجية، فالنوع الأول -أي الخطوات المتسلسلة- نسميه البرمجة الإجرائية Procedural Programming أما النوع الثاني فنسميه البرمجة كائنية التوجه Object-Oriented Programming. صحيح أن هناك نماذج غيرها لكن أشهرها هي البرمجة الكائنية والإجرائية والوظيفية functional.

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

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

استخدام الذكاء الاصطناعي

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

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

ما أهمية مثل هذا الحديث لك كطالب تدرس علوم الحاسوب حاليًا؟ سنوضح في هذا الفصل كيفية استخدام الذكاء الاصطناعي كمعين لك في دراستك ثم كيفية استخدامه في بيئة العمل، وكذلك ما يجب تجنبه عند استخدامه.

ما يجب تجنبه مع الذكاء الاصطناعي

يذكر برايان -كاتب الدليل- أنه يحب دراسة كتاب Structure and Interpretation of Computer Programs لتطوير قدراته البرمجية وأنه يعطي نفسه ست ساعات لحل كل مشكلة في ذلك الكتاب، لاحظ أن المشكلات التي نتحدث عنها هنا ليست مشكلات حقيقية بل تدريبية مصطنعة، وحلولها متوفرة مجانًا على الإنترنت، فلماذا يقضي ست ساعات في حلها إذًا، ألا يبدو هذا مضيعة للوقت في حين كان يستطيع نسخ مستودع repo كتبه شخص آخر أو ينسخ الحل من مكان ما أو ربما يدفع لمبرمج كي يحل له هذه المشاكل؟

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

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

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

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

الاستخدام الصحيح للذكاء الاصطناعي في الدراسة

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

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

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

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

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

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

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

استخدام الذكاء الاصطناعي في العمل

يذكر برايان -كاتب الدليل- أن الذكاء الاصطناعي لم يكن موجودًا بالصورة المعروفة حاليًا حين كان يعمل في السوق البرمجي، لكنه مع هذا يستخدمه الآن لإنجاز مهام بسرعة أكبر بسبب مستوى خبرته الحالي.

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

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

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

الذكاء الاصطناعي في سوق العمل

يذكر برايان أنه كان يظن أن شركة ياهو فكرتها غبية حين خرجت للنور أول مرة، لكنها حققت أرباحًا بمليارات الدولارات، وهو أمر يتكرر كثيرًا في السوق البرمجي كل فترة، أن هذه التقنية أو تلك ستكون ثورة جديدة تلغي ما سبقها وتقلل الحاجة إلى المطورين لأن كتابة البرمجيات ستكون أمرًا سهلًا على كل الناس، كما حدث في موجة No Code، لكن قد يحدث حقًا أن توجد طفرة لا تنطبق عليها القوانين السابقة كما نرى في حالة النماذج اللغوية وأدوات الذكاءالاصطناعي مثل ChatGPT.

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

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

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

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

خاتمة

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

ترجمة -بتصرف- للدليل Beej's Guide to Learning Computer Science لصاحبه Brian “Beej Jorgensen” Hall


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

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

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



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

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

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

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   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.


×
×
  • أضف...