سؤال

على Go لغة المبدعين الكتابة:

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

ما هو رأيك في هذا ؟

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

المحلول

لا، لا يوجد شيء خاطئ assert طالما كنت تستخدمه كما هو المقصود.

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

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

نصائح أخرى

لا لا goto ولا assert هي الشر. ولكن كلاهما يمكن إساءة استخدامه.

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

من خلال هذا المنطق، فإن نقاط التوقف شريرة أيضا.

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

تأكيد موجودة لمساعدتك، مبرمج، والكشف عن المشكلات التي يجب ألا تكون موجودة وتحقق من أن افتراضاتك تظل صحيحة.

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

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

بسبب التأكيدات، أقضي الكثير من برامج تصحيح / تصحيح الوقت أقل.

لقد لاحظت أيضا أن التأكيد ساعدني في التفكير في أشياء كثيرة يمكن أن كسر برامجي.

يجب استخدامها للكشف عن الأخطاء في البرنامج. ليس إدخال المستخدم السيئ.

إذا استخدمت بشكل صحيح، فهي ليس شرير.

كمعلومات إضافية، يوفر GO وظيفة مدمجة panic. وبعد هذا يمكن استخدامه بدلا من assert. وبعد على سبيل المثال

if x < 0 {
    panic("x is less than 0");
}

panic سوف تطبع تتبع المكدس، لذلك بطريقة ما لديها الغرض من assert.

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

build-sorted-list-from-user-input(input)

    throw-exception-if-bad-input(input)

    ...

    //build list using algorithm that you expect to give a sorted list

    ...

    assert(is-sorted(list))

end

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

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

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

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

هناك أيضا مشكلة أخرى مع التأكيدات. يتم فحص التأكيدات فقط في وقت التشغيل. ولكن غالبا ما يكون الأمر هو الحال الذي ترغب في تنفيذه في Compile-Time. من الأفضل اكتشاف مشكلة في تجميع الوقت. بالنسبة للمبرمجين C ++، يوفر Boost Boost_static_assert الذي يسمح لك بذلك. ل C مبربرين، هذه المقالة ( رابط النص ) يصف تقنية يمكن استخدامها لأداء التأكيدات في وقت الترجمة.

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

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

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

أفضل تجنب التعليمات البرمجية التي تقوم بأشياء مختلفة في تصحيح الأخطاء والإفراج.

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

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

assert(2 == ShroedingersCat.GetNumEars()); سيجعل البرنامج يفعل أشياء مختلفة في التصحيح والإفراج.

لقد طورنا مجموعة من وحدات الماكرو التأكيد التي من شأنها أن ترمي استثناءا، وتفعل ذلك في كل من تصحيح الأخطاء والإصدار. على سبيل المثال، THROW_UNLESS_EQ(a, 20); سوف رمي استثناء مع رسالة () التي تحتوي على كل من الملف، والسطر و القيم الفعلية من، وهلم جرا. فقط ماكرو سيكون للطاقة لهذا. قد يتم تكوين المصحح لكسر "رمي" من نوع الاستثناء المحدد.

أنا أكره التأكيد بشكل مكثف. لن أذهب بقدر ما أنهم شرور.

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

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

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

إجابة قصيرة: لا، أعتقد أن التأكيدات يمكن أن تكون مفيدة

لقد بدأت مؤخرا في إضافة بعض التأكيدات إلى التعليمات البرمجية الخاصة بي، وهذه هي الطريقة التي كنت أفعلها:

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

الرمز الداخلي هو كل شيء آخر. على سبيل المثال، قد يتم تعريف الوظيفة التي تحدد متغير في صفي

void Class::f (int value) {
    assert (value < end);
    member = value;
}

ويمكن قراءة الوظيفة التي تحصل على إدخال من الشبكة على هذا النحو:

void Class::g (InMessage & msg) {
    int const value = msg.read_int();
    if (value >= end)
        throw InvalidServerData();
    f (value);
}

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

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

assert مفيد جدا ويمكن أن يوفر لك الكثير من التراجع عند حدوث أخطاء غير متوقعة عن طريق وقف البرنامج في أول علامات للمشاكل.

من ناحية أخرى، من السهل جدا سوء المعاملة assert.

