שואפים לאפס – האם אדם, שאינו חסין מפני טעויות, מסוגל לבנות מכונה חסינת טעויות

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

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

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

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

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

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

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

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

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

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

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

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

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

השאלה היא אם בכלל אפשר להביא מערכת ממוחשבת כלשהי ליכולת
פעולה באפס תקלות. המתכנתים הרברט ומיירון הכט ניסו לענות על כך
באמצעות תרשים הזרימה הבא, המבוסס על ניסיונם שלהם ועל סקר סטטיסטי
שערכו בין מתכנתים וחברות תוכנה. הדוגמה שלהם מתחילה בתוכנית מחשב
גדולה טיפוסית, המכילה כמיליון שורות. בממוצע, 2% מהשורות כוללות
שגיאות. כלומר 20 אלף שגיאות. אחרי בחינות והרצות ניסיון, מתגלות
ומתוקנות 90% מהשגיאות הללו, ונותרות 2,000 שגיאות. לא כל השגיאות
הללו הן קריטיות, ולא כולן באות לידי ביטוי, אבל בממוצע, 10% מהן
עלולות לגרום במשך שנה אחת תקלות חמורות במערכת. כלומר 200 תקלות
זמניות, שאילו היו כלולות במערכת של שוטר-רובוט, היו עלולות לגרום
להריגתם של אנשים חפים מפשע. אילו היו כלולות במערכת לניתוח מצב של
ספינת מלחמה, היו יכולות לגרום לזיהוי שגוי של ספינה אזרחית כספינת
קרב, ולהטבעתה. אילו היו כלולות במערכת הקובעת את קצב הפעולה של
קוצבי-לב, היו גורמות לכך שהניתוח יצליח, אבל החולה ימות.

אפשר להניח שאותן 200 תקלות שתתגלינה במערכת במשך אותה שנה,
יתוקנו. כלומר, במערכת תישארנה 1,800 שגיאות בלבד, ובשנה הבאה
יתבטאו 10% מהן, כלומר 180. תהליך כזה עשוי להפחית במשך הזמן את
מספר השגיאות המקוריות במערכת ממוחשבת עד למצב של קרוב מאוד לאפס
תקלות. אבל כל מערכת בסדר גודל כזה (מיליון שורות) זקוקה לשיפורים
ולעדכונים מתמידים. בממוצע, נוספות לה 10% שורות חדשות מדי שנה.
כלומר, מאה אלף שורות חדשות בשנה, ש-2% מהן שגויות, כלומר 2,000
שגיאות חדשות בשנה. לאחר בחינה והרצות ניסיון, נותרות רק 10% מהן- 200
שגיאות המצטרפות ל-1,800 שנותרו מהשנה הקודמת. כך נשמרת רמה
קבועה של 2,000 שגיאות, לכל מיליון שורות תוכנה. למעשה, רוב השגיאות
מוכנסות לתוך מערכות התוכנה דרך הדלת האחורית של פעולות העדכון
וה"תחזוקה".

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

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