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

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

ממובן למובן מאליו

23/02/2026

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

כשמשהו מובן מאליו זה אומר שהוא מובן ללא כל הסבר נוסף או ללא כל מאמץ נוסף. אי אפשר להתכחש למובנות שלו.

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

def print_fibonacci():
    first = 0
    second = 1
    count = 2  # We already have two elements: 0 and 1

    while count < 10:
        next_num = first + second
        sequence.append(next_num)
        first, second = second, next_num
        count += 1

    print(' '.join(map(str, sequence)))

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

והנה מינימקס פותר את אותה בעיה:

def print_fibonacci(count=10):
    a, b = 0, 1          # start with the first two numbers
    for _ in range(count):
        print(a, end=' ')
        a, b = b, a + b # move to the next pair
    print()              # final newline

גם הוא מעמיס הערות אבל הפעם ברור שאין בהן צורך. את התבנית:

a, b = b, a + b

מכיר כל מי שכתב פיבונאצ'י בפייתון.

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

יש לי הזדמנות

22/02/2026

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

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

במקום לחפש "איפה ה AI פספס" נחפש "איך הקוד החדש פותר את הבעיה"

במקום לחפש "מה ה AI לא ראה" נשאל "מאיפה התבנית הזאת הגיעה?"

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

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

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

כזה ניסיתי: Opencode ומודלי קוד פתוח מ Ollama

21/02/2026

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

  1. Droid
  2. Opencode
  3. Kilocode
  4. Aider
  5. Cline
  6. Roo Code
  7. Claude Code

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

המשך קריאה

עולם ללא קוד

20/02/2026

כבר היום אני לא בטוח שכדאי לאנשים ללמוד את החשיבות של HTML סמנטי, את ההבדלים בין section ל article ומתי להשתמש ב nav במקום ב div. אם זה חשוב אנחנו מצפים ש AI ישתמש בזה כשנבקש ממנו לכתוב HTML.

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

מה לגבי node.js ואקספרס? או ראסט? או Java?

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

הנה מה שכתב rupayanc ברדיט בנוגע ל PR-ים שהוא מקבל על פרויקטי קוד פתוח שלו:

The other half compile but introduce subtle bugs because the model doesn't understand the actual design constraints of the project.

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

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

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

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

כשהקוד הופך זול מאוד אין צורך להבין תחביר. לא צריך לדעת לקרוא מבנה של List Comprehension בפייתון או מה ההבדל בין פונקציה אנונימית לפונקציית חץ ב JavaScript.

אני מבין מה עשית שם

19/02/2026

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

הנה רובי:

def create_connection
  Bunny.new(@connection_config[:url]).tap(&:start)
end

הפונקציה פותחת חיבור ל Rabbitmq ומחזירה את החיבור שנפתח. נתעלם רגע מהשאלה אם צריך פונקציה בשביל זה (אני חושב שלא), אבל השאלה היותר חשובה היא מה ה tap עושה שם? הנה הקוד בצורה הכי מפורשת שלו:

def create_connection
  conn = Bunny.new(@connection_config[:url])
  conn.start
  return conn
end

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

def create_connection
  Bunny.new(@connection_config[:url]).start
end

אז הפונקציה היתה מחזירה את מה ש start מחזירה ואולי זה משהו אחר ממה ש new מחזירה. פה המקום לשים לב לנטיה של AI לעבוד בתבניות - קלוד לא בדק מה start מחזירה. אם הוא היה בודק הוא היה רואה שהיא מחזירה בדיוק את אוביקט החיבור כי מי שכתב את Bunny כבר חשב על מנגנון הקריאה הזה. כלומר ה tap מיותר לגמרי שם.

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

ואז ניסיתי לשכנע את ChatGPT לכתוב קוד יעיל

18/02/2026

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

write a python function that takes 2 arrays and returns the items from first array that are not in the second array (array diff)

וקיבלתי אחלה פתרון:

def array_diff(arr1, arr2):
    """
    Returns items from arr1 that are not in arr2.
    Preserves order and duplicates from arr1.
    """
    set2 = set(arr2)  # Convert to set for faster lookups (O(1))
    return [item for item in arr1 if item not in set2]

כולל הערה שמסבירה שהוא ממיר את המערך ל set בשביל שיהיו לו חיפושים מהירים. ממש אפשר לדמיין שהקוד רץ ב O(1) עד שנזכרים שלהפוך מערך ל set גם לוקח זמן.

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

I think for small arrays it will be faster to just run the nested loop

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

