كيف تقيّم مستوى المبرمج عبر أحجية واحدة فقط: فزبز FizzBuzz

14  تعليق

شاء الله أن أُجريَ عدداً من المقابلات التقنيّة لبعض المتقدمين للوظائف، عادةً ما أنهي المقابلة بسؤال ثابت “كم تحتاج من الوقت لتُنهي قراءة كتابٍ تقني مكون من مئتي صفحة؟

سأخبرك عن سبب هذا السؤال لاحقاً..

لا أدري عن الآخرين، ولكن أعلمُ تماماً أن إجراء المقابلات مسؤليةٌ كبيرة يجبُ فيها قبل كُل شيء استحضارُ العدل بين المتقدمين، وأن يكونَ التقييمُ عادلاً بين الجميع.

ولكن الحقيقة أن معرفة وسبر أغوار الناس لا يمكن أن يتم خلال دقائق معدودة، ولا حتى ساعات! وهنا تكونُ مسؤليّتُك أنت!

على المتقدم أن يكون مستعداً جيداً للمقابلة، نعم. ولكن يجبُ عليك أنت كمُقيّم أن تكونَ مستعداً أكثرَ منه!

حقيقة: المقابلة الوظيفية للمبرمجين بها كثيرٌ من الظلم

قد يكونُ أحدُ المتقدمين للوظائفِ متحدثٌ حصيف ومُقنعٌ يبيعك الطير في الهواء والسمك في البحر ولكنه بلا قدرات تقنية، بينما أحدٌ آخر عبقري عملي ولكنه ضعيفُ الحديث، وآخرون مختلفون.

فيجبُ على المقيّم أن يبذل جهده كي يختار الأنسب ويحاول أن يصل لحقيقة المتقدم ويقيمه كما يجب، ولكن…

ما هي الأدوات المساعدة على سبر أغوار الناس خلال هذه الدقائق القليلة؟!!

خلال قرائتي لبعض المواضيع البرمجية مررتُ على مشكلة برمجية تُسمى فزبز FizzBuzz.

في الأصل هذه المشكلة هي لعبة من الممكن أن يلعبها الأطفال بعد حفظ جداول الضرب التي لا يحبونها 🙂

فكرةُ لعبة فزبز FizzBuzz كالآتي:

  1. نفترض أن اللُّعبة تلعب من قبل شخصين.
  2. كل شخص يذكر رقماً إبتداءً من الرقم واحد 1، 2، 3، 4، …إلخ.
  3. إذا كان الرقم من مضاعفات الرقم 3 يقول اللاعب فز Fizz بدلاً عن الرقم.
  4. إذا كان الرقم من مضاعفات الرقم 5 يقول اللاعب بز Buzz بدلاً عن الرقم.
  5. إذا كان الرقم من مضاعفات الرقمين 3 و 5 في نفس الوقت يقول اللاعب فزبز FizzBuzz.

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

ولكن…

لن تتخيل أن الطريقة التي يبرمجُ بها المبرمج هذه اللعبة من الممكن أن تكون سبباً مقنعاً جداً لاختياره أو رفضه! وعبرها تستطيع تحديد أيضاً تحديد مستواه البرمجي!

هيا فلنبرمج هذه اللعبة ونرى أنواع المبرمجين…


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

المبرمج المبتدئ: المرحلة الأولى

بمجرّد سماع المشكلة ومحاولة تحويل المشكلة إلى منطق برمجي تكون النتيجة كما يلي

        for(int i = 1; i < 100; i++)
        {
            if( i % 3 == 0){
                System.out.println("Fizz");
            }
            
            if( i % 5 == 0){
                System.out.println("Buzz");
            }
            
            if( i % 3 != 0 && i % 5 != 0 ){
                System.out.println(i);
            }
        }

في الحقيقة هذا نوع مميز جداً من المبرمجين، وهو المبرمج المبتدئ.

برغم أن المنطق صحيح تماماً ولكن توجد مشكلةٌ في تنفيذ هذه الشفرة المصدرية!

تنفيذ المحاولة الأولى - فزبز fizzbuzz
تنفيذ المحاولة الأولى

فوفقاً للقاعدة الخامسة المذكورة أعلاه في فكرة اللعبة يجب طباعة FizzBuzz وليس Fizz في سطر و Buzz في سطر!

نتيجة تنفيذ المحاولة الأولى
نتيجة تنفيذ المحاولة الأولى

جميل!

المبرمج المبتدئ: المرحلة الثانية

بعد أن نخبر المبرمج المبتدئ بهذا الخطأ سيبدأ في اصلاحه فوراً بطباعة جملة جديدة كاملة لـ FizzBuzz و تعديل الشفرة البرمجية كما يلي

        for(int i = 1; i < 100; i++)
        {
            if( (i % 3 == 0) && (i % 5 != 0) ){
                System.out.println("Fizz");
            }
            
            if( (i % 5 == 0) && (i % 5 != 0)){
                System.out.println("Buzz");
            }
            
            if( (i % 3 == 0) && (i % 5 == 0)){
                System.out.println("FizzBuzz");
            }
            
            if( (i % 3 != 0) && (i % 5 != 0) ){
                System.out.println(i);
            }
        }

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

