כותבים מה אמור לקרות
לפני שינוי הקוד, הגדירו את המשימה. בדוגמה שלנו רוצים להחזיר את המספר הגדול ביותר ברשימה. עבור הרשימה [3, 8, 2] מצפים ל־8, ועבור [-7, -2, -9] מצפים למינוס 2.
אם התוצאה הצפויה אינה ברורה, עדיין אי אפשר לדעת אם התוכנית נכונה. במטלה מבית הספר משתמשים בהגדרה שניתנה, כולל מה שצריך לעשות בקלט מיוחד. המדריך על פייתון למתחילים מתאים למי שעדיין צריך לחזק לולאות, תנאים ורשימות.
מבדילים בין שגיאת ריצה לטעות לוגית
הודעת שגיאה יכולה לסמן בעיה בתחביר או תקלה בזמן ריצה. בתיעוד הרשמי של שגיאות וחריגות בפייתון מוסבר מבנה ההודעות וההבחנה בין סוגי שגיאות. כדאי לקרוא את סוג השגיאה ואת המיקום, ולא לשנות מיד שורה אקראית.
לעומת זאת, אלגוריתם שמאתחל את המספר הגדול ביותר לאפס עלול לרוץ בלי חריגה ולהחזיר אפס לרשימה של מספרים שליליים. זו טעות לוגית: אפס כלל אינו ברשימה ואינו התוצאה הנדרשת.
עוקבים אחרי משתנה אחד על קלט קטן
נניח שהקוד מתחיל ב־biggest = 0, ועובר על [-7, -2, -9]. בכל צעד הוא מעדכן רק אם הערך הנוכחי גדול מ־biggest. שום ערך אינו גדול מאפס, ולכן המשתנה נשאר אפס.
| הערך שנבדק | האם הוא גדול מאפס? | biggest אחרי הבדיקה |
|---|---|---|
| מינוס 7 | לא | 0 |
| מינוס 2 | לא | 0 |
| מינוס 9 | לא | 0 |
טבלת המעקב חושפת את מקור הטעות: ערך ההתחלה אינו מתאים לכל הרשימות המותרות. הקטנת הקלט עוזרת לבדוק את ההיגיון בלי ללכת לאיבוד בין עשרות ערכים.
מתקנים לפי ההגדרה ומתייחסים לרשימה ריקה
אפשר להתחיל מהאיבר הראשון ולבדוק את השאר. בדוגמה הזאת הוחלט להחזיר None אם הרשימה ריקה. במטלה אחרת ייתכן שנדרש טיפול שונה, ולכן ההחלטה צריכה להיות מפורשת.
def largest(values):
if not values:
return None
biggest = values[0]
for value in values[1:]:
if value > biggest:
biggest = value
return biggestבקשו מהתלמיד להסביר מדוע האתחול החדש מתאים לרשימה לא ריקה, ולמה צריך לבדוק ריקנות לפני גישה לאיבר הראשון.
בודקים גם מקרים שהתיקון עלול לפגוע בהם
בדקו רשימה חיובית, רשימה שלילית, איבר יחיד, ערכים שווים ורשימה ריקה. למשל: [5] מחזירה 5, [4, 4] מחזירה 4, והרשימה הריקה מחזירה None לפי ההחלטה בדוגמה.
אל תסתפקו בקלט שחשף את הבאג. בפנייה למורים למדעי המחשב ותכנות שאלו אם עובדים על ציפיות, בדיקות וטבלאות מעקב. המורה צריך לאפשר לתלמיד להציע את התיקון ולנמק אותו, במקום רק להדביק פתרון חלופי.
שומרים תהליך קצר שאפשר לחזור אליו
הגדירו רצף: תוצאה צפויה, תוצאה בפועל, קלט קטן, מעקב, השערה, שינוי אחד ובדיקה חוזרת. אם השינוי לא פתר את הבעיה, חזרו להשערה במקום להוסיף עוד תיקונים בלי להבין את השפעתם.
לתרגול לקראת תיכון קראו על מדעי המחשב לבגרות. בבית, קבעו מתי התלמיד מנסה לעקוב בעצמו ומתי מבקש רמז, כחלק מעצמאות בשיעורי הבית. המטרה היא שיידע להסביר את התיקון גם בתוכנית הבאה.
משחזרים את התקלה לפני התיקון
רשמו קלט מדויק, פלט שהתקבל ופלט צפוי. אם אי אפשר לחזור לאותה התנהגות, קשה לדעת אם שינוי פתר את הבעיה. אין צורך לשמור קלט גדול כשאפשר לצמצמו. במקרה של מקסימום שמאותחל לאפס, רשימה קצרה של מספרים שליליים כבר מספיקה כדי להראות את הכשל.
אל תתחילו מהחלפת שמות או מהעברת שורות בלי השערה. כתבו מה אתם חושבים שגורם לפלט השגוי ואיך תבדקו זאת. השערה יכולה להיות שערך ההתחלה אינו מתאים, שהתנאי הפוך או שהחזרה מתרחשת מוקדם מדי. כל אחת מובילה לבדיקה אחרת. כך התיקון נעשה תהליך של בירור ולא סדרת ניסיונות שמסתיימת במקרה בפלט הרצוי.
קלט קטן מראה את ההיגיון
בחרו רשימה בת איבר אחד, אחר כך שניים. האם התוכנית מחזירה את האיבר היחיד? האם היא מוצאת מקסימום שנמצא בסוף? קלט קטן מאפשר לעקוב בלי לאבד את הערכים. אם התקלה דורשת מצב מיוחד, שמרו רק את הרכיבים הנחוצים ליצירתו.
במקרה של אתחול לאפס, גם רשימה של מספר שלילי יחיד תחשוף בעיה. אין צורך להמשיך לרשימה בת מאה ערכים. אחרי התיקון חוזרים גם לקלט המקורי כדי לוודא שהבעיה אכן נפתרה בהקשר שבו נמצאה. צמצום הוא כלי להבנה, ולא סיבה לוותר על בדיקת התוכנית בתנאים הרלוונטיים.
טבלת מעקב של הגרסה המתוקנת
בדוגמה שבה largest מתחילה באיבר הראשון, המועמד הוא מינוס שבע. כאשר נבדק מינוס שתיים, הוא גדול מן המועמד ולכן מחליף אותו. מינוס תשע אינו גדול ממינוס שתיים, ולכן המועמד נשאר מינוס שתיים. התוצאה נמצאת ברשימה ומתאימה להגדרת המקסימום.
בקשו להסביר מה נכון לגבי biggest אחרי כל סיבוב: הוא הגדול ביותר מבין הערכים שנבדקו עד כה. המשפט הזה מחבר בין האתחול, העדכון והסיום. אם בוחרים ערך התחלתי שאינו שייך לקלט ואינו מתאים לכל האפשרויות, התכונה עלולה לא להתקיים כבר בהתחלה. הבנת התכונה מסבירה מדוע התיקון עובד גם מעבר לרשימה אחת.
return בתוך הלולאה או אחריה
אם מחזירים תוצאה בתוך הסיבוב הראשון, יתר הרשימה אינה נבדקת. התוכנית עשויה לעבוד כשמקסימום נמצא בתחילה ולהיכשל כשהוא בסוף. זו דוגמה לבאג שאינו דורש הודעת שגיאה. בקשו לסמן מתי הפונקציה מסתיימת ולנבא אילו ערכים כלל לא יגיעו לבדיקה.
שמרו רשימה שבה המקסימום בתחילה ורשימה שבה הוא בסוף. שתי הבדיקות יחד מספקות מידע שהראשונה לבדה אינה נותנת. ההזחה בפייתון היא חלק מן המבנה, ולכן שינוי שלה משנה את ההתנהגות. אין לראות בה רק פרט חזותי. כשקוראים קוד, קראו גם גבולות של תנאי ולולאה ולא רק את תוכן השורות.
מה עושים ברשימה ריקה?
בדוגמה המקורית הוחלט להחזיר None. זו בחירת חוזה, ולכן גם מי שמשתמש בפונקציה צריך לדעת עליה. במטלה אחרת יכול להיקבע שהקלט תמיד לא ריק או שנדרשת תגובה אחרת. אין לשנות את ההתנהגות בלי לעדכן את ההגדרה ואת הבדיקות. ״תיקון״ שמסתיר תקלה עלול ליצור אי־בהירות במקום אחר.
שאלו מה אמור לקרות בהמשך כשמתקבל None. אם הקוד הבא מניח מספר, צריך לטפל במצב בהתאם לחוזה. אין צורך להוסיף טיפול בכל קלט אפשרי לתרגיל בית־ספרי קטן, אבל ההנחות חייבות להיות מפורשות. הבדל בין מקרה אסור למקרה מותר בעל תוצאה מיוחדת הוא חלק מן התכנון.
בדיקות ששומרות על התיקון
אפשר לכתוב בדיקות קצרות לדוגמה שנכשלה ולמקרים רגילים. אלו אינן תחליף להבנת הקוד, אלא דרך לראות ששינוי אינו מחזיר את התקלה.
assert largest([-7, -2, -9]) == -2
assert largest([3, 8, 2]) == 8
assert largest([5]) == 5
assert largest([4, 4, 1]) == 4
assert largest([]) is Noneכל שורה בוחנת מצב אחר: שליליים, קלט רגיל, איבר יחיד, ערך חוזר ורשימה ריקה. אין צורך להוסיף עוד בדיקות רק כדי להגדיל כמות. בחרו מקרה לפי סיכון לוגי. אם הדרישה משתנה, עדכנו את הציפייה מתוך ההגדרה ולא מתוך הפלט החדש שהתוכנית החזירה במקרה.
הודעת שגיאה: קוראים את הסוג ואת ההקשר
שגיאה יכולה להיות תחבירית או להופיע בזמן ריצה. קראו את סוגה ואת המקום שאליו היא מפנה, ואז בדקו גם את השורות הסמוכות. אין צורך להעתיק את כל ההודעה למנוע חיפוש לפני שמבינים מה הקוד ניסה לעשות. לפעמים שם משתנה שלא הוגדר או סוג ערך לא מתאים מסבירים את המצב ישירות.
אם משווים מספר למחרוזת במקום למספר אחר, צריך לברר את הקלט ואת ההמרה, ולא רק לשנות את סימן ההשוואה. אם שם שגוי נכתב, בדקו את ההגדרה והאיות. בכל מקרה חזרו לקלט קטן. המטרה היא לקשר בין ההודעה להתנהגות מסוימת בקוד, לא לזכור פתרון קבוע לכל מילה שמופיעה בשגיאה.
הדפסה לצורך בירור, לא כפתרון
אפשר להדפיס זמנית את הערך הנוכחי ואת המועמד כדי לראות את המעקב. בחרו מידע ממוקד. פלט של כל הנתונים בכל שורה יכול להעמיס ולהסתיר את הנקודה. אחרי הבירור הסירו או ארגנו את ההדפסות לפי מטרת התוכנית. אין צורך להשאיר רעש רק כי הוא עזר ברגע מסוים.
הדפסה אינה מחליפה החזרת תוצאה. אם הפונקציה אמורה להחזיר מספר, צריך לבדוק את הערך שמתקבל אצל הקורא. תלמיד עשוי לראות את המספר הנכון על המסך ולהניח שהכול תקין, אף שהפונקציה מחזירה None. זו הזדמנות להבחין בין כלי בדיקה לבין ההתנהגות שהתוכנית נדרשת לספק.
שינוי אחד בכל ניסיון
לפני תיקון שמרו גרסה או כתבו מה השתנה. אם משנים אתחול, תנאי והזחה יחד, קשה לדעת איזה רכיב פתר את הבעיה ואיזה יצר חדשה. התחילו מן ההשערה הממוקדת ביותר, הריצו את המקרה שנכשל ואז את שאר הבדיקות. אם אין שיפור, חזרו למעקב במקום להוסיף עוד שינויים ללא הסבר.
אין חובה להשתמש בכלי מורכב כדי ללמוד את העיקרון. גם קובץ נוסף או רישום קצר יכולים להספיק בשלב ראשון. בהמשך אפשר ללמוד כלי ניהול גרסאות לפי הצורך. המטרה היא לשמור יכולת להסביר את הדרך ולחזור למצב ידוע, ולא להפוך את סביבת העבודה לעוד חסם שמסיח מן האלגוריתם.
מבחינים בין תיקון לשינוי דרישה
אם התוכנית מחזירה את המקסימום אבל התבקש גם מיקומו, חסר חלק מן הדרישה. זהו אינו אותו מצב כמו ערך מקסימום שגוי. לפני שינוי שאלו אם רוצים לתקן התנהגות קיימת או להוסיף פלט אחר. התכנון והבדיקות צריכים להשתנות בהתאם.
גם במקרה של ערך חוזר צריך לדעת מה מבקשים: ערך בלבד, מיקום ראשון או כל המיקומים. אין תשובה אחת בלי חוזה. כתבו דוגמה שיש בה שוויון ובחרו ציפייה מתאימה להוראה. כך התלמיד לומד שדיוק בבעיה קודם לדיוק בקוד, ושלא כל הבדל בפלט הוא תקלה מאותו סוג.
מעבירים את הדרך לבעיה חדשה
אחרי תיקון מקסימום, נסו בעיית מינימום או סכום עם תנאי. אל תעתיקו אוטומטית את ערך ההתחלה. בסכום ריק אפס יכול להיות מתאים, בעוד במקסימום הוא אינו מועמד תקף לכל קלט. שאלו מה המשתנה אמור לייצג אחרי כל סיבוב ומה צריך להיות נכון לפני הסיבוב הראשון.
בקטגוריית מדעי המחשב והתכנות בררו מורה שמאפשר לתלמיד לעקוב, להסביר ולתקן. הביאו קלט, פלט וציפייה, לא רק צילום של הודעה. סימן להתקדמות הוא יכולת לבנות בדיקה ולנסח השערה בתוכנית חדשה. המקלדת וההחלטות צריכות להישאר גם בידי התלמיד, כדי שהכלי לא יהיה תלוי בפתרון של המורה.
מצמצמים את הקלט שממחיש את התקלה
אם פעולה נכשלת ברשימה ארוכה, נסו למצוא רשימה קצרה שעדיין גורמת לאותה תוצאה שגויה. כך אפשר לעקוב אחר כל עדכון בלי ללכת לאיבוד. שמרו לצד הדוגמה את התוצאה הצפויה ואת התוצאה שהתקבלה. קלט קצר אינו הוכחה שהפעולה נכונה בכל מצב, אך הוא כלי להבנת התקלה. אחרי התיקון הריצו גם את הבדיקות הקודמות, כדי לוודא שלא נפתרה טעות אחת באמצעות יצירת טעות אחרת.