now combine the two - if the input is small use nested loop and if it's large use the set

וכמובן AI כמו AI מצליח לקחת כל רעיון טוב ולשבור אותו, הנה הקוד שהוא יצר:

def array_diff(arr1, arr2, threshold=50):
    """
    Returns items from arr1 that are not in arr2.

    - Uses nested lookup for small inputs.
    - Uses set-based lookup for larger inputs.
    - Preserves order and duplicates from arr1.

    threshold: size of arr2 below which nested lookup is used.
    """

    # If arr2 is small, avoid set overhead
    if len(arr2) <= threshold:
        result = []
        for item in arr1:
            if item not in arr2:
                result.append(item)
        return result

    # Otherwise use set for faster lookups
    set_arr2 = set(arr2)
    return [item for item in arr1 if item not in set_arr2]

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

היום למדתי: Temporal נכנס לעשות סדר בתאריכים ב JavaScript

17/02/2026

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

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

Temporal.Now.instant()

ולקבל אוביקט עם epochMilliseconds ו epochNanoseconds. מחרוזת של תאריך ושעה אנחנו מקבלים מ:

Temporal.Now.instant().toString()

בפורמט:

'2026-02-16T13:21:55.963Z'

ואם אנחנו צריכים אזור זמן אחר אפשר להמיר:

Temporal.Now.instant().toZonedDateTimeISO('UTC').toString()
15:25:11.803 '2026-02-16T13:25:11.801+00:00[UTC]'
15:25:13.784 Temporal.Now.instant().toZonedDateTimeISO('Europe/Paris').toString()
15:25:13.788 '2026-02-16T14:25:13.785+01:00[Europe/Paris]'
15:25:15.889 Temporal.Now.instant().toZonedDateTimeISO('America/New_York').toString()
15:25:15.892 '2026-02-16T08:25:15.89-05:00[America/New_York]'
15:25:21.326 Temporal.Now.instant().toZonedDateTimeISO('Asia/Jerusalem').toString()
15:25:21.337 '2026-02-16T15:25:21.328+02:00[Asia/Jerusalem]'

אפשר גם להוסיף או להפחית זמנים למשל:

Temporal.Now.plainDateISO().add({days: 2}).toString()
Temporal.Now.plainDateISO().subtract({days: 2}).toString()

Temporal.Now.plainTimeISO().add({seconds: 30})

דף התיעוד עמוס בפיצ'רים ושווה להעיף מבט אם אתם מחפשים להיפרד מ moments או days בקוד חדש שכותבים:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal

מתנות חינם

16/02/2026

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

בעולם של ספריות לפיתוח סוכנים חכמים המשחק שונה לגמרי: הממשק מול המודל מתפתח כל הזמן, אגרגטורים כמו Bedrock, Open Router ו Copilot Models עוטפים את ה API הבסיסי ויכולים לספק פונקציונאליות נוספת או כפולה, סביבות להרצת סוכנים כמו Vertex AI Engine או Agent Core מספקות עוד יכולות וכל אלה משתנים כל הזמן. כך יש לנו היום כלים מובנים בתוך ה API של OpenAI, כלים מובנים ב AgentCore, שער של אייג'נט קור להרצת כלים או חיבור שרתי MCP וספריית פיתוח סוכנים שבעצמה מתחברת לשרתי MCP.

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

ומתוך הבנה של תנאי העבודה השונים כדאי לאמץ גישה שונה למתנות שאנחנו מקבלים מכל עולם:

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

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

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

השאלה היא לא כמה אחוז מהקוד ה AI כותב

15/02/2026

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

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

הנה כמה מטריקות טובות יותר לשילוב AI במהלך הפיתוח:

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

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

אם ה AI כתב 100% או 80% מהקוד זה לא הדבר החשוב, מה שחשוב זה איך אנחנו עובדים היום ואיך תהליך העבודה השתפר בזכות שימוש בכלי AI.

הגדרת תלויות ב docker-compose עלולה להסתיר באג במערכת

14/02/2026

נתבונן בדוקר קומפוז הבא:

services:
  db:
    image: postgres:15
    container_name: my_postgres

  api:
    build: ./api
    container_name: my_api
    depends_on:
      - db

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

אבל בעצם... למי אכפת מה עולה קודם?

אם שרת ה API מנסה לעשות משהו עם בסיס הנתונים ולא מצליח הוא צריך להציג שגיאה. כשבסיס הנתונים יעלה ה API יחזור לעבוד. מה עוזר ה depends_on כאן?

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