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

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

אם אף אחד לא קורא לפונקציה האם היא עדיין משמיעה רעש?

03/10/2024

ג'אווהסקריפט שפה מוזרה, וכלי הבנייה של ג'אווהסקריפט רק הופכים אותה ליותר מוזרה. הקוד הבא הוא קוד JavaScript תקין לגמרי שמדפיס hello world:

function f() {
  const x = 10;
  x = 5;
}

console.log(`hello world`);

בדקתי אותו בדפדפן, ב node וב deno.

באותו זמן הוא גם שובר כלי קומפיליציה - esbuild מדפיס אזהרה כי מנסים לכתוב פעם שנייה למשתנה const. ויט בכלל לא הסכים לקמפל את הקובץ וגם babel התלונן.

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

function f() {
  let x = 10; // Use let to allow reassignment
  x = 5;      // Now the reassignment is valid
  console.log(`x is now: ${x}`);
}

f(); // Call the function

console.log(`hello world`);

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

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

שפה מכתיבה מציאות (או למה אי אפשר לשמור פונקציות ב JSON)

02/10/2024

ל JavaScript אין בעיה לשמור פונקציות בתוך אוביקטים:

> const demo = { hi: function() { console.log('hello world') } }

undefined
> demo.hi()
hello world
undefined

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

> const demo2 = {
  name: 'demo2',
  hi: function() { console.log(this.name); } }
undefined
> demo2.hi()
demo2
undefined

אבל שיטת הסריאליזציה הדיפולטית של JavaScript, שהיא כתיבה ל JSON, לא מאפשרת כתיבה של פונקציות:

> JSON.stringify(demo2)
'{"name":"demo2"}'

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

>>> def twice(x): return x * 2
...
>>> twice(10)
20
>>> pickle.dumps(twice)
b'\x80\x04\x95\x16\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main__\x94\x8c\x05twice\x94\x93\x94.'

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

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

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

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

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

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

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

טיפ ChatGPT - השתמשו רק בשיחות זמניות

01/10/2024

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

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

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

המלצה על פרויקט הצפנה לילדים

30/09/2024

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

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

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

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

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

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

https://headstart.co.il/project/80190

האם קורות החיים שלי גרועים?

29/09/2024

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

המשך קריאה

מה זה בכלל גיט?

28/09/2024

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

המשך קריאה

טיפ SQL: החברים של בוב

27/09/2024

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

המשך קריאה

חדש באתר: קורס SQL בסיסי

26/09/2024

הי חברים.

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

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

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

הפרק הראשון חופשי להתרשמות, המשך הקורס במסגרת תוכנית המנויים (רק 117 ש"ח לחודש לגישה חופשית לכל תכני האתר). פרטים והרשמה בקישור:

https://www.tocode.co.il/bundles/sql

ידע מינימלי הכרחי

25/09/2024

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

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

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

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

import React, { useState } from 'react';

const WeekDaysList = () => {
  const daysOfWeek = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
  const [searchTerm, setSearchTerm] = useState('');

  const handleSearchChange = (event) => {
    setSearchTerm(event.target.value);
  };

  const filteredDays = daysOfWeek.filter(day =>
    day.toLowerCase().includes(searchTerm.toLowerCase())
  );

  return (
    <div>
      <h2>Days of the Week</h2>
      <input
        type="text"
        placeholder="Search days..."
        value={searchTerm}
        onChange={handleSearchChange}
      />
      <ul>
        {filteredDays.map((day, index) => (
          <li key={index}>{day}</li>
        ))}
      </ul>
    </div>
  );
};

export default WeekDaysList;

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

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

היום למדתי: ההבדל בין File.read ל IO.read ברובי

24/09/2024

הרבה זמן חשבתי שבגלל ש File יורש מ IO, אין שום בעיה לקרוא ל File.read או ל IO.read ותמיד מקבלים אותה תוצאה. מבחן הניסיון גם הראה לי תמיד שאני צודק לדוגמה:

3.1.1 :003 > File.read('/etc/shells')
 => "# List of acceptable shells for chpass(1).\n# Ftpd will not allow users to connect who are not using\n# one of these shells.\n\n/bin/bash\n/bin/csh\n/bin/dash\n/bin/ksh\n/bin/sh\n/bin/tcsh\n/bin/zsh\n/usr/local/bin/pwsh\n/usr/local/bin/bash\n/usr/local/bin/zsh\n"
3.1.1 :004 > IO.read('/etc/shells')

 => "# List of acceptable shells for chpass(1).\n# Ftpd will not allow users to connect who are not using\n# one of these shells.\n\n/bin/bash\n/bin/csh\n/bin/dash\n/bin/ksh\n/bin/sh\n/bin/tcsh\n/bin/zsh\n/usr/local/bin/pwsh\n/usr/local/bin/bash\n/usr/local/bin/zsh\n"

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

3.1.1 :007 > IO.read('|whoami')
 => "ynonp\n"

3.1.1 :008 > File.read('|whoami')
(irb):8:in `read': No such file or directory @ rb_sysopen - |whoami (Errno::ENOENT)
        from (irb):8:in `<main>'
        from /Users/ynonp/.rvm/rubies/ruby-3.1.1/lib/ruby/gems/3.1.0/gems/irb-1.4.1/exe/irb:11:in `<top (required)>'
        from /Users/ynonp/.rvm/rubies/ruby-3.1.1/bin/irb:25:in `load'
        from /Users/ynonp/.rvm/rubies/ruby-3.1.1/bin/irb:25:in `<main>'

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