Exceptions are NOT Evil

  • פותח הנושא REDMF
  • פורסם בתאריך

REDMF

New member
Exceptions are NOT Evil

כן כן הכותרת באה לעשות פרפרזה על Extends is Evil וGetters and Setter are evil - שני המאמרים המבריקים של אלן Holub.(ראו הפנייה בהודעה של ייוני על מאמרים) אז ככה, יש האומרים (וביניהם יווני) שExceptions are Evil או בלשון העם אל תשתמש בהם כלל. הטענה שלהם מתבססת על הגדרה אשר אומרת כאשר אנו פונה לאובייקט אשר מיישם Interface מסויים, הוא צריך לעבוד, ושלא יעשה לי הצגות. טענה זו נכונה ומעניינת, אבל בעיני סותרת רעיון בסיסי של AGILE. יסוד ההגדרה של AGILE - בעיני היא "אני לא יודע הכל, אני לא יודע מה יהיה, אני רק יודע מה אני צריך עכשיו, ומה היה קודם (ונבדק על ידי הUNIT TESTS). בעיני השימוש בExceptions מאפשר למתכנת לטפל במקרים שהוא חשב עליהם, ולהיות שקט שאם יגיע מקרה שהוא לא לקח בחשבון - המערכת לא תתנהג בצורה לא צפוייה אלא תודיע לו, כאן ועכשיו. דוגמא טובה לכך היא ממשקים, קריאה של XML וקבצים חיצוניים וכו... אני אדגים נגיד שאני מתממשק לWEBSRVICE אשר מחזיר לי איזה שהוא STATUS ID (כן ייוני אני יודע שאתה לא אוהב שזה מחזיר, אבל זו הדוגמא). לאותו סטטוס ID יש כרגע שני ערכים קבועים - 1 הצליח, 2 נכשל. הקוד שלי יהיה משהו כזה
public void UseWebService() { int result = WebService(); if (result ==1) DoSuccessStuff(); else DoFailStuff(); }​
עכשיו אותו WEBSERVICE החליט להוסיף סטטוס נוסף, 3 - שיהיה הצלחתי וחייבתי את הלקוח הקוד שלי לא יעבוד - אני אצתרך להתחיל לחפש לה הקוד מחזיר כשלון במקרים שהלקוח אומר לי שהיתה הצלחה, ואז אני צריך לרוץ, ואחרי זמן לא מבוטל לגלות שהספק הוסיף ערך קבוע נוסף (3). לעומת זאת אם הקוד היה כתוב כך:
public void UseWebService() { int result = WebService(); switch (result) { case "1": DoSuccessStuff(); break; case "2": DoFailStuff(); break; default: throw new Exception ("UnKnow result code = "+result.ToString()); } }​
הקוד הזה, יודיע לי מייד ברגע שהוא נתקל במקרה שלא ידעתי עליו, ולא חשבתי עליו על שגיאה. אשר אותה אוכל לתקן. מקרה נוסף שזה עוזר בו, זה כאשר אני מתממשק עם גורם שלא מתועד כמו שצריך. מה שעושים אז, זה מסתכלים על דוגמאות ונסים לפענח אותן. נגיד שהגעתי למסקנה ששדה A הוא סטטטוס -1 הוא הצלחה ו2 הוא כשלון, ולא נתקלתי במקרה של 3. מה שיקרא עם הקוד הראשון, כאשר יהיה מקרה של 3 הדרך היחידה שלי להבין את זה תהייה פענוח של התוצאות אשר גרמו לו להתנבהג כמו 2 - והיכולת שלי למצא את צומת ההחלטה הזו מהר. במקרה השני, ברגע שאני נתקל בערך לא מוכר - הקוד מודיע לי, היי מקרה לא מוכר (חריג) כלומר Exception אשמח לשמוע את דעתכם בנושא
 

ייוניי

New member
Exceptions should be unexpected

למעשה אני לא נגד שימוש ב Exceptions בכלל. אני אפילו משתמש בהם לא מעט - באופן ספציפי ב InvalidArgumentException בשלב היצירה של אובייקט חדש. החוקיות של הפרמטרים המועברים לאובייקט בשלב הקריטי הזה היא חשובה מאוד על מנת שלא נקבל מצב של אובייקט "לא חוקי" שהפעילות שלו בעתיד תהיה בלתי צפויה. ולעניין, הסיבה העיקרית שלא הייתי משתמש ב exceptions יותר מדי היא משום שיש לי בעיה לא עם החריגה אלא דווקא עם דרך הטיפול בה. קודם כל תסכים איתי שלהחליף בדיקות תקינות מוקדמות בתפישת חריגות מאוחרות זה גם פחות קריא ובוודאי מזיק לביצועים. שנית, העובדה שחריגה קופצת לה במעלה ה call stack מפריעה לי כי היא מטילה את האחריות לטיפול בשגיאה על אותו קוד שקרא למתודה וזה מגביל אותי. אני כבר מעדיף אוטומטית לשלוח אובייקט נוסף כפרמטר שמיישם "קרתה שגיאה" ולטפל בשגיאה שם... (זאת בהנחה שאכן צפויה להיות חריגה כמו במקרה שתארת).
 

REDMF

