Sunday, March 12, 2023

Quality is a four letter word


עברית

A question that started in the ABTesting slack group and has found its way to LinkedIn was wondering about whether an unethical product, even if exquisitely built, can be referred to as "high-quality". 

This question resonated with a biff I have with the term "quality" for quite a while now. Specifically, with how it is commonly used. Since many of us have the word "quality" in our role description, many of us and of our colleagues in other software specialization are using it to indicate the sum of all desired things we might want in a piece of software. As we do that, we are shooting ourselves in our metaphoric leg. How bad is it? well, as I was writing this post, I stumbled upon this episode of the testing peers where we can hear four professionals who care about their craft, spend half an hour talking nonsense. By the end of the episode titled "what is testing" they do recognize the fact that they have not actually defined it.It is of no surprise, this term is difficult to define and is pretty vague, and as I've written in the past, it does not conform with the idea of quality in other fields. When my manger says "we have a quality problem in our product" he means one thing that is probably not the same as the product manager saying "We need to have this shipped with perfect quality", and is surely different from the now-so-common definition of "value to some person who matters" or the approaches adopted by ISO - "fitness for use" or "customer satisfaction". What we are getting when we use such an ambiguous term is a feeling of consensus that will blow up in our faces once the actual differences will start to show.

Moreover, "improving quality" is not actionable. If you actually have such a problem, you have a lot of work to do just to clarify what you actually need, and you will need to override people instinctive understanding of this term. Some people would go as far as claiming that "quality" is just about technical mastery and skillful coding. Others will stress the visibility of the product  and others yet will look at the extent in which it gets the job done. All of those are important, but we need to align in order to move forward

Another notion I've stumbled upon sometime during my career is that "quality" is just another word fro "property", which leads me to suggest talking about the specific qualities we are actually seeking in our software. It could end up being a long list, but it will enable us to align more easily, and to break the dichotomous view of "high\low overall quality" - Software (and life in general) is all about choosing the right tradeoffs, and I might go for something that looks nicer even if it is not as fast, or choose the product that preserves my privacy better over the one with more features and better integrations - we need to use a language that helps us notice these possible tradeoffs instead of concealing them under the very broad term "quality".

If "Quality" is a profane word that should not be used, what should we talk about instead? My preferred way is to break it down to different qualities, and preferably, to avoid confusion: Desired properties. What sort of desired properties are there of a software? I'll list a few here, and there are probably more that would be relevant in the various contexts one might find themselves in: 

  • Correctness: This is the extent to which the software is doing what it is supposed to do. A tax calculator makes no tax mistakes given the proper input, a game is responding to the user commands in the expected way, etc.
  • Robustness: The product can withstand messy (and even malicious) input, recover from mistakes and does so for a prolonged time. 
  • Scalability: The product can support the expected growth in a viable way.
  • Performance: Personally I lump here both the quickness of response and the resources consumed by the system, those can be separated if we are in a place to make internal trade-off (for instance, throw more hardware to get faster results without a redesign). 
  • Privacy: How well is the product protecting human data that it handles (or generates). 
  • Ease-of-use: How well can people achieve their goals with the product.
  • Attractiveness: How appealing is a product to the target audience, that would conform to what James Bach has named "charisma"
  • Explainability: The extent to which the behavior of the software is predictable or easy to explain.
  • visibility: can we figure out what happens in production? can we use that data to improve the product? 
  • Safety: will the product kill someone? Harm them in any way? will releasing a new version put us in risk we can't tolerate?

