עקרונות קוד נקי בפייתון - איך כותבים קוד שגם אתם תבינו בעוד חודש¶
בואו נדבר בכנות. כולם אומרים "תכתבו קוד נקי" אבל כמעט אף אחד לא מסביר מה זה באמת אומר בפועל. אז הנה ההגדרה הכי פשוטה שאני יכול לתת - קוד נקי הוא קוד שמישהו אחר, או אתם בעוד שלושה חודשים, יכולים לקרוא ולהבין בלי לפענח אותו כמו חידה.
הקוד הראשון שכתבתי היה נורא, וזה בסדר גמור. כתיבת קוד נקי היא מיומנות שנרכשת, לא כישרון מולד. הנה כמה עקרונות שיזיזו אתכם קדימה כבר מהיום.
תנו שמות שאומרים משהו¶
זו הטעות הכי נפוצה שאני רואה. תראו את ההבדל:
# לפני
def calc(x, y, z):
return x * y * (1 - z)
# אחרי
def calculate_discounted_total(price, quantity, discount_rate):
return price * quantity * (1 - discount_rate)
שתי הפונקציות עושות בדיוק אותו דבר. אבל בגרסה הראשונה, בעוד שבועיים תסתכלו על calc(x, y, z) ולא תזכרו מה זה בכלל אמור לחשב. בשנייה, השם מסביר את עצמו בלי צורך בהערה נוספת.
הכלל הוא פשוט - אם אתם צריכים הערה כדי להסביר מה משתנה או פונקציה עושים, כנראה שהשם לא טוב מספיק. תשקיעו את השנייה הנוספת לחשוב על שם ברור, זה חוסך דקות של בלבול בהמשך.
פונקציה אחת, משימה אחת¶
פונקציה שעושה יותר מדבר אחד היא סימן אזהרה. תראו דוגמה:
# לפני - עושה יותר מדי
def process_user(name, email):
if "@" not in email:
print("אימייל לא תקין")
return
name = name.strip().title()
print(f"שלום {name}")
save_to_database(name, email)
הפונקציה הזאת מאמתת, מנקה, מדפיסה, ושומרת. אם משהו נשבר, קשה לדעת איפה. פירוק לפונקציות קטנות יותר עוזר גם לבדוק כל חלק בנפרד וגם לקרוא את הקוד כמו רשימת משימות ברורה:
def is_valid_email(email):
return "@" in email
def normalize_name(name):
return name.strip().title()
def process_user(name, email):
if not is_valid_email(email):
print("אימייל לא תקין")
return
clean_name = normalize_name(name)
print(f"שלום {clean_name}")
save_to_database(clean_name, email)
עכשיו כל פונקציה קטנה, ברורה, וקל לבדוק אותה לבד. אם יום אחד תרצו לשנות איך בודקים אימייל תקין, אתם יודעים בדיוק לאן ללכת.
הימנעו מקינון עמוק מדי¶
קוד עם if בתוך if בתוך for בתוך while נהיה בלתי קריא מהר מאוד. תסתכלו:
def check(users):
for user in users:
if user.active:
if user.age >= 18:
if user.verified:
print(f"{user.name} מאושר")
במקום זה, אפשר להפוך תנאים לבדיקות מוקדמות שיוצאות מיד אם משהו לא מתקיים:
def check(users):
for user in users:
if not user.active or user.age < 18 or not user.verified:
continue
print(f"{user.name} מאושר")
אותה לוגיקה בדיוק, אבל בלי שכבות של הזחה שגורמות לעיניים לכאוב.
הערות מסבירות למה, לא מה¶
# לא שימושי - חוזר על מה שהקוד כבר אומר
x = x + 1 # מוסיף אחד ל-x
# שימושי - מסביר את הסיבה
x = x + 1 # מפצה על אינדקס שמתחיל מ-0 בקובץ המקור
הקוד עצמו כבר אומר לכם "מה" הוא עושה, אתם לא צריכים הערה שחוזרת על זה. הערה שווה זהב כשהיא מסבירה למה עשיתם משהו בצורה מסוימת, במיוחד אם זה לא מובן מאליו.
עקביות חשובה יותר מ"נכון" מוחלט¶
יש כמה סגנונות כתיבה תקינים לגמרי, כמו camelCase מול snake_case. בפייתון הקונבנציה היא snake_case לפונקציות ומשתנים. הכלל החשוב באמת הוא - תבחרו סגנון ותהיו עקביים אליו בכל הפרויקט. קוד שמערבב סגנונות מרגיש רשלני גם אם כל שורה בנפרד תקינה.
לסיכום¶
קוד נקי הוא לא עניין של אלגנטיות מיותרת, הוא השקעה ישירה בזמן שלכם בעתיד. כל דקה שאתם משקיעים בשם ברור או בפונקציה ממוקדת חוסכת עשרות דקות של ניסיון להבין מה קרה שם כשתחזרו לקוד בעוד חודשיים, או כשמישהו אחר יצטרך לגעת בו.
בקורס התכנות הבסיסי שלנו יש פרק שלם שמוקדש לקוד נקי, עם דוגמאות לפני ואחרי בדיוק כמו אלה, ותרגילים שמאלצים אתכם לתרגל את ההרגלים האלה עד שהם הופכים לטבעיים.
תרגלו כתיבת קוד נקי בקורס תכנות בסיסי
מוזמנים גם להביא קטע קוד לקהילה ולשמוע דעות איך לנקות אותו, זה אחד הדברים הכי טובים שאפשר לעשות כדי להשתפר מהר.