New member
אין וויכוח

אני בהחלט חושב שExceptions should be unexpected, כל מה שאמרת הוא נכון. מה שחשוב לי להדגיש, זה במקרים שיש דברים שאני לא צופה, לא לייצר איזה שהוא טיפול DEFAULT אלא עדיף לזרוק EXCEPTION ולהתמודד עם זה בהמשך הרי אם בכל מקום, לכל דבר נעביר אובייקט אשר מדברים איתו בקרתה שגיאה, אני מניח עם מלל וכו... אנחנו בונים פה את מנגנון הEXCEPTION שכבר יש לא? מה גם שזה מאד, אבל מאד יכביד על הפיתוח.
 

עידו פ

New member
לא כל כך הבנתי את הפסקה השלישית

אבל אני תמיד בעד exceptions, לפי ההגדרה הבאה: - עקרון ה"אם אין לך מה לעשות עם זה, אל תתפוס את זה" - אני רואה הרבה פעמים תוכניתנים שכותבים catch (Exception ex) ולא עושים עם זה כלום (חוץ מאולי throw) - אם אין לך מה לעשות עם זה, אל תתפוס את זה ! - עקרון ה"תעד בעיות, אך חסוך מה-client את הזבל" - משמע, בכל end-point אני אתפוס כל exception אפשרי ואתעד אותו (חובה!) ובמקומו, אני אחזיר משהו יותר "נוח לעין". הדבר תקף גם כאשר בונים web site ומונעים הצפת exceptions למשתמש וגם כאשר בונים web service שנחשף למערכות אחרות. את הטיפול עצמו ב-exception אני לרוב משאיר לשני רכיבי תשתית: 1. רכיב שמבצע כתיבה של ה-exception ל-log 2. רכיב שמאפשר לתרגם exception להודעה "נורמלית" קריאה לעין אנושית מה שמפריע לי היום בכל הנושא של Exceptions ו-Web services, שאין כמעט תשתיות שמטפלות בזה - הרי תמיד אומרים "אל תעיף exception מ-Web service !", אז מה כבר אפשר לעשות ? להחזיר איזה enum ? ומה בדיוק המשתמש יעשה עם זה ? במקסימום הוא יקריא לי הודעה לקונית של "ארעה שגיאה לא צפויה בשירות, אנא דווח על שגיאה 830" - ואז מה ? אני אמור לחפש בכל ה-event viewer את ה-event שנרשם על היוזר הזה בטווח של ה-X שעות האחרונות ? מה שחסר לי היום זה איזה פרימוורק שיודע להתמודד עם exceptions ברמת service, לתעד אותם, להחזיר עבורם איזשהו מזהה סידורי ולהציף אותו למשתמש בנוסף להודעה - כך שהוא יוכל להקריא לי הודעה קצת פחות לקונית בסגנון - "ארעה שגיאה לא צפויה בשרת ! במקרה של פנייה למנהל הרשת מספר התקלה הינה 663527" ואז אפשר יהיה לאתר באופן מיידי את כל פרטי ה-Exception שתועד בשרת - אבל זה משהו שדורש רכיב תשתיתי ולא כפי שציינו - לכתוב כזה רכיב מאפס בכל פרויקט שמגיעים אליו !
 

ייוניי

New member
ומה לגבי טיפול?

איך אתה מציע לטפל ב EXCEPTIONS? הרי בסופו של דבר הכוונה היא לא שהאפליקציה תעוף על כל חריגה שנזרקת, וגם לכתוב כל חריגה ל LOG זה לא בדיוק Business Logic מי יודע מה... אתה מציע לרשת ממחלקות ה EXCEPTION ולתפוס חריגות ספציפיות? הרי זה יוצר צמידות גבוהה. אז בעצם איפה ואיך אפשר לתפוס ולטפל בחריגות בצורה טובה? ובסופו של דבר אנחנו רוצים לשחרר אפליקציה שלא תתעופף בכלל ושתטפל בכל ה EXCEPTIONS בצורה אינטליגנטית. בעיני טיפול טוב בחריגות צריך להיות חלק מהזרימה הטבעית של האפליקציה ולא משהו שעוצר הכל וקופץ לי באופן חופשי להתחלה למקום שבו יש לי פחות יכולת לבחור התנהגות דיפולטית ולהמשיך הלאה.
 

א נ י ה ו

New member
לדעתי הכל תלוי

במצב בו נמצאת האפלקציה, לא תמיד בשלבים הראשונים ניתן לצפות את כל ה exceptions, ולכן יהיו חסרות בדיקות תקינות, כך שלאט לאט (או מהר מהר), מוסיפים אותם. אני נזכר בחלחלה בקוד שכתבה אחת מצוות הפיתוח שלנו, ועשתה try&catch אחד על כל הקוד שלה
("the system seemd to be down"... לך תבנה מדינה ככה)
 

hg1979

New member
מוזר

"שנית, העובדה שחריגה קופצת לה במעלה ה call stack מפריעה לי כי היא מטילה את האחריות לטיפול בשגיאה על אותו קוד שקרא למתודה וזה מגביל אותי." זה כל הרעיון של מנגנון ה EXCEPTION... נראה לי ששוב פספסת משהו...
 
למעלה