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

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

טיפ גיט: שינוי מקומי בלי קומיט על קבצים במעקב

21/01/2026

אתם כבר מכירים את gitignore ואת .git/info/exclude וזוכרים את הבעיה המעצבנת בשניהם: מנגנון ההתעלמות מאפשר להתעלם מקבצים קיימים על הדיסק שאינם בריפו. אבל מרגע שקובץ נמצא בריפו לא משנה כמה פעמים תכתבו אותו ב gitignore השינויים בו תמיד יופיעו ב status. קובץ שנמצא במעקב עוקף את ה gitignore.

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

התשובה נקראת skip worktree bit ואפשר לקרוא עליה בדף התיעוד man git-update-index. בקצרה זה מתג שנשמר מקומית אצלכם ואומר לגיט לשמור על השינויים המקומיים שלכם כל עוד אפשר. אנחנו מדליקים אותו לקובץ מסוים עם:

git update-index --skip-worktree docker-compose.yml

ומבטלים עם:

git update-index --no-skip-worktree docker-compose.yml

דוגמה? בטח. ניצור ריפו עם שני קבצים:

$ git init .
$ date > a.txt
$ date > b.txt
$ git add .
$ git commit -m 'initial commit'

עכשיו נשנה את b.txt ונראה בסטטוס את השינוי:

$ date > b.txt
ynonp@ynons-MacBook-Air ~/tmp/blog/skipworktree (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)
        modified:   b.txt

no changes added to commit (use "git add" and/or "git commit -a")

נדליק את skip worktree bit:

$ git update-index --skip-worktree b.txt
ynonp@ynons-MacBook-Air ~/tmp/blog/skipworktree (main) $ git status
On branch main
nothing to commit, working tree clean

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

$ git restore b.txt
error: pathspec 'b.txt' did not match any file(s) known to git

ב ls-files לעומת זאת הקובץ כן מופיע:

$ git ls-files
a.txt
b.txt

ואם נוסיף -v נוכל לראות שהוא במצב S כלומר skip-worktree:

$ git ls-files -v
H a.txt
S b.txt

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

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

מינימליזם לא אומר באגים

20/01/2026

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

איך ניגשים לזה?

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

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

I'm building a TODO editor allowing users to create todos items, edit todos, delete todos and reorder todos in the list with optimistic updates.

When users perform multiple actions before server had a chance to update the system has strange bugs, for example: 

1. trying to edit a todo that wasn't yet created 2. trying to reorder todos when server state is different than the optimistic state

Suggest 4 possible architectures to combine optimistic updates and editing, order from simple to complicated. For each architecture explain what API calls are made and when and how it deals with user editing faster than server updates

ואתם יכולים לראות את השיחה כאן: https://chatgpt.com/share/696e35f8-9d68-8009-a35a-26169c8ccbe9

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

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

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

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

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

  4. הנאה - אין הרבה כיף בלכתוב פתרון עם באגים שעובד פחות טוב ממה ש AI היה כותב או להגיד ל AI "טוב תבנה את הדבר הכי פשוט" ולהגיש.

אם אין לכם זמן לכתוב מימוש נכון, איפה תמצאו זמן לכתוב את המימוש פעמיים?

שיחות הזויות עם AI (חלק 28)

19/01/2026

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

רגע, מה?

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

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

חיפוש פוסטים דומים עם Embeddings

18/01/2026

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

המשך קריאה

דברים שקרסר לא הציע למיכאל

17/01/2026

חבר כתב בפייסבוק

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

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

לקחים? אני לא בטוח, הנה כמה מחשבות שלי אחרי הקריאה. לא ראיתי את הפרויקט או את התיקונים של קרסר:

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

  2. רק בגלל שמישהו מפרסם שקרסר הצליח להביא את האתר שלו לציון 100 ב Lighthouse לא אומר שהאתר שלו נטען יותר מהר או שאתם יכולים להגיע לתוצאה דומה על האתר שלכם. בביצועים יש כלל שהרבה יותר קל להגיע לשיפור של 90% מאשר לשיפור של 3% כי אם הורדת את זמן הטעינה ב 90% הקוד המקורי היה די גרוע. בדיקת ביצועים אמיתית דורשת שמירת זמני טעינה של גולשים אמיתיים וניתוח לאורך זמן.

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

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

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

מה הניסוי של קרסר מוכיח?

16/01/2026

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

זה הריפו של הדפדפן שהם יצרו ללא מגע יד אדם: https://github.com/wilsonzlin/fastrender

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

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

fix: resolve merge markers and restore vm-js build
- Remove unresolved merge conflict markers across fastrender + vendored vm-js.
- Fix vm-js exec.rs issues uncovered after cleanup (async yield* arm, NamedEvaluation super prop, unused binding).
- Drop duplicate Range native getter in window_realm.rs (required by conflict-marker guard).

This keeps scripts/check_no_conflict_markers.sh and  passing.

השינוי בקוד הוא שינוי שם של משתנה בקובץ אחד, במקום לקרוא למשתנה expr קראו לו _expr. אני לא יודע איך שינוי הקוד הזה קשור להודעת הקומיט או אם באמת היה או לא היה צורך באיזשהו תיקון.

אבל זה לא מה שחשוב.

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

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

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

טיפ ריילס: מתי להוסיף את שם הטבלה ל Scope

15/01/2026

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

scope :latest, -> { order(created_at: :desc) }

ואז פקודת ה order by תצורף לשאילתה. עד לפה הכל קל, עכשיו נסתכל על סקופ יותר מסובך:

scope :with_questions, ->() {
  where("questions is not null and cardinality(questions) > 0")
}

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

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

MyModel.joins(:other_table).with_questions

ונדמיין שגם ל other_table יש עמודה בשם questions. עכשיו מקבלים את ה SQL:

SELECT "my_models".* FROM "my_models"
INNER JOIN "other_table" ON "other_table".my_model_id = "my_models".id
WHERE questions IS NOT NULL AND cardinality(questions) > 0

ואם לשתי הטבלאות יש עמודת questions נקבל שגיאה:

ERROR:  column reference "questions" is ambiguous

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

scope :with_questions, ->() {
  where("quizzes.questions IS NOT NULL AND cardinality(quizzes.questions) > 0")
}

בואו נלמד Git Worktree בעזרת AI

14/01/2026

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

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

המשך קריאה

השתמשו ב AI כמו בוס

13/01/2026

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

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

  2. האפשרות שתוביל לאבדון - לבקש מ AI לכתוב פיצ'ר שאתם צריכים, לנסות להבין מה הוא עשה, לתקן אם זה לא עובד.

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

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

איך ללמוד תכנות בעידן ה AI

12/01/2026

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

המשך קריאה