تصحيح الأخطاء مقابل تأكيدهااستثناءات محددة

StackOverflow https://stackoverflow.com/questions/61219

  •  09-06-2019
  •  | 
  •  

سؤال

لقد بدأت للتو في قراءة "Debugging MS .Net 2.0 Applications" لجون روبينز، وقد أصابني الحيرة بسبب تبشيره بـ Debug.Assert(...).

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

Debug.Assert(i > 3, "i > 3", "This means I got a bad parameter");

الآن، شخصيًا، يبدو من الجنون بالنسبة لي أنه يحب إعادة صياغة اختباره دون تعليق "منطق العمل" الفعلي، ربما "i <= 3 يجب ألا يحدث أبدًا بسبب عملية تحويل عناصر flobittyjam".

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

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

Debug.Assert(i > 3, "i must be greater than 3 because of the flibbity widgit status");
if (i <= 3)
{
    throw new ArgumentOutOfRangeException("i", "i must be > 3 because... i=" + i.ToString());
}

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

double interestAmount = loan.GetInterest();
Debug.Assert(debugInterestDoubleCheck(loan) == interestAmount, "Mismatch on interest calc");

...لكنني لا أفهمها بالنسبة لاختبارات المعلمات التي تستحق التدقيق بالتأكيد (في كل من إصداري DEBUG وإصدار الإصدار)...أم لا.ماذا ينقصني؟

هل كانت مفيدة؟

المحلول

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

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

أتمنى أن يساعدك هذا!

نصائح أخرى

هناك جانب اتصال للتأكيدات مقابل رمي الاستثناءات.

لنفترض أن لدينا فئة مستخدم مع خاصية الاسم وطريقة ToString.

إذا تم تنفيذ ToString مثل هذا:

public string ToString()
{
     Debug.Assert(Name != null);
     return Name;
}

تقول أن الاسم يجب ألا يكون فارغًا أبدًا وأن هناك خطأ في فئة المستخدم إذا كان كذلك.

إذا تم تنفيذ ToString مثل هذا:

public string ToString()
{
     if ( Name == null )
     {
          throw new InvalidOperationException("Name is null");
     }

     return Name;
}

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

التنفيذ مع كليهما

public string ToString()
{
     Debug.Assert(Name != null);
     if ( Name == null )
     {
          throw new InvalidOperationException("Name is null");
     }

     return Name;
}

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

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

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

القواعد الأساسية الجيدة التي وصلت إليها:

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

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

  3. إذا تعثر التأكيد (إما في اختبار الوحدة أو أثناء الاختبار)، فسيتم التنصت على الفصل.

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

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

أستخدم عمليات فحص صريحة تؤدي إلى استثناءات عام و محمي الأساليب والتأكيدات على الأساليب الخاصة.

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

يمكن اكتشاف الاستثناء وابتلاعه مما يجعل الخطأ غير مرئي للاختبار.لا يمكن أن يحدث ذلك مع Debug.Assert.

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

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

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

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

مثال على الاستخدام الجيد للتأكيد:

Debug.Assert(flibbles.count() < 1000000, "too many flibbles"); // indicate something is awry
log.warning("flibble count reached " + flibbles.count()); // log in production as early warning

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

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

راجع. http://c2.com/cgi/wiki?FailFastتم نسخها وتعديلها من سؤال جافا: الاستثناء مقابل التأكيد

هنا بنسبة 2 سنتا.

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

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

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

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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top