• בלוג
  • אל תבלעו Exceptions. זה לא טעים.

אל תבלעו Exceptions. זה לא טעים.

התקנתי Capybara לפני כמה ימים (או יותר נכון ניסיתי להתקין). כל פעם שהפעלתי את המערכת אחרי ההתקנה הופיעה ההודעה הבאה:

System test integration requires Rails >= 5.1 and has a hard dependency
on a webserver and `capybara`, please add capybara to
your Gemfile and configure a webserver
(e.g. `Capybara.server = :webrick`) before attempting to use system tests.

ההודעה נשמעת מאוד ספציפית עם הוראות מדויקות מה לעשות. רק שצריך לא מעט יצירתיות כדי לקשר בינה לבין הבעיה האמיתית שהיתה במערכת.

לפני שנגיע לזה בואו נלך לקוד של rspec-rails, הספריה ממנה הגיעה הודעת השגיאה. כך נראה הבלוק הבעייתי:

      included do |other|
        begin
          require 'capybara'
          require 'action_dispatch/system_test_case'
        # rubocop:disable Lint/HandleExceptions
        rescue LoadError
          # rubocop:enable Lint/HandleExceptions
          abort """
            System test integration requires Rails >= 5.1 and has a hard
            dependency on a webserver and `capybara`, please add capybara to
            your Gemfile and configure a webserver (e.g. `Capybara.server =
            :webrick`) before attempting to use system tests.
          """.gsub(/\s+/, ' ').strip
        end

רואים מה הם עשו כאן? מנסים להפעיל שתי שורות require ובמידה והתקבלה שגיאה פשוט עוצרים את התוכנית עם הודעת שגיאה גנרית. זה אולי משהו שנחמד להציג למשתמש קצה, אבל כשמדובר במפתח שמנסה להבין למה המערכת לא עולה כל פסיק בהודעת השגיאה המקורית יכול להיות המפתח לפיתרון.

יש שני מצבים בהם מפתחים משתמשים ב Exceptions: הראשון כדי לנסות לבצע קטע קוד מסוים ואז אם זה לא מצליח להמשיך בכיוון אחר. זו התנהגות מאוד אהובה על מתכנתי Python כמו שאפשר לראות בדוגמא הבאה למימוש defaultdict פשוט:

# from: https://www.python.org/download/releases/2.2.3/descrintro/
class defaultdict(dict):

    def __init__(self, default=None):
        dict.__init__(self)
        self.default = default

    def __getitem__(self, key):
        try:
            return dict.__getitem__(self, key)
        except KeyError:
            return self.default

במקרה כזה ברור שצריך לבלוע את הודעת השגיאה - זה חלק מהמנגנון.

אבל הקוד של rspec-rails לא משתמש ב Exception כדי להציע טיפול שונה ולהמשיך הלאה. שם השימוש במנגנון הוא באמת כדי לדווח שמשהו ממש רע קרה ואין לנו מושג איך להמשיך הלאה. במצבים כאלה חשוב לתת למפתחים שיקראו את ההודעה כמה שיותר מידע.

נ.ב. 1 - הודעות שגיאה מתקשרות הרבה פעמים עם סוגיות של אבטחת מידע. באבטחה של מערכת אנו מעדיפים לתת למשתמש הקצה כמה שפחות מידע על מה שקרה בשביל שלא יוכל להשתמש בזה נגדנו. נהוג לחלק את הקוד למצב ״פיתוח״ ומצב ״ייצור״. כך אפשר לתת מידע מפורט למפתחים במצב פיתוח ולבטל את הפירוט במעבר למצב ייצור.

נ.ב. 2 - אצלי Capybara לא עלה בגלל חוסר תאימות בין ריילס 5.1 ל Capybara 3. ברגע ששינמכתי ל Capybara 2 הכל התחיל לעבוד.

נ.ב. 3 - קפיברה (בנוסף להיותה המכרסם הגדול ביותר) היא ספריית בדיקות אוטומטיות ב Ruby.