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