ToCode
1.43K subscribers
4.06K links
טיפים קצרים למתכנתים מאת ינון פרק
Download Telegram
📌 היום למדתי: git intent to add

בואו נשחק עם גיט. יש לי ריפו ויצרתי בו קובץ חדש בשם demo.py. רואים את זה:

ynonp@ynons-MacBook-Air ~/tmp/blog/git (main?) $ git status
On branch main
Untracked files:
(use "git add <file>..." to include in what will be committed)
demo.py

nothing added to commit but untracked files present (use "git add" to track)
ynonp@ynons-MacBook-Air ~/tmp/blog/git (main?) $


עכשיו אני רוצה לראות מה יש בקובץ. קודם כל אני מנסה git diff - אבל הוא לא מדפיס כלום כי אין שינויים בקבצים של הפרויקט (הקובץ demo.py הוא חדש ומבחינת גיט לא חלק מהפרויקט עדיין).

אז אני מנסה להוסיף אותו עם git add . ועכשיו הוא חלק מהפרויקט:

ynonp@ynons-MacBook-Air ~/tmp/blog/git (main?) $ git add .
ynonp@ynons-MacBook-Air ~/tmp/blog/git (main+) $ git status
On branch main
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: demo.py

ynonp@ynons-MacBook-Air ~/tmp/blog/git (main+) $ git diff
ynonp@ynons-MacBook-Air ~/tmp/blog/git (main+) $


אבל עדיין git diff לא מדפיס כלום כי אין הבדל בין תוכן הקובץ לתוכן הקובץ ב Staging Area. שוב ברור, git add הוסיף את הקובץ ל staging area.

עד היום השתמשתי ב git diff HEAD או git diff --cached כדי לראות את השינויים אחרי add לדוגמה:

ynonp@ynons-MacBook-Air ~/tmp/blog/git (main+) $ git status
On branch main
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: demo.py

ynonp@ynons-MacBook-Air ~/tmp/blog/git (main+) $ git diff
ynonp@ynons-MacBook-Air ~/tmp/blog/git (main+) $ git diff HEAD
diff --git a/demo.py b/demo.py
new file mode 100644
index 0000000..d77c663
--- /dev/null
+++ b/demo.py
@@ -0,0 +1 @@
+print("hello world from python")


מסתבר ש git add מגיע עם מתג מיוחד בדיוק למקרים האלה, המתג -N או --intent-to-add. מתג זה מסמן לגיט שאנחנו מתכוונים להוסיף את הקובץ הזה לפרויקט בלי להוסיף את התוכן שלו ל Staging בדיוק בשביל שנוכל לראות את ה diff. ככה זה נראה:

ynonp@ynons-MacBook-Air ~/tmp/blog/git (main?) $ git add -N demo.py
ynonp@ynons-MacBook-Air ~/tmp/blog/git (main+*) $ git status
On branch main
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
new file: demo.py

no changes added to commit (use "git add" and/or "git commit -a")
ynonp@ynons-MacBook-Air ~/tmp/blog/git (main+*) $ git diff
diff --git a/demo.py b/demo.py
new file mode 100644
index 0000000..d77c663
--- /dev/null
+++ b/demo.py
@@ -0,0 +1 @@
+print("hello world from python")
ynonp@ynons-MacBook-Air ~/tmp/blog/git (main+*) $


הקובץ מסומן בתור new file אבל התוכן שלו עדיין לא נשמר וכך אנו רואים אותו ב git diff רגיל.
📌 ואיך את יודעת מה המערכת עושה?

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

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

class IssueInvitation
class Rejected < StandardError; end

def self.call(email:, admin:)
raise Rejected, I18n.t("admin.forbidden") unless admin.admin?

token = SecureRandom.urlsafe_base64(32)
invitation = nil
# Serialize issue/resend calls, including invitations without an existing row.
admin.with_lock do
invitation = Invitation.find_or_initialize_by(email: email.to_s.strip.downcase)
raise Rejected, I18n.t("admin.invitations.existing_user") if User.exists?(email: invitation.email)
if invitation.accepted_at?
raise Rejected, I18n.t("admin.invitations.already_accepted")
end
if invitation.last_sent_at && invitation.last_sent_at > 1.minute.ago
raise Rejected, I18n.t("admin.invitations.cooldown")
end
invitation.assign_attributes(invited_by: admin, token_digest: Invitation.digest(token),
expires_at: 7.days.from_now, last_sent_at: Time.current)
invitation.save!
end
InvitationDeliveryJob.perform_later(invitation.id, token)
invitation
end
end


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

