الكود النظيف وفن التعامل مع الاستثناءات

نشرت: 2022-03-11

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

ظروف شاذة أو استثنائية تتطلب معالجة خاصة - غالبًا ما تغير التدفق الطبيعي لتنفيذ البرنامج ...

وأن التعامل معها يتطلب:

تراكيب لغة البرمجة المتخصصة أو آليات أجهزة الكمبيوتر.

لذلك ، تتطلب الاستثناءات معاملة خاصة ، وقد يتسبب الاستثناء غير المعالج في حدوث سلوك غير متوقع. النتائج غالبا ما تكون مذهلة. في عام 1996 ، نُسب فشل إطلاق صاروخ آريان 5 الشهير إلى استثناء تجاوز السعة غير المعالج. يحتوي برنامج History's Worst Software Bugs على بعض الأخطاء الأخرى التي يمكن أن تُعزى إلى الاستثناءات التي لم تتم معالجتها أو تم التعامل معها بشكل خاطئ.

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

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

التعامل مع الاستثناءات: إنه أمر جيد

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

 begin do_something_that_might_not_work! rescue SpecificError => e do_some_specific_error_clean_up retry if some_condition_met? ensure this_will_always_be_executed end

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

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

فيما يلي بعض الممارسات الموصى بها التي ستساعدك على تبني الاستثناءات والاستفادة منها وقدراتها للحفاظ على شفرتك قابلة للصيانة والتوسيع والقراءة :

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

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

"WTFs / m" بواسطة Thom Holwerda، OSNews

مع ذلك ، دعنا نتعمق في هذه الممارسات ونرى كيف يؤثر كل منها على تلك المقاييس الثلاثة.

ملاحظة: سنقدم أمثلة من Ruby ، ​​لكن جميع التركيبات الموضحة هنا لها مكافئات في لغات OOP الأكثر شيوعًا.

قم دائمًا بإنشاء التسلسل الهرمي الخاص بأخطاء ApplicationError

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

 class ApplicationError < StandardError; end # Validation Errors class ValidationError < ApplicationError; end class RequiredFieldError < ValidationError; end class UniqueFieldError < ValidationError; end # HTTP 4XX Response Errors class ResponseError < ApplicationError; end class BadRequestError < ResponseError; end class UnauthorizedError < ResponseError; end # ... 

مثال على التسلسل الهرمي لاستثناء التطبيق: StandardError في الأعلى. ApplicationError يرث منه. ValidationError و ResponseError كلاهما يرثان من ذلك. يرث RequiredFieldError و UniqueFieldError من ValidationError ، بينما يرث BadRequestError و UnauthorizedError من ResponseError.

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

من منظور المقروئية ، من الأسهل بكثير قراءة:

 rescue ValidationError => e

من أن تقرأ:

 rescue RequiredFieldError, UniqueFieldError, ... => e

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

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

 # app/controller/pseudo_controller.rb def authenticate_user! fail AuthenticationError if token_invalid? || token_expired? User.find_by(authentication_token: token) rescue AuthenticationError => e report_suspicious_activity if token_invalid? raise e end def show authenticate_user! show_private_stuff!(params[:id]) rescue ClientError => e render_error(e) end

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

شيئين يجب ملاحظتهما هنا:

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

لا rescue Exception أبدًا

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

 # main.rb def bad_example i_might_raise_exception! rescue Exception nah_i_will_always_be_here_for_you end # elsewhere.rb def i_might_raise_exception! retrun do_a_lot_of_work! end

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

لا rescue أبدًا استثناءات أكثر مما تحتاج إليه

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

إذا حاولنا التعامل مع أنواع فرعية مختلفة من الاستثناءات في نفس المعالج ، فإننا نقدم كتل التعليمات البرمجية الدهنية التي لها العديد من المسؤوليات. على سبيل المثال ، إذا كنا نبني مكتبة تستهلك واجهة برمجة تطبيقات بعيدة ، فإن التعامل مع MethodNotAllowedError (HTTP 405) ، يختلف عادةً عن معالجة UnauthorizedError (HTTP 401) ، على الرغم من أنهما كلاهما ResponseError s.

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

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

 def get_info begin response = HTTP.get(STOCKS_URL + "#{@symbol}/info") fail AuthenticationError if response.code == 401 fail StockNotFoundError, @symbol if response.code == 404 return JSON.parse response.body rescue JSON::ParserError retry end end

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

قاوم الرغبة في التعامل مع الاستثناءات على الفور

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

أحد الأنماط الشائعة التي نراها في تطبيقات ريلز (خاصة تلك التي تكشف عن واجهات برمجة تطبيقات JSON فقط) هي طريقة التحكم التالية:

 # app/controllers/client_controller.rb def create @client = Client.new(params[:client]) if @client.save render json: @client else render json: @client.errors end end

(لاحظ أنه على الرغم من أن هذا ليس معالج استثناء تقنيًا ، إلا أنه من الناحية الوظيفية يخدم نفس الغرض ، نظرًا لأن @client.save لا يُرجع القيمة false إلا عندما يواجه استثناءً.)

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

 # app/controllers/client_controller.rb def create @client = Client.create!(params[:client]) render json: @client end
 # app/controller/application_controller.rb rescue_from ActiveRecord::RecordInvalid, with: :render_unprocessable_entity def render_unprocessable_entity(e) render \ json: { errors: e.record.errors }, status: 422 end

بهذه الطريقة ، يمكننا التأكد من أن جميع أخطاء ActiveRecord::RecordInvalid يتم معالجتها بشكل صحيح ومعالجتها DRY-ly في مكان واحد ، على مستوى ApplicationController الأساسي. يمنحنا هذا حرية العبث بها إذا أردنا التعامل مع حالات معينة على المستوى الأدنى ، أو ببساطة نسمح لها بالانتشار بأمان.

ليست كل الاستثناءات تحتاج إلى معالجة

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

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

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

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

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

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

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

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

اتبع الاتفاقية

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

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

هناك اصطلاح آخر من روبي ، منسوب إلى Jim Weirich ، وهو استخدام fail للإشارة إلى فشل الطريقة ، واستخدام raise فقط إذا كنت تعيد رفع الاستثناء.

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

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

Logger.log (كل شيء)

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

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

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

تلك الثقة رمز نظيف

معالجة الاستثناءات النظيفة سترسل جودة الكود إلى القمر!
سقسقة

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

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

لقد رأينا أنه من السيئ "الإمساك بهم جميعًا" ، وأنه لا بأس من السماح لهم بالطفو والظهور.

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

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

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

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

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

الموضوعات ذات الصلة: نصائح وأفضل الممارسات لمطوري Ruby