int quotient(int a, int b){
    assert(b != 0);
    return a / b;
}

سيكون النسخة الصحيحة الصحيحة شيئا مثل:

bool quotient(int a, int b, int &result){
    if(b == 0)
        return false;

    result = a / b;
    return true;
}

لذلك ... على المدى الطويل ... في الصورة الكبيرة ... يجب أن أتفق على ذلك assert يمكن أن تعصب. أفعل ذلك طوال الوقت.

assert يتم إساءة استخدامه للعاملين في الأخطاء لأنه أقل كتابة.

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

شعرت أن ركل المؤلف في الرأس عندما رأيت ذلك.

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

كما تمزج الاستثناءات مع رمز الإنتاج بسهولة أكبر. أكاذي أسهل لاحظ throw new Exception("Some generic msg or 'pretend i am an assert'");

مشكلتي مع هذه الإجابات الدفاع عن تأكيد لا تحدد بوضوح ما يجعلها مختلفة عن العادية خطأ فادح, و لماذا تأكيد لا يمكن أن تكون مجموعة فرعية من استثناء.الآن مع هذا قلت ما إذا كان الاستثناء أبدا اشتعلت ؟ لا تجعل من تأكيد التسميات?و لماذا تريد أن تفرض قيود في اللغة التي استثناء يمكن رفع هذا /لا شيء/ يمكن التعامل معها ؟

نعم، تؤكد شريرة.

غالبا ما يتم استخدامها في الأماكن التي يجب أن تستخدم فيها معالجة الأخطاء الصحيحة. تعتاد على كتابة خطأ في جودة الإنتاج المناسبة معالجة من البداية!

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

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

في بعض الأحيان انهم عكازات للتصاميم المكسورة خلاف ذلك؛ أي أن تصميم الكود يسمح للمستخدم بالاتصال به بطريقة لا ينبغي استدعاءها وتأكيد "يمنع" هذا. إصلاح التصميم!

كتبت عن هذا أكثر على مدونتي مرة أخرى في عام 2005 هنا: http://www.lenholgate.com/blog/2005/09/assert-is-es-evil.html.

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

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

بعض البدائل للتأكيد:

  • باستخدام مصحح،
  • وحدة التحكم / قاعدة البيانات / قطع الأشجار الأخرى
  • استثناءات
  • أنواع أخرى من التعامل مع الأخطاء

بعض المراجع:

حتى الأشخاص الذين يدافعون عن تأكيدهم يعتقدون أنهم يجب استخدامهم فقط في التنمية و ليس في الانتاج:

يقول هذا الشخص أن التأكيد يجب استخدامها عندما تكون الوحدة النمطية تالفة البيانات التي تستمر بعد إلقاء استثناء: http://www.advogato.org/article/949.html. وبعد هذه بالتأكيد نقطة معقولة، ومع ذلك، يجب أن وحدة خارجية مطلقا يصف مدى أهمية البيانات التالفة على برنامج الاتصال (عن طريق الخروج "ل" لهم). الطريقة الصحيحة للتعامل مع هذا هي رمي استثناء يجعل من الواضح أن البرنامج قد يكون الآن في حالة غير متناسقة. وبما أن البرامج الجيدة تتكون في الغالب من الوحدات النمطية (مع رمز الغراء القليل في التنفيذ الرئيسي)، فإن التأكيدات هي دائما ما يكون الشيء الخطأ الذي يجب القيام به تقريبا.

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

أنا لا أستخدم أي تأكيد ()، وأمثلة عادة ما تظهر شيئا مثل هذا:

int* ptr = new int[10];
assert(ptr);

هذا سيء، لا أفعل هذا أبدا، ماذا لو كانت لعبتي مجموعة من الوحوش؟ لماذا يجب أن تحطم اللعبة، بدلا من ذلك يجب عليك التعامل مع الأخطاء بأمان، لذلك تفعل شيئا مثل:

CMonster* ptrMonsters = new CMonster[10];
if(ptrMonsters == NULL) // or u could just write if(!ptrMonsters)
{
    // we failed allocating monsters. log the error e.g. "Failed spawning 10 monsters".
}
else
{
    // initialize monsters.
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top