اصطياد الاستثناءات كما هو متوقع التحكم في تدفق تنفيذ البرنامج؟

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

سؤال

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

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

طلب مني قائد هذا المشروع تغييره لالتقاط SqlException برمز 547 (قيد المفتاح الخارجي) والتعامل معه بهذه الطريقة.

انا كنت...
مقاومة.

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

على مستوى ما لا يزال يشعر خطأ بالنسبة لي بالرغم من ذلك.

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

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

المحلول

رائع،

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

الإجابة المختصرة هي "نعم"، لكن الأمر يعتمد على ذلك.

  • لدينا بعض التطبيقات حيث لدينا الكثير من منطق الأعمال المرتبط باستعلامات SQL (وليس تصميمي Gov!).إذا كانت هذه هي الطريقة التي يتم بها تنظيم الأمر، فقد يكون من الصعب إقناع الإدارة بخلاف ذلك لأنها "تعمل بالفعل".
  • في هذه الحالة، هل يشكل الأمر أهمية كبيرة حقًا؟لأنها لا تزال رحلة واحدة عبر السلك والعودة.هل يفعل الخادم الكثير قبل أن يدرك أنه لا يمكنه الاستمرار (على سبيل المثال، إذا كان هناك سلسلة من المعاملات التي تتم أثناء إجراءك، فهل يسقط بعد ذلك في منتصف الطريق، مما يؤدي إلى إضاعة الوقت؟).
  • هل يعقل إجراء فحص في واجهة المستخدم أولاً؟هل يساعد في طلبك؟إذا كان يوفر تجربة مستخدم أجمل؟(أي.لقد رأيت حالات تمر فيها بعدة خطوات في المعالج، ويبدأ ثم ينهار، عندما يكون لديه كل المعلومات التي يحتاجها للسقوط بعد الخطوة 1).
  • هل التزامن مشكلة؟هل من الممكن إزالة/تحرير السجل أو أي شيء آخر قبل تنفيذ التزامك (كما في النسخة الكلاسيكية File.Exists صوت استهجان).

في رأيي:

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

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

نصائح أخرى

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

في هذه الحالة، سيستمر فحص المفتاح الخارجي، والاستثناءات هي الآلية التي يمكن من خلالها إعلامك.

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

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

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

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

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

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

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

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

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

لا أحب رؤية الاستثناءات في كل مكان في البرنامج، لكن في هذه الحالة سأستخدم آلية الاستثناء.

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

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

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

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

سنتى،

إيف

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