if invitation.last_sent_at && invitation.last_sent_at > 1.minute.ago
raise Rejected, I18n.t("admin.invitations.cooldown")
end


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

token = SecureRandom.urlsafe_base64(32)
...
invitation.assign_attributes(invited_by: admin, token_digest: Invitation.digest(token),
expires_at: 7.days.from_now, last_sent_at: Time.current)


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

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

https://www.parameter.ai/labs/we-found-a-gap-at-openai

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

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

ושום AI Security Review בצד של ChatGPT לא ראה את זה לפני שהבאג עלה לאוויר
״תמיד היו בעיות אבטחה״ לא אמור לתת לנו להכניס חופשי קוד למערכת בלי לדעת מה נכנס לשם
👍1
📌 הגרסה המעניינת

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

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

https://tocode.ravpage.co.il/ai-daily

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

וזו הגרסה השניה אחרי הערות:

https://tocode.ravpage.co.il/ai-daily-devs

הרבה יותר יפה אבל משעמם באותה מידה.
(גם הוא עובד. אפשר להירשם ותקבלו 4-5 מאמרים על AI למייל כל בוקר מלבד שבתות וחגים).

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

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

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

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

פעם שניה הוא הלך לאיבוד בחיבור בין next.js ל eve. תיקנתי שוב את הפרומפט.

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

פעם רביעית הוא השתמש ב BetterAuth המשולב ב neon (או לפחות ניסה). תיקנתי את הפרומפט שישתמש במנגנון התחברות מקומי.

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

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

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

ואחרי כל הטעויות האלה הבנתי למה אנחנו אוהבים Coding Agents ואיך כלי פיתוח פשוטים מסתירים את הטפשות של מודלי שפה. אפילו שקלוד מאוד חכם יש יותר מדי נעלמים וניחושים בכתיבת מדריך מראש, אבל כל גרסה של מדריך שנכתבה היה אפשר לתקן ולהביא למצב שהיא עובדת בעזרת לולאת תיקון "תוודא שזה עובד, תקן את הטעויות ותחזור אליי עם קוד רץ". לא כל גרסה היתה יוצאת משהו שרציתי, אבל הרבה יותר מעניין לבחור את ה Tutorial הכי טוב מבין 7 גרסאות (או להמשיך ולייצר גרסאות עד שאני מגיע לגרסה שרציתי).
👍1
📌 מתי לבנות סוכן

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

1. צריכים תרגום? תקראו ל claude עם פרומפט שמבקש תרגום.
2. צריכים לחפש בלוג? שלחו את קלוד למצוא מה מעניין שם.
3. צריכים לסנן איזה PDF הוא חשבונית? פרומפט מתאים לקלוד קוד ותקבלו את הקבצים מסודרים.

אז בשביל מה צריך לכתוב סוכן? אלה התשובות הכי מעניינות שאספנו:

1. ביצועים - כתיבת סוכן מאפשרת להריץ את כל הפניות ל LLM מאותו תהליך במקום להריץ תהליך נפרד לכל פניה.
2. שליטה בטוקנים - כתיבת סוכן מאפשרת לי לקבוע את ה System Prompt ולבחור בדיוק מה יישלח ל LLM.
3. חיבור לתוכנית שלי באמצעות מימוש כלים - במקום לכתוב MCP אני יכול לכתוב פונקציות פייתון פשוטות שיאפשרו למודל להתממשק עם המערכת הקיימת שלי.
4. פלט מובנה - פניה לסוכן בסקריפט עם claude -p מחזירה תמיד תשובה כמחרוזת. סוכן יכול לדרוש Structured Output כדי לקבל מבנה צפוי של התשובה.

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

כשהסוכן כותב ״סיימתי הכל בהצלחה״ למה הוא מתכוון?

נתתי ל-4 סוכנים להוסיף 4 פיצ׳רים במקביל לאפליקציית דוגמה לקראת הוובינר של יום חמישי.

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

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

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

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

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

ומה איתנו?

נניח שאני רוצה לבנות מערכת API בפייתון שתעבוד להרבה לקוחות. אני מתייעץ עם ה AI והוא ממליץ לי על FastAPI כשהשורה הראשונה בהמלצה "מהיר מאוד ותומך ב-async". אני יכול להמשיך עם "תראה לי דוגמה" או לשאול מה זה asyncio ומה היתרונות שלו ואז אני מבין בגדול על מה מדובר ויכול להתקדם לכתוב את השרת.

אבל כל זה זה למידה של אתמול.

