הבלוג של ינון פרק

טיפים קצרים וחדשות למתכנתים

עיקרון הרצף

27/11/2021

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

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

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

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

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

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

פייתון ומפתחות בלי מרכאות

26/11/2021

באג מעניין בתוכנית שלי הזכיר לי לפני כמה ימים למה חשוב להשתמש ב Type Checking בפייתון. הקוד שלי אחרי ניקוי נראה משהו כזה:

filters = [
        { id: 12, filter: None },
        { id: 15, filter: None },
        { id: 16, filter: lambda x: x > 7 }
        ]

def run_filter(filter_id, data):
    fn = next(x for x in filters if x.get("id") == filter_id)["filter"]
    return [x for x in data if fn(x)]

print(run_filter(16, [2, 5, 9, 11, 20]))

במקום להפעיל את פילטר מספר 16 הקוד מתרסק עם השגיאה הבאה:

Traceback (most recent call last):
  File "/Users/ynonp/tmp/blog/c.py", line 11, in <module>
    print(run_filter(16, [2, 5, 9, 11, 20]))
  File "/Users/ynonp/tmp/blog/c.py", line 8, in run_filter
    fn = next(x for x in filters if x.get("id") == filter_id)["filter"]
StopIteration

שאומרת ש next נכשל כי הוא לא מצא אף פילטר שמתאים לתנאי. זה מוזר כי אני די בטוח שהוגדר פילטר שה id שלו הוא 16. כרגע הקוד לא כולל Type Hints ולכן גם mypy לא מתלונן.

נוסיף Type Hints ונראה אם זה יעזור לקבל יותר מידע:

from collections.abc import Callable
from typing import TypedDict 

class Filter(TypedDict):
    id: int
    filter: Callable[[int], bool]|None

filters: list[Filter] = [
        { id: 12, filter: None },
        { id: 15, filter: None },
        { id: 16, filter: lambda x: x > 7 }
        ]

def run_filter(filter_id, data):
    fn = next(x for x in filters if x.get("id") == filter_id)["filter"]
    return [x for x in data if fn(x)]

print(run_filter(16, [2, 5, 9, 11, 20]))

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

$ mypy b.py

b.py:9: error: Expected TypedDict key to be string literal
b.py:10: error: Expected TypedDict key to be string literal
b.py:11: error: Expected TypedDict key to be string literal
Found 3 errors in 1 file (checked 1 source file)

מבט ממוקד יותר בשורה 9 חושף את הבעיה:

{ id: 12, filter: None },

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

[{<built-in function id>: 12, <class 'filter'>: None}, {<built-in function id>: 15, <class 'filter'>: None}, {<built-in function id>: 16, <class 'filter'>: <function <lambda> at 0x1032b3d90>}]

וכמו תמיד כשמבינים את הבעיה התיקון הוא החלק הקל:

from collections.abc import Callable
from typing import TypedDict 

class Filter(TypedDict):
    id: int
    filter: Callable[[int], bool]|None

filters: list[Filter] = [
        { "id": 12, "filter": None },
        { "id": 15, "filter": None },
        { "id": 16, "filter": lambda x: x > 7 }
        ]

def run_filter(filter_id, data):
    fn = next(x for x in filters if x["id"] == filter_id)["filter"]
    return [x for x in data if fn(x)]

print(run_filter(16, [2, 5, 9, 11, 20]))

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

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

מהיר, עמיד ומתועד

25/11/2021

שלוש מילים שאומרות הכל על הפיתרון הבא שעליך לכתוב:

מהיר- כי Over Engineering זו בעיה; כי יש לקוח שמחכה; כי הזמן שלך יקר ואין טעם לבזבז אותו על סיבוכים מיותרים.

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

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

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

אני רוצה להיות ...

24/11/2021

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

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

ויש המון סיבות לפער:

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

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

  3. יש עכשיו המון לקוחות חדשים, צריך לתקן מהר את הבעיות כדי לא ליצור לחברה שם רע.

  4. אין לנו לקוחות בכלל אז חייבים לבנות מהר את הפיצ'ר הזה. אחרי שנמצא כמה לקוחות נוכל לתקן.

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

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

מעניין, מועיל, חשוב

22/11/2021

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

היכרות טובה עם כלי עבודה שאתם כבר היום משתמשים בו יכולה מאוד להועיל לפרודוקטיביות שלכם.

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

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

מעניין דואג לעצמו. זאת המשימה שלנו למצוא זמן ל"חשוב" ו"מועיל". המפתח להצלחה הוא בידיים שלהם.

מה יקרה אם?

21/11/2021

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

המשך קריאה

תרגומון Vue: שלוש דרכים לכתוב קומפוננטה

20/11/2021

המעבר ל Composition API ואחריו ל script setup עלול להיות מבלבל כשמתחילים לעבוד ב Vue: דוגמאות באינטרנט יכולות להופיע בכל אחד משלושת הכתיבים ואפילו התיעוד הרשמי לא בחר המלצה ברורה. כך יוצא שמצד אחד כשמתחילים ללמוד את הפריימוורק אנחנו צריכים לבחור כתיב מסוים, אבל לאורך הדרך בכתיבה אם לא ניפתח להכיר את שני הכתיבים האחרים יהיה לנו מאוד קשה.

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

המשך קריאה

הכי טובה בצוות

19/11/2021

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

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

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

מה לעשות כשגילית שיש דרך יותר טובה?

18/11/2021

התשובה הקלה- לשנות.

אין שום תירוץ להמשיך להשתמש ב componentDidUpdate, componentWillUnmount ו componentDidMount בריאקט אם אתה יודע איך להשתמש ב useEffect.

ואין שום תירוץ להמשיך לכתוב var אחרי שאתה יודע על let ו const.

ועדיין-

החיים האמיתיים קצת יותר מאתגרים. אי אפשר לרוץ על פרויקט שלם ולהתחיל לשנות את כל המקומות שכתבו בהם var ל let או const, כי בפרויקט מספיק גדול לא נצא מזה. אי אפשר להפוך את כל הקומפוננטות ריאקט מכתיב קלאסים לכתיב פונקציות ו Hooks ביום אחד.

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

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

  1. פעם בחודש מקדישים יום לשדרוג תלויות.

  2. פעם בשבוע מקדישים שעתיים ל Refactoring של קוד כדי שיהיה קל יותר לשלב אותו בשיטות עבודה חדשות.

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

  4. כל יום מקדישים רבע-שעה לקריאת מאמר מקצועי כדי להיחשף לשיטות עבודה חדשות וטובות יותר.

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

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