כשאני מלמד Generators בפייתון אני אוהב להתחיל עם הפונקציה הזאת שמחשבת מספר בסידרת פיבונאצ'י:
def fib(n: int) -> int:
a, b = 1, 1
for i in range(n):
a, b = b, a + b
return a
ואז לבקש מהתלמידים לחשב את הסכום של 100 המספרים הראשונים בסידרת פיבונאצ'י. הפיתרון ה"פשוט" הוא למעשה המסובך ביותר:
print(sum(fib(n) for n in range(100)))
בגלל שהוא כולל המון חישובים מיותרים. במצב כזה הרבה יותר יעיל לכתוב פונקציה חדשה (או לכתוב Generator, אבל זה הנושא של השיעור אז בואו לא נקלקל).
הבעיה שלנו כמתכנתים היא שמכל מיני סיבות רוב הזמן אנחנו מעדיפים להשתמש באבסטרקציה הקיימת כדי לפתור בעיות, גם אם היא תקולה, ולא לעצור ולבנות אבסטרקציה חדשה אבל גם לא לכתוב את כל הקוד מחדש. בעולם האמיתי הסיכוי לראות משהו שדומה לחישוב האיטי של סכום פיבונאצ'י הוא מאוד גבוה, והוא גדל ככל שעובדים על מוצרים יותר בשלים (כי יש בהם כבר המון אבסטרקציות).
אני רואה את הטיעון לשימוש באבסטרקציה לא טובה במערכת קיימת. כשיש משהו שעובד חבל לא להשתמש בו, וגם זה יכול לחסוך לי המון זמן פיתוח ולחסוך המון באגים. נכון זה לא הכי יעיל אבל בואו נשאיר את השיפור הביצועים לשלב האופטימיזציה.
אבל כדאי לראות גם את הצד השני - תיקון האבסטרקציה הוא לא רק סיפור של ביצועים אלא גם של נכונות הקוד, ושל כמה מהר אוכל לבנות את הפיצ'ר הבא. ככל שיותר פיצ'רים בנויים על אבסטרקציה קיימת ובעייתית, כך יהיה קשה יותר בהמשך לשנות אותה. בשימוש באבסטרקציה לא נכונה אנחנו פשוט חופרים לעצמנו בור יותר עמוק.
בסיטואציה כזאת הכי טוב לתקן את האבסטרקציה הגרועה ולעשות ריפקטור לכל הקוד שהשתמש בה. אם אין זמן עדיף להתחיל מנגנון חדש. גם אם זה ייקח קצת יותר זמן בפיתוח הפיצ'ר הנוכחי, הזמן הזה יחזיר את עצמו ובדרך גם אנחנו נצבור עוד כמה נקודות במסע להפוך למתכנתים טובים יותר.