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

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

תיקון ליל שבועות

09/06/2022

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

המשך קריאה

טיפ גיט: ריבייס אחרי אמנד

08/06/2022

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

המשך קריאה

טיפ גיטהאב: איך ליצור Pull Request משורת הפקודה

07/06/2022

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

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

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

https://cli.github.com/manual/installation

על מק זה היה באמצעות brew install gh, ועל חלונות מורידים קובץ התקנה מהקישור https://github.com/cli/cli/releases/tag/v2.11.3. יש גם התקנה ללינוקס אבל אני אתן לכם להיכנס לקישור בשביל למצוא את ההוראות.

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

$ gh auth login

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

ואחרי החיבור נוכל להשתמש בפקודה הבאה כדי ליצור Pull Request משורת הפקודה. בדוגמה שלי אני שולח PR למשתמש ynonp-test ולפרויקט cli-pull-request-demo:

gh pr create -R ynonp-test/cli-pull-request-demo --title "Pull request title" --body "Pull request body"

רק עוד שעה

06/06/2022

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

והקוד שלכם - האם הוא יהיה יותר טוב ככל שהמפתחים מכירים יותר לעומק את הטכנולוגיה? ככל שהמפתחים ישנים יותר טוב ורגועים יותר? ככל שהשעות שמושקעות בקידוד מושקעות 100% בקידוד?

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

משחקים עם קלוז'ר: פיתרון AoC 2021 Day 2

05/06/2022

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

המשך קריאה

משחקים עם קלוז'ר: פיתרון AoC 2021 Day 1

04/06/2022

בעקבות המלצה של חבר התחלתי לקרוא על קוטלין, ומאוד רציתי לכתוב כמה פוסטים על התוכניות הראשונות שאני כותב בקוטלין וכמה היא שפה נחמדה. הבעיה שלא היה קליק אז עזבתי את קוטלין לבינתיים, אבל בגלל שכבר הייתי בתוך ה JVM המשכתי לעבוד קצת על קלוז'ר. ומכיוון שהדרך הכי טובה לתרגל שפה היא לפתור כמה תרגילים מ Advent Of Code התחלתי עם פיתרון היום הראשון מ 2021 בקלוז'ר. התוצאה בפוסט לפניכם וגם עם בונוס של השוואה לפייתון כדי להבין את ההבדלים בגישות.

המשך קריאה

מדריך: בואו נכתוב צ'ט ב Python עם Web Sockets

03/06/2022

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

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

המשך קריאה

טיפ פלקסבוקס: המאפיין width על הילדים

02/06/2022

דמיינו שניה דף HTML שמחולק לתיבת צד ותוכן מרכזי. נו, אתם מכירים כאלה, משהו כזה:

<div class="main">
  <div class="sidebar" >
    <ul>
      <li>hello world</li>
      <li>hello world</li>
      <li>hello world</li>
    </ul>

  </div>
  <div class="content">
    <p>
      Flexbox is really cool if you know how to use it
    </p>
  </div>
</div>

עם הגדרות ה CSS הבאות אפשר לקבוע שהרשימה בתיבת הצד תיקח 300 פיקסלים והתוכן המרכזי יקבל את כל השאר:

.main {
  display: flex;
}

.sidebar {
  width: 300px;
}

.content {
  flex: 1;
}

אבל אל תנסו את זה בבית.

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

<div class="main">
  <div class="sidebar" >
    <ul>
      <li>hello world</li>
      <li>hello world</li>
      <li>hello world</li>      
    </ul>

  </div>
  <div class="content">
    <p>
      Flexbox is really cool if you know how to use it
    </p>
    <div>
      <img src="https://placekitten.com/400/300" />
    </div>
  </div>
</div>

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

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

דרך קשוחה יותר לקבוע רוחב לילד בתוך מיכל פלקס היא לציין את flex-shrink להיות 0 (ועל הדרך גם את flex-grow):

.sidebar {
  width: 300px;
  flex-shrink: 0;
  flex-grow: 0;
}

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

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

.sidebar {
  flex-basis: 300px;
  flex-shrink: 0;
  flex-grow: 0;
}

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

.sidebar {
  flex: 0 0 300px;
}

פיצ'ר קריפ בהבנה

01/06/2022

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

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

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

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

אני לא מאמין ששוב טעיתי ב useEffect

31/05/2022

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

הקוד משתמש ב ResizeObserver כדי להריץ קוד כל פעם שהגודל של אלמנט מסוים שהוא מסתכל עליו משתנה:

import React, { useEffect } from 'react';

// trackedRef is a reference to a DOM element
export default function ResizeHandler({ trackedRef }) {
  useEffect(() => {
    const resizeObserver = new ResizeObserver(() => {
      const height = trackedRef.current.scrollHeight;
      console.log(`Your new height is: ${height}`);
    });
    resizeObserver.observe(trackedRef.current);

    return function cancel() {
      resizeObserver.disconnect();
    }
  }, [trackedRef]);

  return <></>;
}

רואים את הבאג? מוזמנים לשתף בתגובות ולהיזהר מסכינים חדות.

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