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

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

הצעה לפרויקט - מישהו ללמוד איתו

03/12/2024

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

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

  1. משתמשים יכולים להיכנס ולהקים מסלולי לימוד. מסלולי הלימוד יוכלו להיות בתשלום או בחינם, והם כוללים סילבוס מסודר, משימות ואולי פיתרונות עם הסברים.

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

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

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

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

איך לענות על שאלת ראיון עבודה

02/12/2024

מישהו פרסם שאלת ראיונות עבודה טפשית על JavaScript ושאל מה יהיה הפלט של התוכנית הבאה:

function sayHi() {
  console.log(name);
  console.log(age);
  var name = 'Lydia';
  let age = 21;
}

sayHi();

זה לא חשוב עכשיו מה התשובה. אתם יכולים ללכת ל Chat GPT לברר. מה שיותר מעניין זה מבנה התשובה של אותו Chat GPT:

  1. המשפט הראשון מסביר את המטרה של השאלה - זו שאלה שבודקת את ההיכרות שלך עם הרעיונות של Variable Hoisting ו Block Scoping ב JavaScript. וזאת בדיוק הדרך שכדאי להתחיל תשובה לשאלות גם בראיון אמיתי.

  2. אחרי זה Chat GPT מסביר על הרעיונות ומספר מה ההבדל בין var ו let בהקשר של גישה למשתנה לפני שורת ההגדרה שלו.

  3. לאחר מכן הוא עובר שורה שורה ומסביר מה היא עושה ולמה (זה קצת מיותר בעיניי).

  4. ובסוף מראה את פלט התוכנית.

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

סיפור, משפטים, מילים.

01/12/2024

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

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

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

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

היום הוא היום הראשון של דצמבר והחידה הראשונה של Advent Of Code בדיוק התפרסמה. בהצלחה.

https://adventofcode.com

עשר דקות עם Tanstack Router

30/11/2024

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

https://github.com/ynonp/tanstack-router-simple-demo

המשך קריאה

מה נשאר מחוץ לקורס

29/11/2024

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

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

יש כל מיני רעיונות שלא עובדים, לדוגמה:

  1. תגיד כל מה שאתה יודע על הנושא כדי לא להשמיט כלום (לא עובד. אם אתה צריך ללמד משהו אתה כנראה יודע עליו יותר ממה שהתלמידים שלך צריכים לדעת).

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

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

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

שליטה על Input ב React לעומת Vue

28/11/2024

הקוד הבא ב Vue יכול להטעות:

<script setup lang="ts">
import {ref} from 'vue';

const data = ref('a');

function handleInput(e: any) {
  if (Math.random() * 10 < 2) {
    data.value = e.target.value;
  }
}
</script>


<template>
    <input type="text" @input="handleInput" :value="data" />
</template>

במיוחד אם משווים אותו לקוד מקביל בריאקט:

function App() {
    const [data, setData] = useState('a');
    function handleInput(e) {
        if (Math.random() * 10 < 2) {
            setData(e.target.value);
        }
    }

    return <input type="text" value={data} onChange={handleInput} />
}

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

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

<input type="text" @input="handleInput" :value="data" />
<button @click="data = ''">Reset</button>

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

גם הגדרת v-model עם אפשרות לכתיבה תישאר עם אותה התנהגות מבלבלת:

<script setup lang="ts">
import {computed, ref} from 'vue';
const data = ref('a');
const dataModel = computed({
  get() {
    return data.value;
  },
  set(newValue) {
    if (Math.random() * 10 < 2) {
      data.value = newValue;
    }
  }
})

</script>

<template>
  <Todos />
  <input type="text" v-model="dataModel" />
  <button @click="data = ''"></button>
</template>

גם במצב זה ב 20% מהמקרים תהיה כתיבה למשתנה אבל בשאר 80% לא תהיה כתיבה למשתנה והטקסט בתיבת הטקסט יצא מסינכרון, התיבה תציג את הטקסט שנכתב אבל המשתנה לא יכיל אותו.

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

function handleInput(e) {
  if (Math.random() * 10 < 2) {
    data.value = e.target.value;
  } else {
    e.target.value = data.value;
  }
}

להחזיר או לזרוק

27/11/2024

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

>>> d = {"a": 10, "b": 20}
>>> d.get("a")
10
>>> d.get("d")

או עם אופרטור סוגריים מרובעים שזורק שגיאה אם הערך לא קיים:

>>> d['a']
10
>>> d['d']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'd'

בסקאלה הפונקציה get מחזירה ערך ממפה ואם הוא לא קיים מחזירה None:

scala> Map("a" -> 10, "b" -> 20).get("a")
val res1: Option[Int] = Some(10)

scala> Map("a" -> 10, "b" -> 20).get("d")
val res3: Option[Int] = None

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

scala> Map("a" -> 10, "b" -> 20)("a")
val res2: Int = 10

scala> Map("a" -> 10, "b" -> 20)("d")
java.util.NoSuchElementException: key not found: d
  at scala.collection.immutable.Map$Map2.apply(Map.scala:316)
  ... 30 elided

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

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

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

על הערך של "להיות בעשייה"

26/11/2024

שלושה פחדים שמשותפים להרבה אנשים שלומדים נושא חדש:

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

  2. "עד שאהיה מספיק טוב כבר יהיה מאוחר מדי (הנושא לא יהיה רלוונטי, אני כבר לא אוהב אותו)".

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

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

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

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

אבל ביקשתי לשים את זה באמצע

25/11/2024

נתבונן על הגדרת ה CSS הבאה:

body, html {
  height: 100vh;
  padding: 0;
  margin: 0;
}

main {
  display: flex;
  place-items: center;
  background: #a0a0a0;
}

וה HTML שבתוך ה body כולל בסך הכל:

<main>hello world</main>

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

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

  2. הפקודה place-items: center באמת קובעת ל main למקם את הילדים שלו באמצע שלו. אבל שימו לב שכל גובהו הוא שורה אחת ולכן השורה הבודדת תופסת את כל הגובה.

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

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

  1. נקבע את הגובה של main למספר קבוע או לגובה של המיכל שלו, במקום לגובה של התוכן שלו, על ידי הגדרת height: 100%.

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

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

סך הכל הדוגמה עם היישור בקודפן:

ובקישור: https://codepen.io/ynonp/pen/WbeeQqm

מורים בעידן ה Chat GPT

24/11/2024

מבחינת תפקיד המורה Chat GPT רק חיזק תהליכים שכבר היו לפניו: כל הידע ממילא קיים ברשת, לכל שאלה יש כבר תשובות מצוינות והסברים מדויקים, ועכשיו אפשר אפילו לשאול כשלא מבינים ולקבל הסבר מותאם אישית.

אז מה נשאר למורים לעשות? הנה שלוש משימות חשובות:

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

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

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

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