This is a partial list that can be extended with a lot of other properties (an example can be found in the paper by Rikard Edgren, Henrik Emilsson and Martin Jansson extending James Bach's  quality criteria), but one obvious thing is not on my list: Testability. Why is that? because in itself, it provides very little value. I think of testability as a secondary desired property that helps achieving the others or verify their state.Other properties in this category could be maintainability or extendability  I also don't consider process properties in this list, even though they are often more desirable than almost every bullet in my list. Things like efficiency or pace of deployment: I had to draw the line somewhere and so I chose to stick with properties that are attached to the product and not to the teams building and maintaining it.

So, next time someone asks you how to improve the quality of your product, take the time to understand what do they really mean. Are they bothered by functional problems? do we have a security problem? There's no need to go out right and tell them "don't use this meaningless, confusing word", but try to drill down using guiding questions such as "what is the most significant current concrete pain that we feel now?" or "do we want to invest now our efforts in increasing our ability to spot problems in production before our customers, or do we have more pressing matters?" get to somewhere concrete and work from there. Ask such questions again after there has been some improvements in the top priority desired properties.


איכות זו מילה גסה


English

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

השאלה הזו מתכתבת עם נושא שמציק לי כבר כמה שנים טובות: בעולם התוכנה משתמשים במילה "איכות" בצורה חסרת אחריות. אולי זה כי לחלקנו יש תפקיד שהמילה "איכות" מופיעה בהגדרה שלו, או כי כולם סביבנו מדברים ככה, אבל המשמעות של המילה "איכות" באופן בו משתמשים בה היא פחות או יותר "כל מה שטוב ושום דבר ממה שרע". השימוש הזה עושה בעיקר נזקים, ובמקרים מסויימים אפילו אפשר לומר שאנחנו יורים לעצמנו ברגל. כמה המצב חמור? בעודי כותב את השורות האלה נתקלתי בפרק של Testing peers שמנסה להגדיר את המונח הזה. זו דוגמה מושלמת לאיך שארבעה אנשי מקצוע שמשקיעים לא מעט זמן בלשפר את ההבנה המקצועית שלהם פשוט מדברים שטויות. אחרי חצי שעה של קשקשת, הם עוצרים כדי להכיר בעובדה ש"בעצם, לא ממש הגדרנו מה זה איכות". תכל'ס? זה לא מפתיע  - די קשה להגדיר "איכות תוכנה". זה מושג עם הגדרה מעורפלת  שפשוט לא מתיישרת עם הגדרות מתחומים אחרים. התוצאה? כשמנהל אחד אומר "יש לנו בעיית איכות" הוא לא מדבר על אותו דבר כמו מנהל המוצר שרוצה להוציא "מוצר באיכות מעולה" ושתי ההגדרות האלה בטח לא מתיישבות עם ההגדרה הנפוצה "ערך עבור מישהו שאכפ לנו ממנו" (Value to someone who matters)  כמו שאמר ג'יימס באך בעקבות ג'רי ויינברג, או ההגדרות שאפשר למצוא בתקן ISO "התאמה לשימוש" או "השבעת רצון הלקוחות". אם ננסה לעבוד כשיש לנו תחושה כוזבת של הסכמה, זה רק יגרום לחיכוכים אחר כך,

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

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

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

  • נכונות: עד כמה התוכנה עושה את מה שהיא אמורה לעשות. מחשבון מס לא מגיע לסכומים לא נכונים, משחק מגיב לפקודות מהשלט בצורה הצפויה ודברים כאלה. 
  • עמידות: עד כמה התוכנה יכולה לתפקד לאורך זמן בעולם האמיתי, גם לנוכח משתמשים שמנסים להתקיף אותה
  • סילומיות: תכל'ס, חיפשתי באינטרנט את המילה הזו, אנשים נורמלים יקראו לזה סקיילבליות או משהו כזה. עד כמה התוכנה שלנו מסוגלת לגדול כדי להכיל את סדרי הגודל הצפויים בעתיד הקרוב והבינוני. 
  • ביצועים:אישית אני דוחס לכאן גם את התשובה לשאלה "כמה מהר" וגם את המשאבים שהמערכת צורכת. אם זה רלוונטי, אפשר להפריד את שני אלה כדי שנוכל לשלם באחד כדי לקבל את השני. 
  • פרטיות: עד כמה התוכנה מגנה על מידע אנושי שהיא נחשפת אליו. 
  • נוחות וקלות שימוש: כמה טוב אנשים יכולים להשיג את המטרות שלהם בעזרת המוצר שלנו. 
  • אטרקטיביות: כמה המוצר מוצא חן בעיני המשתמשים. ג'יימס באך משתמש במושג "כריזמה" כדי לתאר את זה.
  • נהירות:עד כמה קל לנו להסביר מה התוכנה שלנו עושה ועד כמה קל לנו לצפות את ההתנהגות שלה במצבים שונים. 
  • נראות: עד כמה אנחנו יכולים לדעת מה קורה עם המוצר שלנו בעודו רץ? האם יש לנו מידע מהשטח שאנחנו יכולים להשתמש בו כדי לשפר את המוצר? כדי לאתר בעיות?

אפשר להרחיב או לשנות את הרשימה הזו, ויש כבר מי שעשו דברים כאלה (למשל, אדגרן, אמילסון ויאנסון הרחיבו כאן את העבודה של ג'יימס באך), אבל אני רוצה להפנות לרגע את תשומת הלב לתכונה אחת שאני לא כולל בתוך התכונות שאנשים רוצים: בדיקתיות. הסיבה לכך היא שיש מעט מאוד ערך בבדיקתיות בפני עצמה. הדרך בה אני חושב על בדיקתיות היא כעל יעד עזר: זה כנראה יהיה משהו שנרצה כדי להשיג מטרה אחרת, או שזו תהיה תוצאת לוואי של תכונה קיימת (למשל, אם שיפרנו את נהירות התוכנה, ממילא שיפרנו את היכולת שלנו לבדוק אותה, ויהיה לנו קשה מאוד לשמור על רמת נכונות טובה אם המוצר שלנו יהיה קשה מאוד לבדיקה). יש תכונות נוספות שאפשר להכניס לתוך הקטגוריה הזו - כמו תחזוקתיות או יכולת הרחבה, אבל זה לגמרי עניין של מי שמרכיב את הרשימה. 
חוץ מזה, יש סוג אחר של פריטים שלא כללתי ברשימה - תכונות תהליך. דברים כמו עקביות, או צפיות (כמה אנחנו יודעים לומר מה ייקח לנו כמה זמן). זה לא שהם לא חשובים, אלא שהייתי צריך למתוח את הקו איפשהו, ולכן בחרתי להתמקד בתכונות של הקוד עצמו ולא של תהליך הפיתוח. זה גם מתיישר עם התפיסה של "מוצר איכותי" - זה לא משנה מה התהליך שהוביל ליצירת מוצר כלשהו. אם הוא טוב, אז הוא טוב. 

לכן, בפעם הבאה בה מישהו שואל "איך אפשר לשפר את איכות המוצר", עצרו לרגע כדי לחשוב למה בדיוק הוא מתכוון. האם יש לנו תקלות פונקציונליות? האם יש לנו בעיות אבטחה? האם לקוחות מתלוננים בהמוצר שלנו זוחל? כמובן, אין צורך (או טעם) לריב על טרמינולוגיה ולהתחיל להסביר "אל תשתמש במילה 'איכות', היא חסרת משמעות ומבלבלת", אבל מאוד כדאי לצלול טיפה יותר לעומק ולשאול שאלות מנחות כמו "מה התסמין הכי בולט של בעיות שיש לנו כרגע?" או "האם כדאי לנו להשקיע מאמץ בניסיון למצוא טעויות לפני הלקוחות או שיש דברים בוערים יותר לעשות?" אחרי שיש לנו כמה תשובות כאלה, אפשר להתחיל לעבוד. על הדרך, בזמן רגוע יותר, אפשר להתחיל לדבר על התכונות שמרכיבות "איכות" מבחינתנו.  

Monday, November 21, 2022

לאן מתקדם בודק תוכנה?



 

English version

קישור למודל

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

ומה המצב אצל בודקי תוכנה? אפשר לומר שהוא כמעט הפוך. לא מאוד נדיר שבודק תוכנה מתחיל ימצא את המשרה הראשונה שלו באיזה סטארט-אפ בו הוא בודק התוכנה היחיד, או היחיד בצוות אליו הוא גוייס, רוב מי שהוא ייתקל בו, גם בודקי תוכנה מנוסים יותר, לא יודעים הרבה על הצד התיאורטי של בדיקות תוכנה, ובלא מעט מקומות, בודקי תוכנה נמצאים אי שם בחלק התחתון של שרשרת המזון. כמעט כל מי שמדבר על "לאן מתקדמים" מצביע על דרך התקדמות אל מחוץ למקצוע - לפיתוח, דבאופס, הנהלת מוצר או "סתם" לתפקיד ניהולי. אילו כישורים נדרשים מאדם כדי להיות בודק תוכנה מוצלח? יש כאן הרבה פרשנות ומעט מאוד קונצנזוס. אילו קורסים זמינים למי שרוצה להשתפר? יש עשרות קורסים מסביב לתוכן של ISTQB, אבל התוכן הזה פשוט לא טוב, ובטח לא משפר את המקצועיות של מי שטורח ולומד אותו (למה אני אומר את זה? אפשר לקרוא כאן). קורסים טובים? צריך לחפור מתחת לסלע. זה לא שאין בכלל, קיבלתי המלצות על כמה קורסים, אבל זה לא טריוויאלי למצוא אותם. ומבחינת משוב - גם כאן אין כזה באמת. לפעמים משהו מתפוצץ בשטח ואנחנו אומרים "כן, יכולנו לעשות עבודה טובה יותר", אבל מה עם כל הפעמים בהן לא היינו בסדר ושום דבר דרמטי לא קרה? או כשהיינו זהירים מדי ותקענו מקלות בגלגלים של כל תהליך הפיתוח? בדרך כלל המשוב שנקבל יהיה ספורדי, באיחור ודי מעורפל. גם כאן, יש את יחידי הסגולה שמצאו דרך לקבל משוב מהיר מהשטח על איכות הפיתוח - הם בדרך כלל לא באמת צריכים בודקי תוכנה.
בקיצור, מנקודת המבט של בודקי תוכנה מתחילים, כל מסלולי הקידום מובילים אל מחוץ למקצוע הבדיקות.חלק קטן מהבודקים האלה ימצאו במקרה מסלולים בתוך עולם הבדיקות (וחלק מתוך אלה יתקדמו בהם עד לנקודה בה תיאורי תפקיד רשמיים לא משנים מאוד), אבל רוב העובדים שטובים מספיק כדי להתקדם יכוונו את הקריירה שלהם למקום אחר. מקומות עבודה שמחפשים בודקי תוכנה מנוסים יצטרכו להתאמץ מאוד כדי למצוא מישהו שגם פנוי לעבודה, גם מנוסה וגם מסוגל לעשות עבודה טובה. 

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

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

כדי לתמוך במטרות האלה, בניתי מודל שמכיל שלוש רמות של הגדרות:

1. בכירות.
חלוקה כללית לדרגות - מי מקבל יותר כסף ויותר אחריות. אם אלה הדברים שמעניינים אותך (ולא, זה לא בהכרח עניין של שטחיות או סתם חמדנות - יש אנשים שנמצאים בתפקיד אחר: משאבי אנוש, כספים, ואפילו המנכ"ל - לא צריך להיות להם אכפת מה בדיוק אומר התפקיד שלך, רק כמה הוא בכיר), אפשר לעצור כאן. אבל, גם לכולנו נוח מדי פעם להכיר את החלוקה לרמות, גם במובן של שכר וגם כדי לדעת מה סוג האחריות שאנחנו צפויים לה.
במודל השתמשתי בשלוש רמות - ג'וניור, סיניור וprinciple (ולא, לא היה לי הגיוני לכתוב את זה בעברית) כשההפרדה היא לפי מידת השפעה מרמת הוא שעושה את העבודה שלו ועד לזה שמשפיע על כל הארגון. ככל הנראה, ארגונים קטנים מאוד יצטרכו רק שתי קטגוריות, ובארגוני ענק יהיה צורך ברמות נוספות.

2. תפקידים: אלה כותרות כלליות לסוגי עבודה שונים שאפשר לכלול תחת המטרייה הרחבה של "בדיקות תוכנה". בארגוני ענק יכול להיות שיהיו צוותים שונים שממלאים את הפונקציות האלה, אבל במקומות קטנים יותר (ובארגונים גדולים שבחרו לארגן את העבודה כך), סביר שאדם אחד ימלא מספר תפקידים. למשל - ארגון לא חייב להחזיק מומחה נגישות במשרה מלאה, אבל כדאי שיהיה מישהו שמבין בתחום ויכול לעזור במשימות קשורות כאשר הן צצות. 

3. כישורים ויכולות: כדי לבצע תפקיד בהצלחה, נדרשים כישורים מסויימים. יהיה קשה מאוד לתפקד כמומחה ביצועים בלי להכיר כלי או שניים שמייצרים עומסים או בלי לדעת לנתח צריכת משאבים. עבור כל כישור ניתן לבנות מסלולי הכשרה - ביצוע משימות קשורות, קורסים, הרצאות וכדומה, ולהגדיר דרכים למדידת המיומנות של עובד בכישור מסויים. 

העבודה שלי, באופן טבעי, רחוקה מלהיות מושלמת. אני משתמש בשפה שמובנת בעיקר לי, ואין ספק שאני מחמיץ תחומים שלמים. לכן, אני מבקש מכם להוסיף הערות - הייתי שמח אם המודל הזה יהיה משותף לקהילה כולה ויוכל לשמש גם את מקומות העבודה השונים בהגדרת התפקידים שהם מחפשים ומסלול ההתקדמות וגם את בודקי התוכנה עצמם כשהם מנסים להגדיר לעצמם את מסלול ההתפתחות שהם רוצים לנסות.  המודל שלי נמצא כאן ויש הרשאות הערה לכל מי שניגש אליו. ספרו לי מה עובד בשבילכם היטב, אילו הנחות אני מניח ולא מתאימות לכם, מה חסר. שתפו את המודל הזה עם קולגות וחברים כדי שגם הם ייתנו משוב. זו גם ההזדמנות להודות לPerze Ababa שהשקיע לא מעט מזמנו ועזר לי לשים לב לכמה פערים ולראות גם חלק מנקודת המבט של ארגונים גדולים באמת. 

What's the career path of a tester?

עברית

Link to the model

 When programmers set their foot on their first job, there are quite a lot of options they can see and choose to specialize in: Embedded systems or highly distributed cloud architectures, specific programming language such as Java, Python or c, optimization and debugging, and that's even before we consider business domains. They will often find themselves with more experienced developers who will give them feedback on their work during design & code reviews, who will talk about concepts they still need to master such as secure code design, efficiency or design philosophies. They will have plenty of opportunities to go back to a piece of code they wrote and experience their mistakes biting in their respective behinds, just so that they can see how much progress they have made. All in all, that's an amazing learning environment even before we consider the plethora of easy to find courses and online resources that teach relevant skills in the appropriate level. 

How is it for software testers? Well, one might say it's the complete opposite. It's not uncommon for testers to find themselves the sole tester in a team, or even in the whole start-up that hired them. Most of the people they meet, including some more experienced testers) won't know a lot about testing and in many places testers are so down the pecking order that it can seem that any career progress is pointing outside of testing - to programming, devOps, product management, or just to being a manager. What skills are required to function well as a function tester? One can find as many opinions as there are people, and most of them won't be actionable. Courses? By a simple search one will stumble upon a lot of ISTQB content, but this content is the opposite of helpful as it provides misconceptions and bad thought patterns (more on that here). There is some good content out there (I've heard good recommendations on BBST and RST, but can't attest yet to their content personally), but if you can find it - you have already burrowed deep enough into the rabbit hole that is the very specific testing community where I've been around for a while now. As for feedback on our work - what feedback? With the exception of an occasional blaming finger of "how did this bug escaped QA" (which we try to avoid), there's very little feedback on testing done right or wrong. What about the times where we were slacking but by chance there wasn't any critical blowup that happened? Or when we were too careful and slowed down the entire development process? Yes, there are outliers that have managed to build a way to get good, reliable feedback on their product from the real world, where it's deployed. But guess what? They usually don't really need testers.
In short, taking the view of an inexperienced software tester, it looks as if all growth paths are leading outside of testing. A small part of those testers will manage to find their way inside the testing world (and some of those will make progress to the level where formal titles do not limit them and matter a lot less) but most capable employees will find a way out of testing. As a result, places looking for experienced, high-skilled testers will have a hard time finding them, and those testers will have a difficult time finding a workplace that will appreciate their skills.

Where I work, we decided to tackle this difficulty initially by looking for inexperienced employees, assuming that it will be easier to teach people good testing if there aren't any bad habits that needs to be broken. We knew that this plan has some drawbacks: We'll have to invest more in training, and we are taking a gamble on their ability to develop the skills we need - which is more difficult than assessing the existing skills of a person. Those were challenges we assumed we could overcome. Naturally, we did not foresee all of the challenges we would face. One of which was employee attrition. To be fair, it's not that we completely ignored this risk, we just assumed that it would be at the same rate as in other teams in the company. Sure, software testing has bad reputation, but we're building a strong team and we can show employees that they can grow significantly and stay. 
Well... no. Inexperienced software testers apply for their first (or second) positions for many reasons, and the most prominent I've encountered is that Software testing has a lower entry bar to "high-tech" jobs, and they assumed (with some degree of truth in it) that it would provide them with a good stepping stone towards the position they actually aim for. Talking with people who left us raised a common pattern: They decided that they can't build their career in testing, and since they did gain some relevant skills, they were ready to make a transition. They also didn't feel they were improving as testers - they could say they are better coders, but the rest of the skills they improved were invisible to them. More importantly, they couldn't see how those skills would help them find their next, hopefully better, job. This brings me back to the job market: Developer jobs are specific (see the list at the top for examples). Testing jobs are almost always "tester\QA\QE\SDET" - nothing that will help differentiate between testers with different experience. It means that the ability to articulate one's added value or interests requires deep thought that is not easy to do at the beginning of one's career, especially if they work in a place that is still building its career ladders and work procedures. 

I want to build a map. Something that will describe possible progress paths inside the role of an individual contributor software tester. It might have exit paths to other roles or to management , but the focus is on software testers and the various kinds of tasks they might perform. Such a map will enable people to look and say "Those are my areas of expertise, this is what I want to do next". For beginners, it can help visualizing their progress, they could look and say "A year ago I had some basic fundamental skills, since I've gained knowledge of accessibility testing, delved a bit deeper into load generation and log filtering and I'm better at risk assessment than I was then". They could then go and say something like "I enjoyed trying to make sense out of heaps of data, so I might want to look into production monitoring and deeper into performance tests, for both I will need skills in data visualization, working with big data and data storage and retention strategies.
With some luck, companies could use it when they define their career ladders, or even in their recruiting processes and ads which will lead to more diversity in hiring "tester".

To support those goals, I built a three layered model:

  1. Seniority.
    A generic, non specialized, catch-it-all division. People who only care about prestige, compensation and responsibility can stop at this level (no, they are not shallow or indifferent, they might be from other professions, such as finance, HR or even your CEO), for the rest of us, it would still be helpful to know which level is any role - both in terms of  compensation and in terms of the type of skills that would be relevant to it.
    In the model I use 3 such categories - Junior, Senior and Principle that represent ever growing sphere of influence - from just doing one's own job, to having a company-wide impact. Smaller companies might only need two such categories, while larger corporations might need more.
  2.  Roles.
    Those are titles to the types of work people with the title of "tester" are often doing and are not considered a distinct role (so, doing part time customer support does not count). Again, the size of the organization matters. Larger ones can have teams that focus on one such role, while smaller places, or corporations that chose to organize their work differently, will have people wearing multiple hats. For instance, not every place needs or can afford an accessibility expert, but most places can benefit from someone who has some accessibility expertise and help the rest of the team(s). 
  3. Skills and capabilities.
    In order to be successful in each role, certain skills are needed. Since those are the things one can learn intentionally breaking down the roles to specific key competencies will be helpful to people who try to make their way through a specific career path. At a later phase, each such skill can be augmented with resources that can help acquiring it, and companies can decide on ways to measure them to decide whether someone has achieved the necessary level of a skill for the step they want to make. 

My work, quite naturally, is far from being perfect or complete, I'm using language and terminology that makes sense to me, and I'm most certainly missing entire fields. This is the point where I'm asking for your help: I would be happy if this could become a model that is developed by the community and will be usable by both companies defining their processes and individuals crafting their career.
My model can be found here and anyone with access can comment. Tell me what works for you, what does not, which assumptions that I make are not suitable for you and what you can see missing there.
This is also the place to thank Perze Ababa that contributed from his time and helped me notice some key insights I was ignoring, as well as see the perspective of the larger corporate for a while.

 

Friday, October 14, 2022

Testing Magic 101

 

עברית

 Every now and then, I get to hear about "X testing", where X might be API, mobile, embedded software or just anything that isn't a website. While I normally scoff at the relevance of such distinctions that usually can be narrowed to "understand your system, understand how to interact with it, the rest of the differences are nothing you haven't seen before", it is true that the good content will help you notice parameters you possibly didn't consider such as battery consumption for mobile, or heat and power fluctuation for embedded systems.

I got to listen to a recent episode of "The testing show" on AI testing which was, sadly, another one of the infomercial-like episode. It wasn't as terrible as the ones they bring in people from Qualitest, but definitely not one of their better ones. The topic was "AI\ML testing", and was mainly an iteration of the common pattern of "it's something completely new, and look at the challenges around here, also ML is really tricky".

This has prompted me to write this post and try to lay the basics for testing stuff related to ML, at least from my perspective. 

The first thing you need to know is what you are testing - are you testing an ML engine? A product using (or even based on) an ML solution? the two can be quite different. 

For the past decade, I've been testing a product that was based on some sort of machine learning - first a Bayesian risk-engine detecting credit-card fraud, and then an endpoint protection solution based on a deep neural net to detect (and then block) malware. The systems are quite different from each other, but they do have one aspect that was shared to them - The ML component was a complete black-box, not different than any 3rd party library that was included in it. True, that particular 3rd part was developed in-house and was the key differentiator between us and the competition, but even when you have a perfect answer to the relevant question (is this transaction fraudulent? is this file malicious?), there's still a lot of work to do in order to make that into a product - For the endpoint protection product it would be hooking to the filesystem to identify file-writes, identifying the file type, quarantining malicious ones and reporting the attack, all of which should be done smoothly while not taking up too much resources from the endpoint itself, not to mention the challenge of supporting various OS and versions deployed in the field. All of which have zero connection to the ML engine that powers everything. If you find yourself in a position similar to this (and for most products, this is exactly the case) - you are not testing ML, you are at most integrating with one, and can treat the actual ML component as a black box and even replace it with a simulator in most test scenarios.

There are cases, however, that one might find themselves actually testing the ML engine itself, in which case start by admittin that you don't have the necessary qualifications to do so (unless, of course, you do). Following that, we need to distinguish again between two kinds of algorithms - straightforward and opaque. 

Straightforward algorithms are not necessarily simple, but a human can understand and predict their outcome given a specific input. For instance, in the first place I've been the ML was a Bayesian model with a few dozen parameters. The team testing the risk engine  was using a lot of synthetic data - given specific weights for each "bucket" and a given input, verify the output is exactly X. In such cases, each step can be verified by regular functional tests they might require some math, but if a test fails we can see exactly where did the failure happen. In a Bayesian case, calculating a weighted score, normalizing it, recalculating "buckets" and assigning new weights are all separate, understandable steps that can be verified. If your algorithm is a straightforward one, "regular" testing is just what you need. You might need a lot of test data, but in order to verify the engine correctness, you just need to understand the rules by which it functions. 

Opaque ML systems are a different creature. While it is possible to define the expected output of the algorithm given the state it's in (unless it also has a random effect as well), there's use to actually finding them since it would not help us understand why something was a specific answer was given. Notoriously, there are the deep neural networks that are nothing short of magic. We can explain the algorithm of transitioning between layers, the exact nature of the back-propagation function we use and the connections between "neurons", but even if we spot a mistake, there isn't much we can do besides feeding it through the back-propagation function and move on to the next data point.In fact, this is exactly what is being done on a massive scale while "training" the neural net. With opaque systems testing is basically the way they are created, so accepting them as fault-free is the best we can do. 

That being said, ML algorithms are rarely fault free, and this brings us to the point we mentioned before - most of our product is about integrating ML component(s) to our system and we should focus on that  The first thing is to see whether we can untangle it from the rest of our system. We could either mock the response we expect or use input that is known to provide certain result and see that our system works as expected given a specific result from the ML component.

Clever, just assume that correctness is someone else's problem, and we're all peachy. Right?
Well, not exactly. Even though in most cases there will be a team of data scientists (or is it data engineers now?) who are building and tuning the model, there are cases where we actually need to cover some gaps in figuring out whether it's good enough - Is our model actually as good as we think it is? Maybe we've purchased the ML component and we take the vendor's claims with a grain of salt.

A lot of the potential faults can be spotted when widening the scope from pure functionality to the wider world. Depending on what our ML solution does, there's a plethora of risks - from your chatbot  turning Nazi to describing black people as apes to being gender-biased in hiring, that's without considering deliberate attacks that will run your self-driving car to the ditch. To avoid stupid mistakes that make us all look bad in retrospect, I like to go through a list of sanity questions - ones that have probably been addressed by the experts who've built this system, but just in case they got tunnel vision and forgot something - The list is quite short, and I'm probably missing a few key questions, but here's what I have in mind:

  • Does it even makes sense? Some claims (such as  "Identifying criminals by facial features") are absurd even before we dive deeper into the data to find the problems that make the results superficially convincing).
  • The "Tay" question: Does the software continues to learn once in production? If it does - how trustworthy is the data? what kind of effort would be needed to subvert the learning ?
  • The Gorillas question: Where did we get the training data from? is it representative of what we're expecting to see in production?
  • Our world sucks question: Is there a real world bias that we might be encoding into our software? Teaching software to learn from human biased decisions will only serve to give this bias a stamp of algorithmic approval.
  • Pick on the poor question: Will this software create a misleading feedback loop? This idea came from Cathy O'Neil's "Weapons of Math Destruction" - Predictive policing algorithms meant that cops were sent to crime ridden neighborhoods, which is great. But now that there are more cops there, they will find more crimes - from drunken driving to petty crimes or jaywalking. So even if those areas are back to normal rate of crime, it will still get more attention from the police and will make the life of the residents there more difficult. 
  • "Shh.. don't tell"  question: Is the model using data that is unlawful to use? Is it using proxy measures to infer it? Imagine an alternative ML based credit score calculator. It helps those who don't have a traditional credit score to get better conditions for their credit. Can it factor in their sexual preference? And if they agree to disclose their social profiles for analysis, can we stop the algorithm from inferring their sexual preferences?

After asking those questions (that really should be asked before starting to build the solution, and every now and then afterwards), and understanding our model a bit better, we can come back to try and imagine risks to our system. In security testing (and more specifically, threat modeling) there's a method of identifying risks called "movie plotting" where we assemble a diverse team and ask them to plot attacks in a movie like "mission impossible". This idea could work well to identify risks in incorporating ML components to our business, with the only change is that the movie plot will be inspired by to "Terminator" or "The Matrix"

And yet, the problem still remains: Validating ML solutions is difficult and requires a different training than what most software testers have (or need). There are two tricks that I think can be useful.

  1. Find an imperfect oracle: it could be that you have competitors that provide similar service, or that there's a human feedback on the expected outcome (you could even employ the Mechanical Turk). Select new (or recent) data points and compare your system results with the oracle ones - The oracle should be chosen such that every mismatch is not necessarily a problem, but that it's something that is worth investigating. Keep track on the percentage of differences. If it changes drastically, something is likely wrong on your side. Investigate a few differences to see if your oracle is good enough. In our case, we try a bunch of files that enough of our competitors claim to be malicious, and if we differ from that consensus, we assume it's a bug until proven otherwise.
  2. Visualize. Sometimes, finding an oracle is not feasible. On the other hand, it could be that people can easily spot problems. Imagine that Google were placing a screen in several offices and projecting crawled images with what the ML thinks it actually is. It is possible that an employee would have seen it classifies people as apes way before real people were offended by it. 

With that being said, I want to circle back to where I've started: While I hope you've gained an idea or two, testing is testing is testing. With any sort of system that you test, you should start by understanding just enough about it and how it interacts with your business needs, then figure out the risks that you care about and find the proper ways to address those risks.

מבוא לבדיקות קסם

 

English

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

יצא לי להאזין לפרק של The testing show על בדיקות AI. הפרק היה, למרבה הצער, עוד פרק על גבול הפרסומי בו הביאו מישהי אחת לדבר על המוצר שהיא מוכרת. סליחה, על אילו אתגרים בבדיקות יש במוצר הזה. זה לא היה גרוע כמו בפעמים בהן מגיע מומחה מטעם Qualitest, אבל זה לא היה רחוק מזה. בכל מקרה, הנושא היה למידת מכונה, ומעט התוכן שהיה שם ולא היה סתם היכרות או קשקשת ידידותית, היה בעיקר חזרה על "יש פה משהו חדש לגמרי ושונה מכל מה שהכרנו עד היום, ותראו אילו אתגרים יש פה! כבר אמרתי שזה קשה?". 

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

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

בעשור האחרון עבדתי עם מוצרים שהיו מבוססים על למידת מכונה. קודם על מוצר שעוטף מודל בייסיאני כדי לאתר הונאות בכרטיסי אשראי, אחר כך מוצר שעוטף רשת נוירונים כדי לחסום רושעות. לא בטוחים מה אחד המונחים האלה אומר? אפשר לקרוא על זה בזמנכם הפנוי, כרגע מספיק אם נתייחס לזה כאל כישוף שחור 1 וכישוף שחור 2. למרות ששני המוצרים שונים מאוד זה מזה בכמעט כל פרמטר, מבחינת שניהם המודל היה סוג של קסם - זורקים עליו את הנתונים בצורה הנכונה ומקבלים בחזרה תשובה שתהיה חלק מעץ ההחלטות. נכון. הקסם הזה פותח באותה חברה, והוא גם היתרון היחסי על המתחרים, אבל גם כשיש תשובה מושלמת לשאלה (האם מישהו משתמש בכרטיס אשראי גנוב? האם הקובץ הזה הוא זדוני?) עדיין יש לא מעט לעשות כדי להפוך את זה למוצר - זה לא מספיק לדעת לזהות כל רושעה, צריך גם להתחבר למערכת ההפעלה כדי לתפוס קבצים שנכתבים, צריך לדעת לבודד אותם ולהתריע על המתקפה. כל זה צריך לעבוד בצורה חלקה בלי לגזול יותר מדי משאבים, לתמוך במגוון מערכות הפעלה ועוד. לכל הדברים ההיקפיים האלה יש בדיוק אפס קשר לבדיקות של למידת מכונה והם יהיו עיקר העבודה של מי שמוצא את עצמו בודק מוצר כזה. אלה לא בדיקות של למידת מכונה, אלה בדיקות אינטגרציה עם למידת מכונה, וזה די סבבה להתייחס לרכיב הזה כאל קופסה שחורה, או אפילו להחליף אותו עם איזה סימולטור ברוב המקרים. 

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

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

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

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

הרבה מהבעיות האפשריות עם למידת מכונה הן לא בעיות של תפקוד "לא נכון", כמו שהן בעיות של תפקוד לא צפוי, ולכן תקלות פוטנציאליות יהיו ברורות אם נרחיב קצת את המבט שלנו ונסתכל על ההקשר בו התוכנה שלנו פועלת. זה לא שחסרות תקלות "מפתיעות" שקשורות ללמידת מכונה - מצ'אטבוט נאצי, זיהוי אנשים שחורים כגורילות, הטיה מגדרית בסינון קו"ח וזה לפני שאנחנו סופרים מתקפות מכוונות שגורמות למכוניות אוטונומיות לעשות שטויות.כדי להימנע מתקריות שיביכו את החברה שלנו מאוד, אני אוהב לשאול כמה שאלות בסיסיות שצריכות להישאל עוד לפני שמתחילים לחשוב על שימוש בבינה מלאכותית לפתרון בעיה, והמומחים שבנו את המערכת כנראה כבר שאלו, אבל רק למקרה שהם החמיצו משהו (או, שוב, אם קונים מוצר מדף):

  • כמה זה מטומטם? יש טענות (כמו היכולת לזהות פושעים לפי תווי פנים) שהם מספיק לא הגיוניים עד שאין צורך לחפש את הבעיה בנתונים כדי לדעת שיש אחת כזו.
  • יש מלא נאצים שם בחוץ: האם המודל ממשיך ללמוד תוך כדי שהמוצר נמצא בשטח? אם כן, עד כמה המידע שם אמין? איזה מאמץ יידרש כדי להטות את המודל בצורה שלא תמצא חן בעיני?
  • מוצא האדם מן הקוף: מניין השגנו את הנתונים עליהם אימנו ובחנו את המודל? האם הם מייצגים את המציאות שהמוצר שלנו יפגוש?
  • העולם דפוק: האם יש איזו בעיה בעולם האמיתי שהאלגוריתם שלנו מנציח? אם כשבני אדם מקבלים החלטה הם עושים את זה בצורה מוטה ומפלה, ללמד תוכנה להחליט כמונו רק ייתן להחלטה המוטה סמכות כי "המחשב החליט".
  • בוא נציק לערבים: האם התוכנה שלנו תייצר מעגל משוב מזיק? הרעיון הגיע מהספר של קת'י אוניל "Weapons of Math Destruction" שם היא מדברת על מוצרים שנועדו לעזור לכוחות משטרה (בארה"ב) לחלק את כוח האדם המוגבל שלהם בצורה אפקטיבית יותר ושלח יותר שוטרים לשכונות מוכות פשע. אלא מה? נתוני הפשיעה מגיעים ממה שהמשטרה כבר מצאה. אז גם התחלנו עם הטייה נגד שחורים, וגם עכשיו נמשיך למצוא יותר פשיעה בשכונות האלה, כי מי שנוהג שיכור בשכונה אחרת פשוט לא ייתפס באותה מידה, אז נמשיך לשלוח שוטרים לאותן שכונות ולמצוא בהן יותר פשעים משכונות אחרות. 
  • אל תשאל, לא תשמע שקרים: האם התוכנה שלנו משתמשת במידע אסור כדי לקבל החלטות? אם נחזור לסינון קורות החיים, אנחנו אולי חושבים שהתוכנה לא תפסול מועמדים רק כי הם השתחררו מצה"ל בדרגת רס"ן וטוחנים מילואים, אבל עם מספיק קורות חיים היא תמצא סימנים מקשרים (למשל, לימודים באמצע השירות הצבאי או כניסה מאוחרת לשוק העבודה) שיאפשרו לזהות מי קצין בכיר גם בלי שזה יהיה כתוב באופן מפורש. אם המודל שלנו סתום, הצלחה לנו עם למצוא את זה. 

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

ועדיין, הבעיה נותרת בעינה: לוודא מערכות לומדות זו משימה מורכבת שדורשת הכשרה שונה מזו שיש לרובנו. יש עוד שני טריקים שאני מאמין שיכולים לעזור.

  1. אוראקל לא מושלם: יכול להיות שיש לנו מתחרים שפותרים את אותה בעיה, או משוב שחוזר לגבי כמה התשובה שהאלגוריתם נתן מתאימה. אולי זו סטטיסטיקה כלשהי שאנחנו מודדים, אולי זה משוב אנושי (אפשר גם להפעיל את הטורקי המכני של אמאזון אם אנחנו ממש מגזימים). מה שחשוב הוא שתהיה לנו דרך לומר על מקרה מסויים אם התוצאה הייתה נכונה או שגוייה. אם מצאנו אוראקל לא פגום מדי, אז כל "טעות" היא משהו שמעניין לחקור. למשל - כדי לבדוק את היכולת שלנו לזהות זודנות, אנחנו סורקים קבצים שמספיק מהמתחרים שלנו טוענים שהם זדוניים. לפעמים קורה שאנחנו צודקים יותר, אבל ברוב המקרים, אם אנחנו לא מסכימים עם הקונצנזוס, יש לנו מה לתקן. שיחקנו קצת עם "כמה מתחרים צריכים לחשוב שקובץ הוא זדוני" כדי שברירת המחדל תהיה "אם יש חוסר הסכמה, זה באג עד שיוכח אחרת".
  2. ויזואליזציה. לא תמיד אפשר למצוא אוראקל בקלות (כמה מתחרים יש לגוגל בסיווג תמונות לקטגוריות?), אבל בחלק מהמקרים בן אדם יכול לזהות בעיות במבט חטוף. כמה מהר גוגל היו מוצאים את בעיית הגורילות אילו הם היו מקרינים על מסכים במשרד תמונות ביחד עם התיוג שלהן? או אם הם היו שולחים לכל עובד דוא"ל יומי עם שלוש תמונות ובקשה לאישור?

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

Tuesday, September 20, 2022

defensive coding

 

One of the things happening to people in testing positions is that every now and then we get to say "I told you so", usually around a bug report that was filed and closed as a "won't fix\not a bug\not important" and came back to bite us in the rear. While there's always the basic joy of being right (and more importantly, of other people being wrong), over the years I've learned to see those cases as a professional failures instead of sources of joy. After all, I saw the problem in advance, knew that it was a problem and maybe I could have done something differently to actually get it fixed. Maybe I could have presented the problem differently, talked to other people who could advocate it better for me, collected more evidence or perhaps it was only a matter of being more persistent in asking it to be fixed. In other cases, there was nothing I could do at the time since the reason for not addressing it is rooted in the organizational culture, that I now can start pushing towards. Saying "I told you so" is not the professional thing to do. 

Last week I had just such a case - Something didn't work for a customer, and upon further inspection - had never worked since deployment. Before we got to difficult debugging, we went over the short checklist of problems. Something quite equivalent of your ISP tech support asking you to reboot your router when you call. In our case, this list consisted on one thing - checking the configuration file on the server. With two relevant entries, it was a rather short glance - the authentication token looked fine and the destination URL pointed to the correct base path. So far, so good. 
Then, by sheer luck, something stirred my memory and I've noticed that the URL has been typed with schema+FQDN, you know - the way URLs are usually formatted. I recalled that when I've worked on that feature there was something odd regarding to having the schema provided in the file. A short trip to our bug tracking system, and indeed my memory was correct - if we provide the schema (for those less fluent in this specific terminology, that's the https:// part) , it won't work as the client consuming this configuration will add the schema themselves, and https://https://any.domain will fail. To make it that much more fun, there won't be any way to understand that from the logs. The ticket was logged in last December (about 9 months ago!) and in the discussion around it there were some acceptable reasons to not fixing it, a case could have been made for a fix anyway, but back then it would have been a harder battle to win. It's not that any fix would have been difficult -  the team configuring the server could add a regular expression validation to their tool, the server could reject the config or remove the schema, the client could do the same and log a meaningful error and all of us could be monitoring for this feature once it was deployed We could even change the name of the parameter so that instead of "...URL" it would be "...DOMAIN" and reduce the chance of errors. For almost all steps that we could have taken but did not there's a common reason: Optimistic coding. 
Optimistic coding is a state of mind where we assume that everything is going to be fine - the API is to be used only internally, so everyone will know what they should be doing. And if someone makes a mistake? Well,  it's their problem to fix.  
What we should be doing (and I intend to use this incident as leverage to push towards such behavior) is to create our software with a slightly more paranoid approach. Software is created to be used and operated by human beings, and human beings make mistakes. We need to assume that people operating, configuring and debugging the system will act very stupidly, not because they are stupid but because they are doing something else, under time-pressure and with a lot of distractions around. Most likely, at least some of those people will be our future selves. If we keep that in mind we can adopt a "Nothing gets passed me" approach - any mistake that can be detected in a given phase should be dealt with at this place - fix it if possible, return (or report) an error if fix is not possible.  and almost never let a problem pass from one component to the next.