נתוני בדיקה של כתובות הם בדרך כלל מערך הבדיקות האחרון שמישהו מארגן, והראשון שהופך לחסר תועלת. הוא מתחיל בכמה מחרוזות שהודבקו לסקריפט זריעה, גדל בשורה אחת בכל פעם שמתקנים תקלה, ומסתיים בארבעים דוגמאות כמעט זהות שאיש אינו מבין וכולם חוששים למחוק.
המאמר מתאר דרך לארגן את הנתונים כך שיישארו קריאים: מקובצים לפי מדינה ולפי תרחיש, משוחזרים ממקור מתועד, ומסומנים בבירור כבדיוניים כדי שאף קורא עתידי לא יטעה לחשוב שאלה רשומות של לקוח.
להתחיל מתרחישים ולא ממדינות
הדחף הטבעי הוא לארגן מערכי בדיקות לפי גיאוגרפיה—דוגמה אחת לכל מדינה שמשרתים. התוצאה היא רשימה ארוכה עם כיסוי דל מאוד, משום שמה ששובר צינור עיבוד כתובות הוא לעיתים רחוקות המדינה עצמה. זו צורה מסוימת של נתונים: מיקוד חסר, שורת רחוב ארוכה מדי, פרט יחידה, כתב שאינו לטיני, אזור שאינו מסכים עם המיקוד שלו.
יש לארגן לפי תרחיש קודם, ולציין את המדינה בתוך כל תרחיש. מערך התחלתי מעשי נראה כך.
| תרחיש | מה הוא מפעיל | צורה לדוגמה |
|---|---|---|
| כתובת מינימלית | שדות חובה בלבד, בלי יחידה, בלי נפה | רחוב, עיר, חלוקה, מיקוד |
| כתובת מלאה | כל שדה רשותי קיים | מוסיפה יחידה, בניין, נפה, שורה שנייה |
| מיקוד חסר | שדה רשותי במדינות מסוימות | מדינה שכתובותיה אינן נושאות קוד |
| מיקוד בספרות בלבד | אחסון כטקסט, אפסים מובילים | קוד שהתו הראשון שלו הוא אפס |
| מיקוד באותיות וספרות | מחלקות תווים ומפרידים | קוד עם אותיות משולבות |
| שורת רחוב ארוכה מדי | גבולות אורך וחתיכה | שם ארוך בתוספת פרט יחידה |
| כתב שאינו לטיני | ערכת תווים ורינדור | שם במערכת כתב שאינה לטינית |
| אזור לא עקבי | בדיקות יחסיות | אזור שאינו יכול להכיל את המיקוד הזה |
המערך הזה קטן, והוא מכסה יותר מצבי כשל מדוגמה מכל שמונים ומשהו המדינות גם יחד. המדינה שלא בודקת דבר היא זו שכולם כבר תומכים בה.
מדוע מערכי בדיקות של כתובות חייבים להיות משוחזרים?
מערך בדיקות של כתובות שאינו ניתן להפקה מחדש הוא מערך שאיש אינו סומך עליו. אם הנתונים הועתקו פעם ממקום כלשהו והמקור אבד, אז כשבדיקה נכשלת אין דרך לדעת אם הכשל הוא נסיגה בקוד או שינוי בערך שבמקרה ישב שם.
שחזוריות פירושה שאותו קלט מפיק אותו פלט, בכל מכונה ובכל זמן. שתי דרכים להגיע לשם. או שהערכים נגזרים באופן דטרמיניסטי ממזהה—אותו זרע, אותה כתובת, בכל הרצה—או שהערכים נשמרים כקבצים ואינם נערכים ביד לעולם. מה שאינו עובד הוא מחולל שמחזיר דוגמה שונה בכל הפעלה וכותב אותה לתוך מערך הבדיקות, משום שאז שני מהנדסים שמריצים את אותה בדיקה משווים מול נתונים שונים.
להפקה דטרמיניסטית יש תועלת שנייה בסביבות הרצה. רשומה שנטענת פעמיים נושאת את אותה כתובת, כך שהרצה חוזרת אינה יוצרת כפילויות שנבדלות רק בשדות הכתובת שלהן, וצילום מסך מן השבוע שעבר עדיין מתאים לרשומה שרואים היום.
מדוע כתובות אמיתיות של לקוחות אינן שייכות לכאן
העתקת כתובות מסביבת ייצור לסביבת בדיקה או הרצה היא הטעות הנפוצה ביותר בתחום הגנת הנתונים, וקל להבין מדוע אנשים עושים אותה: הנתונים ריאליסטיים, הם כבר שם, ואיש אינו צריך לחשוב על כיסוי.
כתובת היא נתון אישי. היא מזהה אדם, או קבוצה קטנה מאוד של אנשים, ובצירוף שם, היסטוריית הזמנות או מזהה חשבון היא מספיקה כדי לאפשר איתור. מסד נתונים של סביבת הרצה שנבנה בהעתקה מייצור יורש את כל זה, בדרך כלל עם בקרות גישה חלשות יותר, יותר עותקים ביותר מחשבים ניידים, ותקופת שמירת נתונים ארוכה מכפי שמישהו התכוון. הכללים נבדלים בין תחומי שיפוט ובין חוזים, והמאמר הזה אינו ייעוץ משפטי, אבל הנוהג הטכני אינו מוטל בספק: אין להעביר נתוני כתובת אמיתיים לסביבה שאינה ייצור. התמונה הרחבה, כולל שמירת נתונים והסתרה, מכוסה בפרטיות נתוני כתובת.
נתונים בדיוניים מסירים את הדילמה. הם ריאליסטיים בצורתם, אינם הכתובת של איש, ואפשר לפרסם, לשתף, לבצע בהם commit ולהפיק אותם מחדש בחופשיות.
איך שומרים על נתונים בדיוניים ישרים?
נתונים בדיוניים מתכלים. מישהו מוסיף שדה, מישהו אחר עורך ערך ביד כדי לשחזר תקלה, ותוך חודשים ספורים מערך הבדיקות כבר אינו תואם את הסכימה שהוא אמור לבדוק.
שלושה הרגלים מאטים את התכלות הזאת. יש לסמן את הנתונים כבדיוניים בתוך מערך הנתונים עצמו ולא רק בהערה, כך שכל שורה נושאת את הסטטוס שלה לכל מקום שהיא נוסעת. יש לשמור מקור מתועד לכל המערך—הפעלה אחת של מחולל או קובץ אחד שנשמר—במקום מקור לכל רשומה שאיש אינו מעדכן. וכשהסכימה משתנה, יש לגזור את מערכי הבדיקות מחדש ולא לתקן שורות בודדות, כדי שהמערך יישאר עקבי מבפנים.
עוזר גם להפוך את הבדיוניות לגלויה במקומות שבהם היא חשובה. שם נמען או סימון בגוש הכתובת שהוא בבירור לא אמיתי מונעים מצילום מסך של סביבת הרצה להיטעות כרשומה אמיתית, ומונעים שימוש בכתובת בדיקה למשלוח בפועל בידי מי שמצא אותה בקובץ לוג. המערך בכללותו בדיוני: נבנה לבדיקות תוכנה, אינו קשור לשום מסלול מסירה אמיתי, ואינו מלמד דבר על מקום מגוריו של איש.
למפתחים: צורה, בידוד וסקירה
יש לשמור את מערכי הבדיקות במאגר כנתונים, ולא כקוד שבונה נתונים בתוך השורות. ערכים בקובץ ניתנים להשוואה, לסקירה ולחיפוש; ערכים שנבנים משרשרת קריאות בתוך עזר בדיקה אינם ניתנים לשום אחד מאלה, וכשמערך בדיקות משתנה איש אינו רואה זאת בסקירה.
יש לתת לכל שדה את הטיפוס שסכימת הייצור משתמשת בו, כולל טיפוס טקסט על המיקודים. מערך בדיקות שמאחסן מיקוד כמספר יסתיר את תקלת האפס המוביל שהוא היה אמור לתפוס, והבדיקה תעבור מהסיבה הלא נכונה. מערכי בדיקות צריכים להיות קפדניים כמו הייצור, ולעולם לא סלחניים ממנו.
יש לבודד את הנתונים לפי סביבה ולהיות מפורש איזה מערך רץ היכן. בדיקות יחידה רוצות דוגמאות זעירות ודטרמיניסטיות; בדיקות אינטגרציה רוצות את מטריצת התרחישים שלמעלה; נתוני זריעה לסביבת הרצה רוצים נפח, מופק ולא מועתק. לשלושת המערכים תוחלת חיים שונה, ואיחודם הוא מה שהופך סקריפט זריעה לבלתי ניתן לשינוי בבטחה.
לבסוף, יש לסקור שינויים במערכי בדיקות כמו קוד. שינוי של שורה אחת במערך בדיקות יכול להפוך בשקט בדיקה שנכשלת לכזו שעוברת, וזה בדיוק סוג השינוי שמגיע בתוך דיף גדול בלי הסבר.
צעדים הבאים
יש לכתוב את מטריצת התרחישים של המוצר לפני שמוסיפים עוד דוגמת מדינה, ולמחוק את מערכי הבדיקות שאינם בודקים דבר. אחר כך יש להפיק את המערך הבדיוני במעבר אחד דרך מחולל הכתובות, לבצע commit לערכים, ולתעד את הפרמטרים שהפיקו אותם. אם מערכי הבדיקות נושאים גם מספרי טלפון, כללי העקביות בקידומות טלפון והתאמת יישוב ראויים ליישום באותו מעבר. להבדל בין עיצוב מחדש לבדיקה אמיתית, ראו אימות ונרמול כתובות.