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

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

ואז זה עבד

18/07/2025

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

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

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

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

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

ספירת שורות בקובץ בפייתון

17/07/2025

הסיפור היום מתחיל כשביקשתי מ ChatGPT להדפיס פונקציה שסופרת כמה שורות יש בקובץ:

def count_lines(filepath):
    with open(filepath, 'r') as f:
        return sum(1 for _ in f)

אבל - איך זה עובד? בואו נפרק את הקוד יחד.

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

>>> open('/etc/passwd', 'r')
<_io.TextIOWrapper name='/etc/passwd' mode='r' encoding='UTF-8'>

פקודת open מחזירה TextIOWrapper. שתי פונקציות העטיפה שלו הן:

>>> f.__enter__
<built-in method __enter__ of _io.TextIOWrapper object at 0x100e879f0>

ו:

>>> f.__exit__
<built-in method __exit__ of _io.TextIOWrapper object at 0x100e879f0>

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

>>> f=open('/etc/passwd', 'r')
>>> f.__exit__()
>>> f.read()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: I/O operation on closed file.

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

>>> (1 for _ in f)
<generator object <genexpr> at 0x101013ed0>

אם אמרנו ש f הוא TextIOWrapper, אז פקודת for ... in f היא פקודת יצירת גנרטור. היא עדיין לא מפעילה שום לולאה על הקובץ אלא רק מחזירה אוביקט שיודע "לעשות משהו" עם השורות שבקובץ:

>>> f=open('/etc/passwd', 'r')
>>> g=(1 for _ in f)
>>> next(g)
1
>>> next(g)
1
>>> next(g)
1

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

>>> g=(line for line in f)
>>> next(g)
'# Note that this file is consulted directly only when the system is running\n'
>>> next(g)
'# in single-user mode.  At other times this information is provided by\n'
>>> next(g)
'# Open Directory.\n'

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

השורה המלאה:

return sum(1 for _ in f)

מפעילה את sum על גנרטור. זה מעניין! אנחנו רגילים להפעיל sum על רשימות:

>>> sum([10, 20, 30, 40])
100

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

>>> f=open('/etc/passwd', 'r')
>>> g=(1 for line in f)
>>> line_count = 0
>>> for value in g:
...     line_count += 1
...
>>> line_count
140

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

def count_lines(filepath):
    with open(filepath, 'r') as f:
        line_count = 0
        for line in f:
            line_count += 1
        return line_count

הגנרטור אפשר לארגן מחדש את המבנה בצורה שיותר מתאימה ל sum וכך הצלחנו לכתוב:

def count_lines(filepath):
    with open(filepath, 'r') as f:
        return sum(1 for _ in f)

כי האיטרציה מבוצעת בתוך הפונקציה sum.

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

מעבר לקופיילוט - מה זה אומר להטמיע AI בארגון פיתוח?

16/07/2025

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

  1. איך משלבים כל כך הרבה PR-ים לגירסה? מתי מעלים גירסה? מה צריכות להיות דרישות הקבלה ומה התכולה?

  2. מיומנות גיט - איך מנווטים בין כל ה PR-ים? איך מבטלים PR אחרי ששילבתי אותו? איך מוציאים תיקון לגירסה ישנה?

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

  4. מיומנות תשתית - איך לארגן את הקוד כדי שסוכן קוד יוכל לעבוד עליו בענן?

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

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

יבוא מושהה בטייפסקריפט 5.9 הוא אחד השיפורים המלהיבים בשפה

15/07/2025

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

  1. עם השנים קוד JavaScript רק מתארך.

  2. לא רק שקשה להוריד קוד JavaScript ארוך מהשרת (כי הקובץ יותר גדול) אלא שהרצה ופיענוח של קוד כזה מכבידים על הדפדפן.

  3. אחרי שכתבת את הקוד קשה להחליף מ import רגיל ל import דינמי, בגלל שזה יכריח אותך לשנות את כל שרשרת הקריאות לקריאות עם await.

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

Copy
// ./some-feature.ts
initializationWithSideEffects();

function initializationWithSideEffects() {
  // ...
  specialConstant = 42;

  console.log("Side effects have occurred!");
}

export let specialConstant: number;

והקוד שמשתמש בו:

import defer * as feature from "./some-feature.js";

// No side effects have occurred yet

// ...

// As soon as `specialConstant` is accessed, the contents of the `feature`
// module are run and side effects have taken place.
console.log(feature.specialConstant); // 42

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

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

דף הפרסום המלא של טייפסקריפט 5.9 בטא זמין כאן לסקרנים: https://devblogs.microsoft.com/typescript/announcing-typescript-5-9-beta/

מימוש משחק סנייק עם AI (טייק 2)

14/07/2025

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

המשך קריאה

ואולי AI בכלל מאט אותך?

13/07/2025

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

התוצאות מעניינות ובמספר מימדים:

  1. גם לפני וגם אחרי המחקר המפתחים הרגישו שהם עבדו יותר מהר עם AI.

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

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

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

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

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

שטויות שלקח לי יותר מדי זמן להבין על LangGraph

12/07/2025

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

  1. כדאי להתחיל עם LangChain. זה לא אחד במקום השני אלא שאחד מרחיב את השני.

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

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

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

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

  6. אפשר וכדאי להשתמש ב State Class שונה לכל נוד (וכך פלט של נוד אחד הוא הקלט של הנוד הבא). את הסטייט אפשר לכתוב בתור TypedDict או pydantic. אני מעדיף pydantic.

  7. תחברו את LangSmith. זה שווה את השתי לחיצות.

  8. כל קריאה ל graph.stream שולחת את הסטייט הראשוני למסע בגרף ומסתיימת כשהגרף מסתיים עם הסטייט מהנוד האחרון.

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

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

להביא את הפיצה

11/07/2025

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

  1. הגדרת יעדים ברורים - איך נראית הצלחה.

  2. שיפור היכולות - איך אפשר לעשות יותר עם הצוות והמשאבים הקיימים.

  3. שיפור המערכת - זיהוי הזדמנויות "להוריד עלויות" ולשפר תהליכים.

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

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

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

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

  3. שיפור תהליכים מערכתיים - זיהוי תבניות בעייתיות בקוד ש AI מייצר, ריפקטורינג של המערכת כדי של AI יהיה יותר קל, בניית AI Friendly Codebase, שיפור הבדיקות.

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

שקרן שקרן

10/07/2025

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

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

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

גם את זה נצטרך לשנות.

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

הטמעת AI במוצר קיים

09/07/2025

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

המשך קריאה