لماذا؟!

انظر إلى عدد المقارنات في الهذه الشفرة المصدرية

عدد المقارنات في الشفرة المصدرية للمبتدئ
عدد المقارنات في الشفرة المصدرية للمبتدئ

المبرمج المتقدّم: المرحلة الأولى

كان بالإمكان تقليل عدد المقارنات إل حد كبير “نسبياً” بإستخدام عبارة else بعد إعادة ترتيب المقارنات منطقياً، فتصبح الشفرة المصدرية  كما ترى

        for(int i = 1; i < 100; i++)
        {
            if( (i % 3 == 0) && (i % 5 == 0)){
                System.out.println("FizzBuzz");
            }
            else if( i % 3 == 0 ){
                System.out.println("Fizz");
            }
            
            else if( i % 5 == 0 ){
                System.out.println("Buzz");
            }
            
            else {
                System.out.println(i);
            }
        }

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

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

  • إذا كان الرقم من مضاعفات 4 اطبع Guzz.
  • إذا كان الرقم من مضاعفات 4 و 3 إطبع FizzGuzz.
  • إذا كان الرقم من مضاعفات 4 و 5 إطبع BuzzGuzz.
  • إذا كان الرقم من مضاعفات 3 و 5 و 4 اطبع FizzBuzzGuzz.

وفقاً للشفرة المصدرية السابقة ستصبح الشفرة المصدرية أكثر تعقيداً و ضعيفة المقروئية.

المبرمج المتقدّم: المرحلة الثانية

هنا يوجد نوعٌ آخر من المبرمجين الذين يكتبون شفراتهم المصدرية بالطريقة التالية

        for(int i = 1; i < 100; i++)
        {
           String print = "";
           if( i % 3 == 0){
               print += "Fizz";
           }
           if( i % 5 == 0){
               print += "Buzz";
           }
           if( i % 4 == 0){
               print += "Guzz";
           }
           
           if( print.equals("") ){
               print = String.valueOf(i);
           }
           
            System.out.println(print);
        }

هنا عرّف المبرمج متغيراً نصياً في البداية وطبعهُ في النهاية، ما بين البداية والنهاية أجرى عملياتٍ تحدد محتوى النص الذي سيُطبع.

بهذه الطريقة أصبحت الشفرة المصدرية أكثرْ رُقياً وتحضراً، كما غدا توسيعُ الحل كُلّما توسّعت المشكلة أسهل.

ولكن يا صديقي..

ما زال هناك نوعٌ آخر من المبرمجين، يستطيعُ أن يفعل المزيد بهذه الشفرة البرمجية.

لاحظ إلى هذه الأجزاء:

أجزاء متشابهة من الشفرة البرمجية
أجزاء متشابهة من الشفرة البرمجية

المبرمج المتقدم: المرحلة الثالثة

هنا يأتي آخرُ نوعٍ من المبرمجين من المبرمجين المتقدمين. وهو الذي يفكر في أخذ جميع الأجزاء المتشابهة ووضعها في دالة منفصلة

    public static void main(String args[]){
        for(int i = 1; i < 100; i++)
        {
           String print = "";
           print += problemLogic(i,3,"Fizz");
           print += problemLogic(i,5,"Buzz");
           print += problemLogic(i,4,"Guzz");
           
           if( print.equals("") ){
               print = String.valueOf(i);
           }
           
            System.out.println(print);
        }
    }
    
    static String problemLogic(int i,int number, String text){
        if( i % number == 0){
               return text;
        }else{
            return "";
        }
    }

وما زال بالإمكان تحسين الشفرة المصدرية أكثر!

خاتمة

ألم ترَ كيف أن هذه المشكلة البرمجية البسيطة بإمكانها أن تفرق بين المبرمجين ومستوياتهم!

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

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

عندما كُنت أسأل المتقدمين عن الوقتِ اللازم لقراءة كتاب من 200 صفحة كنت أرغب في معرفة رغبتهم في التعلم التقني، وكانت الإجابات مساعدةً جداً لفتح بابٍ لمناقشة هذا الأمر!

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


قد يعجبك أيضا

100+ شهادة تقنية لإحتراف 8 تخصصات: أمن المعلومات، الشبكات، الإدارة، البرمجة…إلخ

100+ شهادة تقنية لإحتراف 8 تخصصات: أمن المعلومات، الشبكات، الإدارة، البرمجة…إلخ

هل تستطيع تعلم البرمجة أو علوم الحاسب بعد أن تبلغ من العمر **** عاماً؟

هل تستطيع تعلم البرمجة أو علوم الحاسب بعد أن تبلغ من العمر **** عاماً؟
ما رأيك؟ اترك تعليقاً أدناه


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

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

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

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

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

    1. وعليكم السلام ورحمة الله أخي عزت ومرحباً بك دوماً.
      أتمنى أنّك بخير كذلك ويسعدني تواجدك هنا. دُمت بود أخي

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

{"email":"البريد الالكتروني غير صحيح","url":"رابط الموقع غير صحيح","required":"بعض الحقول المطلوبة لم تتم تعبئتها"}

نجاح!

تنبيه!

خطأ!