נגד הרוח

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

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

class Demo:
    def __init__(self, data=[]):
        self.data = data

    def add(self, x):
        self.data.append(x)

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

d = Demo()
print(d.data)

e = Demo([10, 20, 30])
print(e.data)

f = Demo()
print(f.data)

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

d = Demo()
print(d.data)
d.add(10)

e = Demo([10, 20, 30])
print(e.data)

f = Demo()
print(f.data)

ומדפיס עכשיו:

[]
[10, 20, 30]
[10]

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

class Demo:
    def __init__(self, *data):
        self.data = list(data)

    def add(self, x):
        self.data.append(x)

ובאופן כללי אם אנחנו מקפידים לא להעביר בתור Default Value משהו שהוא Mutable לעולם לא תהיה לנו בעיה של שיתוף ערך בלי שהתכוונו.

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