קוד לשימוש חוזר

14/01/2023

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

דוגמה? בשמחה. קחו קוד פייתון שעושה יותר מדי עבודה על משפט:

import re

text = "one two three I want to see three four five I am alive"

# delete all spaces in sentences
text = re.sub(r'\s+', '', text)

# replace each letter by its ordinal value
text = [ord(c) for c in text]

# leave only values that are larger than what came before
new_text = [text[0]]
for value in text:
    if value > new_text[-1]:
        new_text.append(value)

text = new_text

print(sum(text))

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

גירסה מסוכנת יותר של הקוד הזה עשויה להיראות כך:

import re

def main():
    text = "one two three I want to see three four five I am alive"
    text = delete_all_spaces(text)
    text = change_to_ord_values(text)
    text = change_to_increasing(text)
    print_result(text)


def delete_all_spaces(text):
    # delete all spaces in sentences
    text = re.sub(r'\s+', '', text)
    return text

def change_to_ord_values(text):
    # replace each letter by its ordinal value
    text = [ord(c) for c in text]
    return text

def change_to_increasing(text):
    # leave only values that are larger than what came before
    new_text = [text[0]]
    for value in text:
        if value > new_text[-1]:
            new_text.append(value)

    text = new_text
    return text

def print_result(text):
    print(sum(text))


main()

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

רוב הסיכויים שלא.

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

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