فن التعلم العميق: متى تستنفد كل ما يمكن تعلمه من مشكلة برمجية؟

دقائق القراءة: 7

مقدمة: ما وراء الحل المباشر للمشكلات البرمجية

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

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

مفهوم “النظر إلى الخلف” في حل المشكلات

في هذا السياق، وحسب تعبير عالم الرياضيات جورج بوليا (George Pólya)، يحين الوقت “للنظر إلى الخلف” (look back). يكتب بوليا عن عملية حل المشكلات في كتابه “كيف تحلها؟” (How to Solve It)، من منظور حل المشكلات الرياضية. لكن أفكاره قابلة للتطبيق بامتياز على البرمجة.

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

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

  • التعلم من النجاحات: فهم ما كتبته ولماذا اخترت هذه الطريقة تحديداً.
  • ترسيخ تعلم المفاهيم الجديدة التي اكتسبتها.
  • رؤية الأنماط المتكررة وفهم السياق الأمثل لاستخدام بنية بيانات (data structure) أو خوارزمية (algorithm) معينة.

مثال توضيحي: لاعب كرة السلة

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

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

لماذا يُعد “النظر إلى الخلف” أمراً حاسماً؟

1. رؤية الأنماط وفهم السياق

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

2. ترسيخ تعلمك

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

3. التعلم من نجاحاتك

يصل عالم الرياضيات ريتشارد هامينغ (Richard Hamming) إلى جوهر الأمر من خلال هذا الاقتباس من كتابه “فن القيام بالعلوم والهندسة” (The Art of Doing Science and Engineering): “أعتبر دراسة النجاحات أكثر أهمية من دراسة الإخفاقات… هناك الكثير من الطرق للخطأ والقليل جداً للصواب، لذا فإن دراسة النجاحات أكثر كفاءة.”

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

أربع طرق فعالة لتطبيق “النظر إلى الخلف”

هناك عدة طرق أستخدمها “للنظر إلى الخلف” في المشكلات. جربها بنفسك:

1. علّم نفسك

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

إليك مثال على بعض الكود وبعض التعليقات التي كتبتها:

 export default function ManageTeamMembersPage ( props ) { const [teammate, setTeammate] = useState({ name : "" , email : "" , role : "" , }) ... // Use props to access data passed down from the parent component. // Add state hook. The hook takes a default, which is an object that contains everything I need for the form: name, email, role.

تتعلق هذه الطريقة من “النظر إلى الخلف” بالفهم العميق. في هذا المثال، كنت أتعلم عن الحالة (state) والخصائص (props) والنماذج (forms) في مكتبة React. كتابة التعليقات لشرح الكود الخاص بك سيساعدك على ترسيخ المفاهيم في ذهنك. إذا لم تتمكن من كتابة شرح قصير لها على الفور، فراجع الموضوع. هذه الطريقة مفيدة بنفس القدر للمشكلات والمشاريع المستقبلية. أقوم بانتظام بسحب المشكلات والبرامج القديمة التي قمت بتدوينها. أستخدمها كمرجع عند كتابة برامج ذات صلة أو حل مشكلات ذات صلة. القيام بذلك يعزز الأفكار الرئيسية، ووفقاً لنقطة هامينغ، يساعدني على تذكر نجاحاتي: ما يجب الاستمرار في فعله.

2. دراسة حلول المبرمجين المتميزين

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

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

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

3. إضافة قيود (Constraints)

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

4. حل مشكلة ذات صلة

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

الخلاصة التقنية

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

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *