טיפים לכתיבת קוד נקי בשפה דינמית

14/05/2023

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

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

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

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

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

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

user = User.find_by(email: 'ynon@tocode.co.il')
language = Language.find_by(name: 'English')
blog_post = BlogPost.find_by('published_at > ?', 1.days.ago)

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

  1. השתמשו בקונבנציות שמות - כשיש טיפוסים מסוימים שחוזרים על עצמם, משתלם להשתמש בקונבנציית שמות כדי לרמוז לקורא למה אנחנו מצפים. לדוגמה בקוד JavaScript הרבה מתכנתים ישתמשו בתחילית $ כדי לרמוז שמשתנה מסוים צריך לקבל DOM Element. אם זו קונבנציה גם בפרויקט שלכם ואתם רואים פונקציה כזו:
function applyTheme($el) { ... }

אז ברור שהפונקציה מצפה לקבל אלמנט והיא כנראה "תלביש" עליו איזושהי ערכת עיצוב.

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

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