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

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

הבחירה לא לדעת

08/10/2024

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

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

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

היום למדתי: הרצת AI מקומי מעולם לא היתה קלה יותר

07/10/2024

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

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

  1. מורידים ומתקינים Ollama מהקישור https://ollama.com/download. וכן יש גם גירסה ללינוקס אז אפשר להפעיל את זה על שרת לכל מערכת ווב שנכתוב.

  2. אחרי ההתקנה על מק התוכנה עלתה לבד והתחילה לענות על בקשות ב API. אם זה לא קורה אפשר להפעיל משורת הפקודה ollama serve.

  3. איך יודעים שזה עובד? מפעילים:

curl http://localhost:11434/api/generate -d '{
  "model": "llama3.2",
  "prompt": "Why is the sky blue?",
  "stream": false}'
  1. אם אתם אנשי שורת הפקודה תוכלו לתקשר עם המודל דרך צ'ט טקסטואלי בעזרת הפעלת הפקודה:
ollama run llama3.2

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

  1. אם אתם מעדיפים GUI תוכלו להתקין את ollama-gui מהקישור https://github.com/HelgeSverre/ollama-gui. אחרי שכפול הריפו מפעילים npm install ואז npm run dev ומקבלים מסך צ'ט בדפדפן בדיוק כמו ChatGPT.

יותר כיף כשמבינים

06/10/2024

ההרצאה של DHH ב Rails World האחרון מעולה ומלאה בתובנות על עולם הפיתוח בכלל ופיתוח ווב בפרט. אחת התובנות שאני רוצה לקחת משם ולשתף היא המשפט Being competent is more fun.

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

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

  1. דיפלוימנט הולך להתבצע דרך Dockerfile שיהיה חלק מהפרויקט ועל שרת שלך.

  2. העדפה לעבודת Front End בלי שלב בנייה, כך שאפשר תמיד ללחוץ View Source ולראות את הקוד המקורי בדפדפן (בלי טייפסקריפט, בלי ריאקט ובלי מיניפיקציה).

  3. שימוש בתבניות ו Generators כדי לאפשר כתיבה מהירה של קוד שיהיה באחריות המפתח.

  4. כל הזמן חיפוש איך להשתמש בפחות - ריילס 8 כבר לא דורשת redis בשביל לנהל Cache, Jobs ו Web Sockets - כל אלה עברו לבסיס הנתונים.

אני רואה את המאמץ אבל חייב להודות שיש גם משהו לא מדויק בדברים במיוחד כשנזכרים ב Active Record ואיך כל תשתית ה ORM של ריילס מרחיקה אנשים מלימוד SQL ואיך אינסוף הפונקציות שהם הוסיפו לרובי גורמות למתכנתי ריילס להרגיש אבודים כשמנסים להפעיל פונקציה כמו second על מערך ומגלים שזו עוד המצאה של ריילס.

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

נ.ב. לינק להרצאה, לפחות החצי הראשון מומלץ גם למי שלא חי בעולם של ריילס: https://www.youtube.com/watch?v=-cEn_83zRFw

מנגנון האותנטיקציה של ריילס 8 דווקא ממש נחמד

05/10/2024

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

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

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

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

  3. קונטרולר ומסכים לטיפול ב"שכחתי סיסמה".

ברירות המחדל שנבחרו מצוינות:

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

class ApplicationController < ActionController::Base
  include Authentication
  # Only allow modern browsers supporting webp images, web push, badges, import maps, CSS nesting, and CSS :has.
  allow_browser versions: :modern
end

השורה include Authentication מכניסה לכל קונטרולר את הבלוק:

included do
  before_action :require_authentication
  helper_method :authenticated?
end

הסיסמאות שמורות בתור bcrypt.

מסך החיבור מוגבל עם Rate Limit עם השורה:

  rate_limit to: 10, within: 3.minutes, only: :create, with: -> { redirect_to new_session_url, alert: "Try again later." }

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

  1. אין תמיכה בייצור טוקנים ל API.

  2. אין מסכים ליצירת משתמשים, או בכלל התיחסות ל flow של משתמש חדש (אולי אימות של כתובת מייל).

  3. אין עריכת פרטי משתמש, שינוי כתובת מייל או שינוי סיסמה.

  4. אין התיחסות לחיבור משתמש דרך שירותי צד שלישי.

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

לא מחכה לריאקט 19

04/10/2024

ריאקט התחילה בתור ספרייה לשכבת הממשק בלבד (UI Library). בשנים הראשונות הצוות שעבד על ריאקט חיפש את הדרך הטובה ביותר לבנות ממשק שיאפשר למפתחים לכתוב קומפוננטות לשימוש חוזר. הם עברו שתי מהפכות גדולות - מאובייקטים לקלאסים ומקלאסים לפונקציות. אחרי המעבר לפונקציות החל שינוי כיוון בפיתוח ריאקט והצוות התחיל לחפש "תבניות" שאנשים כותבים בריאקט ולהכניס אותן לתוך הפריימוורק. תקופה ארוכה התעסקנו עם Concurrent Mode ועם היכולת לאפשר לקומפוננטות לעצור באמצע תהליך Rendering, ואחרי שזה בוצע היעד הבא שלהם היא לפתור את ה Data Fetching וזה הסיפור של ריאקט 19.

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

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

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

  3. הוקים חדשים בשם useActionState ו useFormStatus נועדו להקל על הגשה של טפסים בצורה אסינכרונית.

  4. פונקציה חדשה בשם use (סוג של הוק) מאפשרת להשתמש ב Suspense לצורך Data Fetching ולבצע קריאה אסינכרונית מתוך קומפוננטה, בעצם סוג של לכתוב קומפוננטה אסינכרונית.

אין ספק שיש הרבה שיפורים מעבר לתמיכה המובנית ב Data Fetching - התמיכה ב Stylesheets מתוך קומפוננטה, התמיכה במאפיינים לכותרות המסמך ותיקוני API שקשורים ל ref ול useDeferredValue, ועדיין אני בטוח שהשינוי הבולט ביותר יהיה הפונקציה use. אז איפה הבעיה? כמו תמיד כשמפתחים API חדש יהיו בעיות, יהיו מקרי קצה מבלבלים, רוב האנשים ישתמשו בזה לא נכון ועוד שנתיים נגלה שחצי מהקוד שכתבנו לא מספיק יעיל או לא מטפל נכון באותם מקרי קצה. וכן זה בסדר לנסות לחדש, אבל הייתי שמח לראות את החידושים שקשורים ל Data Fetching תחומים לתוך ספריות כמו react query ולא גורמים לנו לארגן מחדש את הקוד וליצור "עוד דרך" לכתוב קומפוננטות ריאקט.

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

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

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

המשך קריאה