يا هلا بيكم يا جماعة الخير، معكم أخوكم أبو عمر.
خلوني أحكي لكم قصة صارت معي قبل سنوات طويلة، أيام ما كنت لسا شاب صغير بحاول أثبت حالي في عالم البرمجة. وصلتني فرصة مقابلة في شركة كبيرة، من الشركات اللي الكل بيحلم يشتغل فيها. تحضرت للمقابلة شهور، حليت مسائل على كل المنصات اللي بتخطر على بالكم، وكنت حاسس إني “وحش” برمجة وجاهز لأي تحدي.
دخلت المقابلة، وبعد شوية كلام وتعارف، أعطاني المحاوِر (Interviewer) مسألة برمجية على السبورة البيضاء. المسألة كانت متوسطة الصعوبة، وشبيهة بشيء حليته قبل هيك. ابتسمت ابتسامة الواثق من نفسه، مسكت القلم، وبلّشت أفكر. في عقلي، كانت الخوارزميات تتراقص، وهياكل البيانات تتشكل. خلال دقيقتين، كان الحل الأمثل واضح قدامي زي الشمس. صمت مطبق في الغرفة، ما في غير صوت القلم على السبورة. كتبت الكود، سطر ورا سطر، نظيف، مرتب، وبأفضل تعقيد زمني (Time Complexity) ممكن.
لما خلصت، تراجعت خطوة للوراء ونظرت لإنجازي بفخر. نظرت للمحاوِر وقلت: “تفضل، هذا هو الحل”.
نظر هو للكود، هز رأسه بهدوء، وسأل سؤالين بسيطين، ثم قال الجملة اللي بيكرهها كل مبرمج: “تمام، شكرًا لوقتك. راح نتواصل معك”.
خرجت من المقابلة وأنا حاسس إني أبدعت. لكن بعد أسبوع، وصلتني رسالة الرفض المعتادة. “نعتذر… نتمنى لك التوفيق…”. صابتني صدمة! كيف؟ الحل كان صحيح 100%، والكود كان مثالي! تكرر هذا السيناريو في مقابلتين بعدها. إجابات صحيحة، ورفض صامت.
كنت على وشك أفقد الأمل، لحد ما فضفضت لصديق إلي أكبر مني وعنده خبرة. سمع القصة، وضحك ضحكة خفيفة وقال لي: “يا أبو عمر، المشكلة مش في كودك، المشكلة في صمتك. هم ما بدهم آلة بتكتب كود، هم بدهم يوظفوا مهندس يفكر ويتحاور ويحل المشاكل. أنت أعطيتهم السمكة، بس ما فرجيتهم كيف اصطدتها”.
هذه الجملة كانت نقطة التحول في مساري المهني كله. ومن يومها، تعلمت فن “التفكير بصوت عالٍ”.
لماذا الصمت قاتل في المقابلات التقنية؟
قبل ما ندخل في “كيف”، خلينا نفهم “ليش”. لما تكون صامت وأنت بتحل المشكلة، المحاوِر ما بيشوف غير النتيجة النهائية. هو ما بيعرف شو اللي كان يدور في بالك. هل أنت:
- حافظ الحل؟ يمكن تكون شفت نفس المسألة وحافظها، وهذا لا يعكس قدرتك على حل المشاكل الجديدة.
- وصلت للحل بالصدفة؟ ربما جربت شيء وزبط معك بالحظ، لكنك لا تفهم المبادئ الأساسية وراءه.
- شخص صعب العمل معه؟ المقابلة هي محاكاة ليوم عمل. إذا كنت صامتًا ومنعزلًا في المقابلة، سيفترضون أنك ستكون كذلك في الفريق. البرمجة عمل جماعي، والتواصل هو مفتاحه.
- عاجز عن شرح أفكارك؟ كونك مبرمجًا شاطرًا شيء، وكونك قادرًا على شرح أفكارك التقنية لزملائك (حتى غير التقنيين) شيء آخر لا يقل أهمية.
المحاوِر مش كومبايلر (Compiler) يتأكد من صحة الكود فقط. هو يريد أن يرى طريقة تفكيرك، كيف تحلل المشكلة، كيف تقارن بين الحلول المختلفة، وكيف تتعامل مع العقبات. صمتك يحرمه من كل هذا.
ما هو “التفكير بصوت عالٍ” (Thinking Out Loud)؟
ببساطة، هو أن تحوّل أفكارك الداخلية إلى حوار مسموع. هو أن تشرح للمحاوِر كل خطوة تخطوها في عقلك، من لحظة قراءة المسألة وحتى اختبار الحل النهائي. أنت لا تثرثر بلا هدف، بل تقدم تعليقًا منظمًا ومباشرًا على عملية حل المشكلة.
تخيل نفسك معلقًا رياضيًا على مباراة كرة قدم تجري داخل دماغك. مهمتك هي شرح كل تمريرة، كل خطة، وكل هجمة للمشاهدين (المحاوِر).
كيف تطبق “التفكير بصوت عالٍ” خطوة بخطوة؟ (مع مثال عملي)
لنجعل الأمر عمليًا. لنفترض أن المحاوِر أعطاك هذه المسألة الكلاسيكية: “أعطيتك مصفوفة من الأرقام (Array of integers) ورقمًا مستهدفًا (Target). عليك إيجاد مؤشري (indices) رقمين في المصفوفة مجموعهما يساوي الرقم المستهدف”.
مثال: `nums = [2, 7, 11, 15]`, `target = 9`. الإجابة هي `[0, 1]` لأن `nums[0] + nums[1] = 9`.
هنا كيف ستتعامل معها بأسلوب التفكير بصوت عالٍ:
الخطوة الأولى: تأكد من فهمك للمسألة
لا تقفز مباشرة إلى الحل. ابدأ بالحديث:
“تمام، إذًا المطلوب هو إيجاد مؤشري عنصرين في المصفوفة `nums` مجموعهما يساوي `target`. فهمت المسألة بشكل صحيح؟”
ثم ابدأ بطرح أسئلة توضيحية (Clarifying Questions) لتظهر أنك تفكر في الحالات الهامشية (Edge Cases):
- “هل يمكن أن تحتوي المصفوفة على أرقام سالبة أو صفر؟”
- “ماذا لو لم يكن هناك حل؟ هل أرجع مصفوفة فارغة أم `null`؟”
- “هل يمكن استخدام نفس العنصر مرتين؟ (على الأغلب لا، لكن السؤال جيد)”
- “هل هناك ضمانة بوجود حل واحد فقط؟”
هذه الأسئلة وحدها تضعك في خانة المرشحين المتميزين، لأنها تظهر أنك دقيق ومنهجي.
الخطوة الثانية: استعراض الحل المبدئي (الحل الساذج – Brute Force)
لا تخف من البدء بالحل الأبطأ والأكثر بديهية. هذا طبيعي ويظهر أنك تبني تفكيرك تدريجيًا.
“حسنًا، أول حل بيخطر على بالي هو الحل المباشر. يمكنني استخدام حلقتين متداخلتين (Nested Loops). الحلقة الخارجية ستمر على كل عنصر، والحلقة الداخلية ستمر على باقي العناصر للبحث عن العنصر المكمّل له. إذا وجدت عنصرين مجموعهما يساوي الهدف، سأرجع مؤشريهما.”
ثم حلل هذا الحل بصوت عالٍ:
“هذا الحل سيعمل بالتأكيد. لكن من ناحية الأداء، التعقيد الزمني سيكون O(n²)، لأن لكل عنصر في المصفوفة، سأمر على باقي العناصر تقريبًا. إذا كانت المصفوفة كبيرة جدًا، قد يكون هذا الحل بطيئًا جدًا. دعنا نرى إن كان بإمكاننا تحسينه.”
الخطوة الثالثة: الانتقال إلى الحلول المحسّنة
هنا تظهر براعتك في التحسين (Optimization).
“لتحسين الأداء من O(n²) إلى شيء أسرع، ربما O(n)، نحتاج إلى تجنب الحلقة الداخلية. كيف يمكننا أن نعرف بسرعة ما إذا كان ‘العنصر المكمّل’ موجودًا في المصفوفة دون الحاجة للبحث عنه في كل مرة؟”
“أها! يمكننا استخدام هيكل بيانات يسمح بالبحث السريع، مثل الـ Hash Map (أو الـ `object` في JavaScript أو `dict` في Python). الفكرة هي أنني سأمر على المصفوفة مرة واحدة فقط.”
“في كل خطوة، سأحسب ‘المكمّل’ (complement)، وهو `target – current_number`). ثم سأبحث عن هذا المكمّل في الـ Hash Map. إذا وجدته، فهذا يعني أنني وجدت الحل وسأرجع المؤشر الحالي ومؤشر المكمّل الذي خزنته سابقًا. إذا لم أجد المكمّل، سأقوم بتخزين الرقم الحالي ومؤشره في الـ Hash Map، حتى تتمكن العناصر اللاحقة من إيجاده.”
لا تنس تحليل الحل الجديد:
“هذا النهج ممتاز! لأنه سيقلل التعقيد الزمني إلى O(n)، لأنني أمر على المصفوفة مرة واحدة فقط، وعمليات البحث والإضافة في الـ Hash Map تأخذ وقتًا ثابتًا O(1) في المتوسط. أما بالنسبة للتعقيد المساحي (Space Complexity)، فسيكون O(n) في أسوأ الحالات لأننا قد نخزن كل عناصر المصفوفة في الـ Hash Map.”
الخطوة الرابعة: كتابة الكود مع الشرح
الآن فقط، بعد أن شرحت خطتك بالكامل وحصلت على موافقة ضمنية من المحاوِر، تبدأ بكتابة الكود. وأثناء الكتابة، استمر في الشرح.
“الآن سأكتب الكود باستخدام JavaScript. أولاً، سأقوم بتعريف `Map` لتخزين الأرقام التي رأيتها ومؤشراتها.”
function twoSum(nums, target) {
// سأقوم بتعريف الـ Map لتخزين الأرقام ومؤشراتها
const numMap = new Map();
// الآن سأمر على المصفوفة باستخدام حلقة for
for (let i = 0; i < nums.length; i++) {
const currentNum = nums[i];
// سأحسب الرقم المكمّل الذي أبحث عنه
const complement = target - currentNum;
// الآن، سأتحقق مما إذا كان المكمّل موجودًا في الـ Map
if (numMap.has(complement)) {
// إذا كان موجودًا، فقد وجدت الحل!
// سأرجع مؤشر المكمّل من الـ Map والمؤشر الحالي
return [numMap.get(complement), i];
}
// إذا لم أجد المكمّل، سأضيف الرقم الحالي ومؤشره إلى الـ Map
// للرجوع إليه في الدورات القادمة
numMap.set(currentNum, i);
}
// في حال لم أجد أي حل بعد انتهاء الحلقة
// سأرجع مصفوفة فارغة كما اتفقنا في البداية
return [];
}
الخطوة الخامسة: اختبار الكود
لا تتوقف بعد كتابة الكود. قم بتشغيله في عقلك على مثال.
“دعنا نختبر هذا الكود على المثال `nums = [2, 7, 11, 15]` و `target = 9`.
- `i = 0`, `currentNum = 2`, `complement = 7`. هل الـ Map تحتوي على 7؟ لا. إذًا، نضيف `{2: 0}` إلى الـ Map.
- `i = 1`, `currentNum = 7`, `complement = 2`. هل الـ Map تحتوي على 2؟ نعم! إذن نرجع `[numMap.get(2), 1]` والذي هو `[0, 1]`. وهو الحل الصحيح.”
بهذه الطريقة، أنت لم تقدم حلًا صحيحًا فحسب، بل أخذت المحاوِر في رحلة ممتعة ومنظمة داخل عقلك.
نصائح من خبرة أبو عمر
- تدرب على هذا الأسلوب وحدك: افتح أي منصة مسائل برمجية، وشغل مسجل الصوت في جوالك، وحل المسألة وأنت تتحدث بصوت عالٍ. ثم استمع للتسجيل. هل كنت واضحًا؟ هل شرحت خطواتك بشكل منطقي؟
- الممارسة مع صديق: أفضل تمرين هو المقابلات الوهمية (Mock Interviews). اتفق مع صديق أو زميل لك، وقوموا بمقابلة بعضكم البعض. هذا يكسر حاجز الخوف ويجعل الأمر طبيعيًا.
- لا تخف من الخطأ: من الطبيعي أن تسلك طريقًا خاطئًا في البداية. الأجمل هو أن تقول: “انتظر، هذا النهج سيواجه مشكلة في الحالة الفلانية. دعني أعيد التفكير…”. إظهار قدرتك على تصحيح مسارك هو مهارة قوية جدًا. المهم مش بس الحل الصح، المهم كيف وصلتله.
- تحكم في وتيرتك: لا داعي للسرعة. إذا احتجت لحظة للتفكير، قل ببساطة: “دعني أفكر في هذا لثوانٍ”. صمت قصير ومُعلَن أفضل بكثير من صمت طويل ومُربِك.
- اجعلها محادثة: انظر للمحاوِر كزميل محتمل. اسأله: “هل يبدو هذا النهج معقولًا بالنسبة لك؟” أو “هل لديك أي تفضيل بين استخدام `Map` أو `Object` هنا؟”. هذا يحول المقابلة من استجواب إلى جلسة عمل مشتركة.
الخلاصة: المقابلة ليست اختبارًا، بل حوار 💬
يا أصدقائي، في نهاية اليوم، تذكروا أن الشركات لا توظف “كودًا”، بل توظف “أشخاصًا”. الكود يمكن تعلمه وتحسينه، لكن مهارات التواصل وحل المشاكل والتفكير المنهجي هي التي تميز المهندس الرائع عن المهندس الجيد.
أسلوب “التفكير بصوت عالٍ” هو الجسر الذي ينقل تميزك التقني من عقلك الصامت إلى عقل المحاوِر المترقب. إنه يحول المقابلة من اختبار مخيف إلى فرصة لإظهار من أنت حقًا: مهندس ذكي، ومتواصل، وممتع العمل معه.
لا تدع الصمت يكون سبب رفضك القادم. تدرب، تحدث، تحاور، وأظهر لهم العقل الرائع الذي يقف خلف ذلك الكود. بالتوفيق يا أبطال!