שלום אורח התחבר

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

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

מעדיפים לקרוא מהטלגרם? בקרו אותנו ב:@tocodeil

או הזינו את כתובת המייל וקבלו את הפוסט היומי בכל בוקר אליכם לתיבה:

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

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

סיבה שניה (או יותר נכון אילוץ) להפעיל push מיד אחרי commit היא בשביל להפעיל איזה pipeline שיבדוק את השינוי על שרת מרוחק. גם פה אם אפשר שווה לייצר מאגר אחד עבור ה pipelines והבדיקות, ומאגר שני, אמיתי, לצורך שיתוף קוד עם אנשים אחרים.

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

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

$ git branch --unset-upstream

ועכשיו ניסיון לעשות push ייכשל עם ההודעה:

fatal: The current branch mybranch has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin mybranch

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

$ git push origin mybranch

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

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

המשך קריאה...

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

אבל אלה רק חלק קטן מהמצבים.

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

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

#!/bin/bash

count=0

ls | while IFS= read -r line;
do
  (( count++ ))
done

echo $count

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

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

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

המשך קריאה...

מספר שמח הוא מספר שסכום ריבועי הספרות שלו בסוף יוצא 1. מספר עצוב הוא מספר שסכום ריבועי הספרות שלו לא יוצא 1, לא משנה כמה פעמים מעלים בריבוע ומחברים. ככה יוצא ש 7 הוא מספר שמח, כי כשמעלים אותו בריבוע מקבלים 49, וכשמעלים בריבוע את שתי הספרות של 49 מקבלים 16 ו 81 שסכומם יוצא 97, ממשיכים עוד סיבוב ומקבלים את 49 ו 81 שסכומם הוא 130, ועכשיו אנחנו מתקרבים למשהו כי 3 בריבוע זה 9 ו 1 בריבוע נשאר 1, יחד הם נותנים 10, שסכום ריבועי הספרות שלו הוא פשוט 1 בריבוע ועוד אפס בריבוע כלומר המספר 1.

לעומתו 4 הוא מספר עצוב כי בריבוע הוא נותן 16, וכשמעלים בריבוע את 1 ו 6 מקבלים 1 ו 36, שזה יחד 37, הסכום הבא הוא 58, אחרי זה 89, ואז 145, 42, 20 ושוב 4.

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

המשך קריאה...

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

זה לא אומר שהקוד גרוע.

זה לא אומר שהבעיה קשה מדי וצריך ללכת לפתור בעיות אחרות.

זה לא אומר שאתה לא מתכנת טוב.

זה לא אומר שצריך למצוא ספריה חיצונית שתעשה את הדבר הזה.

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

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

<div />
<div />
<div />
<div />

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

ברכב אפשר לכוון את המראות או לקנות מובילאיי כדי להילחם בשטחים המתים. בקוד, לכל שפת תכנות וסביבה יש את הדרכים שלה ועם הזמן אנחנו לומדים לשים לב ולבנות עוד דרכים כדי לראות טוב יותר. ב HTML שווה להשתמש ב HTML Hint, שאומנם לא זיהה את הבעיה הפעם אבל עוזר לזהות אינסוף בעיות אחרות. דרך שניה היא להתרגל לפתוח את הקובץ בדפדפן עם Inspect Element כדי לראות איך הדפדפן רואה את העמוד. כפתור זה מיד היה מראה את הבעיה כי בחלון ה Inspect אני רואה מה באמת קורה שם:

<div>
    <div>
        <div>
            <div></div>
        </div>
    </div>
</div>

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

function Counter(props: { initialValue: number, step: number }) {
}

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

interface ICounterProps {
  initialValue: number;
  step: number;
  buttonText?: string;
}

function Counter(props: ICounterProps) {
}

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

interface ICounterProps {
  initialValue: number;
  step: number;
  buttonText?: string;
  turboButtonText?: string;
  turboStep?: number;
}

function Counter(props: ICounterProps) {
}

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

interface ICounterProps {
  initialValue: number;
  step: number;
  buttonText?: string;
}

interface ICounterWithTurboProps extends ICounterProps {
  turboButtonText: string;
  turboStep: number;
}

בקוד הקומפוננטה נאפשר לקבל פרמטרים משני הממשקים באמצעות איחוד טיפוסים, ונשתמש ב Casting כדי להפוך את ה props לממשק הכללי ביותר:

function Counter(props: ICounterProps|ICounterWithTurboProps) {
  const {
    initialValue,
    step,
    buttonText = 'Increase',
    turboButtonText,
    turboStep,
  } = props as ICounterWithTurboProps;
}

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

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

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

המשך קריאה...

מתי עוצרים? מתי למדתם "מספיק להיום"? אולי...

  • בסיום השיעור (כשהשעון מראה 12, בעוד 20 דקות)

  • בסוף הפרק

  • אחרי שאסיים את כל התרגילים

  • אחרי שאפתור את הבאג, או כשהקוד יעבוד

  • עד שהאוכל יגיע

  • עד שתיכנס שיחת טלפון מעניינת

  • עד שתגיע הודעה חשובה בווטסאפ

  • עד שאירדם

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

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