كتابة التعليمات البرمجية التي يسهل إزالتها وتصحيحها



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

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

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

القاعدة 0: يحتوي كود جيد على أخطاء واضحة.


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

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

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

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

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

القاعدة 1: هناك دائمًا مشاكل في الكمبيوتر


يعاني الكمبيوتر من مشكلات وتعطل البرنامج أثناء التشغيل الأخير.

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

على سبيل المثال ، عند قراءة أو كتابة حالة إلى ملف ، قد تحدث المشاكل التالية:

  • الملف مفقود.
  • الملف تالف.
  • ملف نسخة قديمة أو أحدث.
  • لم يكتمل التغيير الأخير للملف.
  • نظام الملفات يكذب عليك.

هذه المشاكل ليست جديدة ؛ فقد واجهتها قواعد البيانات منذ العصور القديمة (1970-01-01). سيساعد استخدام شيء مثل SQLite على التعامل مع العديد من المشاكل المماثلة ، ولكن إذا تعطل البرنامج في التنفيذ الأخير ، فقد يعمل الكود مع بيانات خاطئة و / أو بطريقة خاطئة.

على سبيل المثال ، مع البرامج المجدولة ، سيحدث شيء من هذه القائمة:

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

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

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

الرمز الذي يسهل تصحيحه هو:

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

القاعدة 2: يحارب برنامجك مع نفسه


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

ينطبق هذا على جميع أنظمتنا.

أستريد أتكينسون ، مهندس لعبة طويلة

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

يمكن أن تسبب صعوبة كبيرة حتى فحص النظام.

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

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

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

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

القاعدة 3: إذا تركت شيئًا غامضًا الآن ، فسيتعين عليك تصحيحه لاحقًا


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

هذا يعني أيضًا أنك بحاجة إلى تجنب المشكلة شبه الأصلية بعناية ، ولا تستخدم أبدًا قيمة واحدة ( count ) لتمثيل زوج من القيم ( boolean ، count ). من الضروري تجنب إرجاع رقم موجب للنتيجة وفي نفس الوقت إرجاع -1 إذا لم يتطابق أي شيء. الحقيقة هي أنه يمكنك بسهولة العثور على نفسك في موقف تحتاج فيه إلى شيء مثل " 0, but true " (وهذا بالضبط ما هي الميزة في Perl 5) ؛ أو عند إنشاء رمز يصعب دمجه مع أجزاء أخرى من النظام (قد لا يكون -1 للجزء التالي من البرنامج خطأ ، ولكن قيمة إدخال صالحة).

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

عندما لا تمر الحالة من الأعلى إلى الأسفل ، أي في حالة الدورة العرضية ، من الأفضل تزويد الدولة بمتغيرها الخاص ومسح المنطق. إذا كان لديك مجموعة من القيم المنطقية داخل الكائن ، فاستبدلها بمتغير يسمى state واستخدم التعداد (أو سلسلة إذا لزم الأمر في مكان ما). if التعبيرات ستبدو مثل if state == name ، وليس if bad_name && !alternate_option .

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

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

القاعدة 4: السلوك العشوائي هو السلوك المتوقع.


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

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

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

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

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

لكن أي محاولة للتغلب على UUID ستفشل: لقد حاولنا بالفعل استخدام الرموز البريدية وأرقام الهواتف وعناوين IP ، وفي كل مرة نفشل فيها بشكل بائس. قد لا تجعل UUID رمزك أسهل في التصحيح ، ولكن السلوك الأقل العشوائي يعني مشكلة أقل.

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

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

القاعدة 5: التصحيح هو مهمة اجتماعية ، أولاً وقبل كل شيء ، مهمة تقنية.


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

يمكن إصلاح ذلك من خلال التخطيط والأدوات والعمليات والتوثيق.

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

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

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

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

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

من السهل شرح التعليمات البرمجية بسهولة.


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

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

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

تبين أن هذا لم يكن خطأ مترجم.

Source: https://habr.com/ru/post/ar412693/


All Articles