חוב טכני (ידוע גם בשם "חוב דיזיין"[1] או "חוב קוד") הוא עיקרון בפיתוח תוכנה, שמשקף את העלות המרומזת של תוספת עבודה. העלות הזו נוצרת כאשר בוחרים בפתרון קל ומיידי במקום בגישה טובה יותר שתדרוש זמן רב יותר.[2]
אפשר להשוות חוב טכני לחוב כספי[3]. אם חוב טכני אינו מוחזר, הוא יכול לצבור "ריבית", ולהקשות על מימוש שינויים בהמשך. חוב טכני שאינו מטופל מגדיל את אנטרופיית התוכנה. חוב טכני אינו בהכרח דבר רע, ולעיתים נדרש חוב טכני על מנת לגרום לפרויקט להתקדם (כמו במקרה של הוכחת היתכנות). מצד שני ישנם מומחים הטוענים כי דימוי החוב הטכני נוטה למזער את עוצמת הפגיעה שנגרמת ממנו, ובכך הדימוי מוביל לתיעדוף נמוך מדי של עבודת התיקון של סיבוכי תוכנה מסוג זה.[4][5]
כאשר מבצעים שינוי בקוד, בדרך כלל נדרש שינוי תואם בחלקים אחרים בקוד, או בתיעוד. כאשר לא מבצעים את השינויים הללו, הם נחשבים לחוב טכני שיהיה לשלמו מתישהו בעתיד. בדיוק כמו חוב כספי, השינויים שלא בוצעו צוברים ריבית וריבית דריבית, ומכבידים על בניית הפרויקט. למרות שהביטוי שגור בעיקר בפיתוח תוכנה, ניתן ליישם אותו גם בתחומים אחרים.
גורמים
בין הגורמים הנפוצים לחוב טכני נמצא שילוב בין:
חוסר בהגדרות מוצא: כשהדרישות עדיין מתגבשות במהלך הפיתוח, הפיתוח מתחיל מבלי שהוגדר דיזיין. דברים נעשים כך כדי לחסוך בזמן אך בדרך כלל דורשים בהמשך עבודה נוספת.
לחץ עסקי: כאשר העסק מעוניין לשחרר משהו בהקדם לפני שכל השינויים הושלמו, נוצר חוב טכני תואם לאותם שינויים חלקיים.
חוסר בתהליך או בהבנה: כאשר העסק עיוור לעיקרון של חוב טכני, ומקבל החלטות מבלי לקחת בחשבון את ההשלכות.
רכיבים מצומדים: כאשר יכולות אינן מודולריות, התוכנה אינה גמישה מספיק כדי לעבור התאמה לשינויים בארגון.
חוסר בחבילת בדיקות: מעודדת פלסטרים מהירים ומסוכנים בעת תיקון באגים.
חוסר בתיעוד: כאשר קוד נוצר ללא קוד תומך הכרחי. העבודה הנדרשת לייצר כל תיעוד תומך שהוא מייצגת את החוב שיש לשלם.
חוסר בשיתוף פעולה: כאשר לא משתפים ידע בארגון והיעילות העסקית סובלת, או כאשר מפתחים זוטרים אינם מקבלים מנטורינג ראוי.
פיתוח מקביל: פיתוח מקביל בשני ענפים או יותר צובר חוב טכני בגלל העבודה הנדרשת באיחוד שני הענפים לבסיס קוד יחיד. ככל שמבצעים יותר שינויים בסביבה מבודדת, כך גדל החוב הטכני.
התעכבות בארגון הקוד מחדש: עם התפתחות דרישות הפרויקט, יש שמתגלה כי חלקים של הקוד הפכו לבלתי יעילים או קשים לעריכה, ויש לארגן אותם מחדש על מנת לתמוך בדרישות עתידיות. ככל הארגון מחדש מתעכב, וקוד מתווסף, כך גדל גם החוב הטכני.
חוסר בהתאמה לסטנדרטים: התעלמות מפיצ'רים, frameworks וטכנולוגיות שמהווים סטנדרט בתעשייה. ההתאמה לסטנדרטים תגיע בסופו של דבר, אך ככל שיקדימו לעשותה, המחיר יקטן (בדומה ל"התעכבות בארגון הקוד מחדש".)
חוסר בידע: כאשר המפתח פשוט אינו יודע איך לכתוב קוד אלגנטי.
חוסר בבעלות: כאשר ניסיון לבצע מיקור חוץ של תוכנה מסתיים בצורך בהנדסה מקומית כדי לארגן מחדש או כדי לשכתב את הקוד שכתבו בחוץ.
הנהגה טכנולוגית גרועה: כאשר הוראות לא מחושבות מספיק שנמסרות לאורך שרשרת הפיקוד מגדילות את החוב הטכני במקום להפחית אותו.
שינויי הגדרות של הרגע האחרון: לשינויים כאלו יש סיכוי לחלחל לפרויקט, אך הם אינם מלווים בזמן או בתקציב שיאפשרו להכניסם לתיעוד או לבדיקות.
סוגים
רבעי החוב הטכני
פזיז
זהיר
מכוון
"אין לנו זמן לדיזיין"
"חייבים לשחרר, ונתמודד עם ההשלכות (אחר כך)"
לא מכוון
"מה זה חלוקה לשכבות?"
"עכשיו ברור איך היינו צריכים לעשות את זה"
ישנם ארבעה סוגי חוב טכני הראויים להתייחסות. בכתבת בלוג בנושא[6] מבדיל פולר בין ארבעה סוגי חוב טכני המבוססים על שתי קטגוריות: קטגוריית פזיז-זהיר וקטגוריית כוונה-טעות.
השלכות
ברור מה העלות של חוב טכני שאינו משולם לעולם: שחרור פיצ'רים יהפוך בשלב מסוים לכל כך איטי שמוצר תוכנה מתחרה שמעוצב היטב יוכל בקלות לתפוס את מקומה של התוכנה עם הפיצ'רים החסרים. מנסיוני, תוכנה שמעוצבת רע יכולה גם לגרום למתח עודף למהנדסים, שיגרום לתחלופת עובדים גבוהה יותר (שבתורה תשפיע על עלויות ויצרניות בשחרור פיצ'רים). בנוסף, עקב הסיבוכיות בקוד, תיעלם היכולת להעריך במדויק את זמן העבודה. כאשר חברות פיתוח גובות על בסיס פיצ'רים, הדבר יכול להביא לשחיקת הרווחים.
"תשלומי ריבית" נגרמים גם בגלל התחזוקה המקומית ובגלל חוסר תחזוקה מצד משתמשים אחרים של הפרויקט. המשך פיתוח של פרויקט הבסיס עליו נבנה הפיתוח יכול גם הוא להקשות על "תשלום החוב" בעתיד. תשלום החוב נעשה פשוט על ידי השלמת העבודה החסרה.
הצטברות חוב טכני היא סיבה מרכזית בפספוס דד-ליינים. קשה להעריך כמה עבודה בדיוק נדרשת בשביל לשלם את החוב. עם כל שינוי מוכנסת לפרויקט גם כמות לא ברורה של עבודה חלקית. פספוס של דד-ליין נוצר כאשר מבינים מבצעי הפרויקט כי שיש יותר עבודה שנדרשת לביצוע מזמן לבצע אותה. על מנת לאפשר תזמוני שחרור צפויים, חייב הצוות המפתח להגביל את כמות העבודה המתמשכת כך שכמות העבודה שלא מבוצעת (או החוב) תישאר קטנה בכל זמן נתון.
אם מושקעת בפרויקט מספיק עבודה בשביל להסיר חסמים לשחרור, הפרויקט ישוחרר, וגם במקרה כזה יש כמות משמעותית של חוב טכני. אם התוכנה מגיעה לפרודקשן, יגדלו מאוד הסיכונים שבמימוש כל שינוי מבני עתידי שמטרתו לטפל בחוב טכני . שינוי בקוד שנמצא בפרודקשן יוצר סיכונים לקריסה, להפסד כספי ממשי, וייתכן שאף לתביעות במקרה שחוזה כולל הסכמות על רמת שירות (SLA). לפיכך אפשר לראות חוב טכני שנגרר לפרודקשן כסוג של עליית ריבית וזו יורדת רק כאשר מערכת נסגרת או יוצאת משירות.
"עם התפתחותה המתמדת של תוכנה, גדלה גם הסיבוכיות שלה אשר משקפת מבנה שמתדרדר, אלא אם מתבצעת עבודת לתחזק או להפחית אותה." [8]
בעוד החוק של מני להמן כבר ציין כי הסיבוכיות של תוכנה מתפתחת גדלה כל הזמן, והמבנה שלה מתדרדר כאשר לא מבוצעת בה עבודת תחזוקה, וורד קאנינגהאם היה הראשון שהשווה בין סיבוכיות טכנית לבין חוב בדוח מ-1992:
"שחרור קוד בפעם הראשונה היא כמו כניסה לחוב. חוב קטן מאיץ מהירות פיתוח כל עוד משלמים אותו במהירות באמתעות שכתוב... הסכנה מאיימת כאשר לא משלמים את החוב. כל דקה שמבוזבזת על קוד שלא-לגמרי-בסדר נחשב כריבית על החוב. ארגון הנדסי שלם יכול לכרוע תחת עומס חוב של מימוש מפורד, מונחה אובייקטים או אחר."[9]
בספר Refactoring to Patterns מ-2004, ג'ושוע קרייבסקי הציג טיעון מקביל באשר לעלויות הקשורות להזנחה תכנונית, אותן תיאר כ"חוב דיזיין".[10]
בין הפעילויות שניתן לדחות אפשר למצוא תיעוד, כתובת טסטים, טיפול במשימות שמסומנות בהערות TODO וטיפול באזהרות קומפיילר בהקשר של ניתוח קוד סטטי. מקרים אחרים של חוב טכני כוללים ידע שלא משתפים בארגון וקוד מסובך מדי שלא ניתן לשנותו בקלות.
גריידי בוש משווה ערים מתפתחות למערכות תוכנה, ומתאר איך חוסר בשינויים מבניים מוביל לחוב טכני.
"קונספט החוב הטכני הוא מרכזי בהבנת הכוחות שמכבידים על מערכות, כי הוא בדרך כלל מצליח להסביר איפה, איך ולמה ישנו עומס על מערכת. בערים בדרך כלל עבודות תשתית מעוכבות והשינויים מבוצעים בהדרגה ולא בצורה נועזת. כך גם במערכות עתירות תוכנה. משתמשים סובלים מההשלכות של סיבוכיות גחמנית, שיפורים מעוכבים ושינויים זוחלים ולא מספקים. המפתחים שמפתחים מערכות כאלו סובלים מחוסר יכולת לכתוב קוד איכותי כי הם תמיד מנסים לעמוד בקצב."[1]