יותר מעניין להמשיך את השיחה עם "מעניין ואיך זה בנוי?" ואפילו "מה הייתי צריך בשביל לממש event loop מאפס?". השאלה השניה מלמדת אותי שזה אפשרי ושהבסיס הוא Generators אז אני ממשיך עם פרומפט יותר ארוך:

בנה מודול לימוד אינטרקטיבי בסגנון Khan Academy על ״מבנה asyncio בפייתון״
במודול לומדים איך עובד asyncio ומה זה mainloop ואיך בונים אותו מאפס. נרצה לראות מימוש פשוט לדוגמה של Task Scheduler, Poller, Time queue ו Ready queue.

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

בנה את זה בתור artifact עם HTML/JavaScript/CSS שיהיה יפה מדליק וכיפי לתלמידים

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


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

בנה מודול לימוד אינטרקטיבי בסגנון Khan Academy על ״מבנה asyncio בפייתון״
במודול לומדים איך עובד asyncio ומה זה mainloop ואיך בונים אותו מאפס.

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

בנה את זה בתור artifact עם HTML/JavaScript/CSS שיהיה יפה מדליק וכיפי לתלמידים

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

שים לב:

1. המודול צריך להיות פשוט. לא להשתמש במילים מתוך async/await עצמה אלא להראות קודם איך בונים כל מושג מתוך מושגים בסיסיים יותר. אני רוצה להתמקד בפיתוח אינטואיציה לגבי asyncio יותר מאשר היכרות עם הפרטים הטכניים שלו
2. המודול צריך ללמד צעד צעד איך בונים mainloop ופונקציות אסינכרוניות ואיך החלקים מתחברים. אפשר להישאר רק עם sleep בתור פעולה לא צריך עבודת רשת בינתיים.


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

https://claude.ai/artifact/S9H8oUouBggjmBizAn6cJF

מוסר ההשכל היותר חשוב הוא שבתור מרצה לייצר כזאת חווית למידה לפני 5 שנים היה לי מאוד קשה ולא פרקטי. אנשים עשו את זה, אני זוכר משחקי לימוד ל CSS Flexbox ו Grid שמאוד אהבתי אבל זה היה בשוליים. רוב הזמן למדנו דרך קריאת קוד ואיפיון ותשומת לב לפרטים כי הם באמת היו מאוד חשובים. היום המשחק השתנה ואני חושב שכדאי להתרגל גם ללמוד אחרת.
👍1
📌 בטח שקוד יכול להיות יפה

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

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

1. סלאק שולח בהודעה רק מזהה משתמש. הצגת השם דורשת פעולה נוספת מול סלאק של "קריאת שם המשתמש" ודורשת הרשאה גדולה יותר מהאפליקציה. מה עושים עם אפליקציות קיימות? מה אם משתמשים מסוימים יעדיפו לא לתת יותר הרשאות רק בשביל להציג שמות?
2. מתי פונים לסלאק כדי לקבל את שם המשתמש - מיד כשמקבלים הודעה? אולי קצת אחרי שנכנסת הודעה? אולי רק כשמישהו רוצה לקרוא את ההודעות וצריך את המידע?
3. איפה שומרים את המיפוי ממזהים לשמות משתמשים - נשמור אותם בבסיס הנתונים או במיפוי זמני? ואם בבסיס הנתונים איך נדע כשמישהו שינה לעצמו את השם? אם במיפוי זמני לכמה זמן נשמור את המידע?
4. המערכת יכולה לדבר עם משתמשים גם בטלגרם אבל שם כל הודעה מתקבלת עם שם השולח. אם מגיעה הודעה חדשה בטלגרם עם מזהה משתמש שאנחנו כבר מכירים אבל שם אחר צריך לעדכן את ההודעות הישנות מאותו שולח לשם החדש?

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

ריילס שחררו גרסה שמתקנת 21 בעיות אבטחה השבוע:
https://rubyonrails.org/2026/11/4/Rails-8.0.5.2-and-8.1.4.1-have-been-released

אלפין לינוקס היה פתוח לכניסה לכל אחד בעשר השנים האחרונות פשוט על ידי הכנסת סיסמה ארוכה מ 256 תווים:
https://sshhole.com

באג בספריה בשם ברוטלי אפשר לכל אחד להיכנס להמון שרתי לינוקס באמצעות הרצת סקריפט פשוט:
https://ubuntu.com/security/CVE-2026-111497

כל זה רק כמה ימים אחרי שהתגלה PHP2Shell אוסף חולשות בליבה של PHP ששוב אפשרו השתלטות מלאה על שרתים שמריצים PHP:
https://www.php2shell.com

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

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