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

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

משחקים עם קלוז'ר: פיתרון 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 על הילדים

דמיינו שניה דף 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, לכתוב אפקטים קצרים ולא יותר מדי מהם ולקוות שבאיטרציה הבאה של ריאקט דן אברמוב יבוא עם מנגנון יותר ידידותי).

הזמנה לוובינר: ניהול משתמשים עם auth0

30/05/2022

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

השבוע אנחנו הולכים לתקן את זה.

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

  1. מה זה OAuth, מה זה OpenID Connect, ותכל׳ס איך זה עובד.

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

  3. נבנה בעזרת Auth0 שרת API שרק משתמשים רשומים יכולים לפנות אליו.

  4. נבנה לקוח React שיאפשר למשתמשים "להתחבר" למערכת ולבצע פעולות בשרת ה API.

בדרך נדבר על JWT, Access Tokens, ID Tokens, Refresh Tokens, על ניהול Session בעזרת Cookies או Local Storage, וכל שאלה אחרת שתהיה לכם בנושא הזדהות.

הוובינר יערך בזום ביום חמישי הקרוב ה 2/6 בשעה עשר בבוקר. לפרטים והרשמה בחינם הכנסו לדף הוובינר בקישור:

https://www.tocode.co.il/workshops/114

היום למדתי: מה באמת הפריע כל כך ב class ב React

27/05/2022

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

Warning: Invalid DOM property `class`. Did you mean `className`?

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

import "./styles.css";

export default function App() {
  return (
    <div class="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

ל div המרכזי יהיה את הקלאס App.

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

export default function App(props) {
    const { class } = props;
}

שלא היה עובד בגלל ש class זו מילה שמורה.

וכן ברור שהיינו יכולים לכתוב במקום משהו כזה:

export default function App(props) {
    const { class: className } = props;
    // now I use className inside the component, to handle the "class" from outside
}

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

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