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

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

כל יצרן והסקילז שלו

31/03/2026

למינימקס יש ריפו של סקילז למודל שלהם: https://github.com/MiniMax-AI/skills

זה של אנטרופיק: https://github.com/anthropics/skills

זה של OpenAI: https://github.com/openai/skills

וכמובן של Gemini: https://github.com/google-gemini/gemini-skills

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

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

Copy

1. Write in product language, not design commentary.
2. Let the headline carry the meaning.
3. Supporting copy should usually be one short sentence.
4. Cut repetition between sections.
5. Do not include prompt language or design commentary into the UI.
6. Give every section one responsibility: explain, prove, deepen, or convert.

If deleting 30 percent of the copy improves the page, keep deleting.

לעומתם אנטרופיק מתארים לנו פרומפט הרבה יותר פתוח ויצירתי:

Design Thinking

Purpose: What problem does this interface solve? Who uses it?
Tone: Pick an extreme: brutally minimal, maximalist chaos, retro-futuristic, organic/natural, luxury/refined, playful/toy-like, editorial/magazine, brutalist/raw, art deco/geometric, soft/pastel, industrial/utilitarian, etc. There are so many flavors to choose from. Use these for inspiration but design one that is true to the aesthetic direction.
Constraints: Technical requirements (framework, performance, accessibility).
Differentiation: What makes this UNFORGETTABLE? What's the one thing someone will remember?

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

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

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

ומי יפתח את הריאקט הבא?

30/03/2026

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

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

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

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

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

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

אני חושב שיש פה 3 תשובות אפשריות:

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

  2. נגלה בינה מלאכותית חכמה יותר מ LLM-ים והיא תמציא את הדור הבא של שפות תכנות.

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

קידוד עם AI משנה את סדר העבודה (וזה חלק מהקושי)

29/03/2026

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

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

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

https://github.com/ynonp/langlets-rails/blob/main/app/controllers/reviewlessonscontroller.rb

וזה הקובץ המקורי שטיפל במשתמשים שפשוט תרגלו את השיעור:

https://github.com/ynonp/langlets-rails/blob/main/app/controllers/lessons_controller.rb

וקל לראות שיש המון קוד משותף בין שני הקבצים האלה.

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

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

  1. תאר מה עושה קובץ א
  2. תאר מה עושה קובץ ב
  3. הסבר מהם כל התהליכים שמבוצעים בפונקציה X בקובץ א ובקובץ ב, ואיזה מהם משותפים לשני הקבצים?
  4. סדר מחדש את הקוד של פונקציה X ופצל אותו לפונקציות קטנות יותר כדי שנוכל לראות מה התפקיד של כל חלק

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

חדש בפייתון InterpreterPoolExecutor

28/03/2026

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

from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor, InterpreterPoolExecutor
import math
import time

def is_prime(n: int):
    for i in range(2, math.floor(math.sqrt(n)) + 1):
        if n % i == 0:
            return False

    return True

if __name__ == "__main__":
    t0 = time.time()
    with ThreadPoolExecutor(max_workers=4) as p:
        print(sum(p.map(is_prime, range(1_000_000))))
    t1 = time.time()

    with ProcessPoolExecutor(max_workers=4) as p:
        print(sum(p.map(is_prime, range(1_000_000))))
    t2 = time.time()

    print(f"Thread count took {t1-t0}")
    print(f"Process count took {t2 - t1}")

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

  1. אין הפרדה בין האוביקטים - כלומר קוד מכל threads יכול לגשת ולעדכן אוביקטים גלובאליים.

  2. גרסאות רבות של פייתון מגיעות עם Global Interpreter Lock מה שאומר שכל פעולה של פייתון בתוך ה thread צריכה לנעול את אותו מנעול גלובאלי.

גרסה 3.14 של פייתון הוסיפה פתרון ביניים שנקרא InterpreterPoolExecutor. מבצע זה יריץ כל משימה במפרש פייתון עצמאי שרץ ב thread נפרד, כלומר במקום להפעיל fork ולייצר תהליך מערכת הפעלה חדשה למפרש החדש הם מריצים את המפרש באותו תהליך. התוצאה היא הפרדה מלאה בין משתנים כי לכל מפרש יש את המשתנים הגלובאליים שלו, הפרדה בנעילות כי לכל מפרש יש את ה GIL שלו ועדיין ריצה יותר מהירה כי אנחנו רצים ב threads במקום ב processes. כמה יותר מהיר? זה מה שלקח לספור מספרים ראשוניים אצלי על המק:

Thread count took 6.0312182903289795
Process count took 80.60068678855896
Interpreter count took 24.76494789123535

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

הטעות של מפתחים שעוברים בין שפות

27/03/2026

כמה זמן באמת לוקח לעבור מפייתון ל Java? מפייתון לרובי? האם הגיוני לגייס מפתח עם נסיון ב Rust לעבודת Java או להיפך?

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

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

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

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

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

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

תרגיל vue.js - מה שבור בקומפוננטה

26/03/2026

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

מוכנים? הנה קוד קומפוננטת vue.js שאמורה להציג קוד צבוע אבל מתעלמת מפרמטר השפה שאני מעביר לה ותמיד מריצה זיהוי אוטומטי:

import { ref, h, computed, defineComponent, Plugin, watch } from 'vue'
import hljs from 'highlight.js/lib/core'
import { escapeHtml } from './lib/utils'

const component = defineComponent({
    props: {
        code: {
            type: String,
            required: true,
        },
        language: {
            type: String,
            default: '',
        },
        autodetect: {
            type: Boolean,
            default: true,
        },
        ignoreIllegals: {
            type: Boolean,
            default: true,
        },
    },
    setup(props) {
        const language = ref(props.language)
        watch(() => props.language, (newLanguage) => {
            language.value = newLanguage
        })

        const autodetect = computed(() => props.autodetect || !language.value)
        const cannotDetectLanguage = computed(() => !autodetect.value && !hljs.getLanguage(language.value))

        const className = computed((): string => {
            if (cannotDetectLanguage.value) {
                return ''
            } else {
                return `hljs ${language.value}`
            }
        })

        const highlightedCode = computed((): string => {
            // No idea what language to use, return raw code
            if (cannotDetectLanguage.value) {
                console.warn(`The language "${language.value}" you specified could not be found.`)
                return escapeHtml(props.code)
            }

            if (autodetect.value) {
                const result = hljs.highlightAuto(props.code)
                language.value = result.language ?? ''
                return result.value
            } else {
                const result = hljs.highlight(props.code, {
                    language: language.value,
                    ignoreIllegals: props.ignoreIllegals,
                })
                return result.value
            }
        })

        return {
            className,
            highlightedCode,
        }
    },
    render() {
        return h('pre', {}, [
            h('code', {
                class: this.className,
                innerHTML: this.highlightedCode,
            }),
        ])
    },
})

const plugin: Plugin & { component: typeof component } = {
    install(app) {
        app.component('highlightjs', component)
    },
    component,
}

export default plugin

רואים את הבעיה? התשובה בשורה 30:

const autodetect = computed(() => props.autodetect || !language.value)

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

autodetect: {
    type: Boolean,
    default: true,
},

כלומר אם אני לא מעביר ערך false בצורה מפורשת לאותו autodetect ברירת המחדל שלו היא לזהות לבד את השפה ולהתעלם מערך ה language שהעברתי.

הסיבה שאני נתקעתי על הסיפור הזה יותר מדי זמן היא דף התיעוד של הספריה שמציג את הדוגמה הבאה:

<div id="app">
    <!-- bind to a data property named `code` -->
    <highlightjs autodetect :code="code" />
    <!-- or literal code works as well -->
    <highlightjs language='javascript' code="var x = 5;" />
</div>

שכמובן עובדת רק בגלל ש highlightjs מצליח לזהות אוטומטית בדיוק את אותה שפת javascript שמוגדרת ב language.

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

מי שלא נפגע מטריוי

25/03/2026

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

https://github.com/aquasecurity/trivy/security/advisories/GHSA-69fq-xp46-6x23

מה שמעניין בסיפור הוא לא מי שנפגע אלא מי שלא נפגע. מתוך הדיווח אנחנו לומדים שלא נפגעו מי שהשתמשו ב trivy images referenced by digest - אבל מה זה אומר? ולמה גרסאות ה digest היו חסינות?

מאגר החבילות של טריוי מכיל את רשימת האימג'ים שהם פרסמו עם תגיות כמו canary, latest, 0.69.3 ותגיות ארוכות יותר שמתחילות ב sha256 כמו sha256:b39e145284f15252b2135abe0e24509d7ad2459d28c18f014e478c6ca0aee533.

כשאנחנו מריצים docker run aquasec/trivy אנחנו מריצים את הגרסה שיש עליה את התג latest. ואם נריץ docker run aquasec/trivy:canary נריץ את הגרסה המתויגת canary. וכמו שבטח הבנתם אם נפעיל:

docker run ghcr.io/aquasecurity/trivy:sha256-bcc376de8d77cfe086a917230e818dc9f8528e3c852f7b1aff648949b6258d1c

נריץ את הגרסה עם התג הארוך.

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

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

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

לפני חודש זה עבד

24/03/2026

כמה תקלות שתיקנתי ללקוחות בתקופה האחרונה, כולן בקטגוריית "זה עבד לפני חודש ומאז לא נגענו"-

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

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

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

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

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

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

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

מ MCP ל Skills

23/03/2026

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

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

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

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

נפתח תיקיה חדשה ~/.claude/skills:

mkdir -p ~/.claude/skills/npm-search

בתוך התיקייה אני יוצר קובץ בשם SKILL.md עם התוכן הבא:

  ---
  name: npm-search
  description: Use this skill whenever implementing a feature or adding functionality to a JavaScript/TypeScript/Node.js project. Before writing custom code, always run npm search to find existing libraries that can solve the problem. This prevents reinventing the wheel and leverages the npm ecosystem.
  ---

  # NPM Search Guide

  ## Overview

  Before implementing any feature in a JavaScript/TypeScript/Node.js project, search npm for existing libraries that can solve the problem. This ensures you leverage the ecosystem rather than reinventing the wheel.

  ## When to Search npm

  Use npm search before implementing:
  - Data processing or transformation utilities
  - HTTP clients or API helpers
  - Date/time manipulation
  - Validation libraries
  - Authentication/authorization
  - File handling (CSV, JSON, XML, PDF, etc.)
  - Database connectors
  - Testing utilities
  - UI components (for frontend projects)
  - Any common utility or pattern

  ## Running npm Search

  Use the provided script to search for packages:

  ```bash
  ./scripts/npm-search.sh <search-term>

Or run directly: bash npm search

### Example Searches

  # Looking for a date library
  ./scripts/npm-search.sh date format manipulate

  # Looking for a validation library
  ./scripts/npm-search.sh schema validation zod joi

  # Looking for an HTTP client
  ./scripts/npm-search.sh http client axios fetch

  # Looking for a CSV parser
  ./scripts/npm-search.sh csv parse stream

## Evaluating Packages

When reviewing search results, consider:

  1. Downloads: Higher weekly downloads indicate community trust
  2. Version: Recent versions suggest active maintenance
  3. Description: Clear descriptions indicate well-documented packages
  4. Dependencies: Fewer dependencies mean smaller bundle size

## Installation

Once you've identified a suitable package:

  npm install <package-name>
  # or
  pnpm add <package-name>
  # or
  yarn add <package-name>

## Implementation

After installation, read the package's README or documentation before using it. Look for: - Basic usage examples - Configuration options - Common patterns and best practices ```

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

לסיום אני יוצר סקריפט בשם scripts/npm-search.sh בתוך אותה תיקייה עם התוכן הבא:

#!/bin/bash
# npm-search.sh - Search npm for packages
# Usage: ./scripts/npm-search.sh <search-terms>

if [ $# -eq 0 ]; then
    echo "Usage: $0 <search-terms>"
    echo "Example: $0 date format manipulate"
    echo "         $0 csv parse stream"
    exit 1
fi

SEARCH_QUERY="$*"

echo "🔍 Searching npm for: $SEARCH_QUERY"
echo "----------------------------------------"

npm search "$SEARCH_QUERY"

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

סך הכל הסקיל מורכב משני הקבצים:

ynonp@ynons-MacBook-Air ~/.claude/skills/npm-search (main?) $ tree
.
├── scripts
│   └── npm-search.sh
└── SKILL.md

2 directories, 2 files

שיפור לעומת MCP? בהחלט:

  1. קל יותר לכתיבה - כל הטקסטים יושבים בקובץ markdown מסודר במקום בתיאור של tool-ים. סקריפטים יכולים להיכתב בכל שפה ואפילו אפשר לשלב מספר שפות.

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

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

https://github.com/anthropics/skills

או במאגר הסקילים של קודקס:

https://github.com/openai/skills/tree/main/skills/.curated

אגב מבחינת ראנרים אחרים אז גם קופיילוט וגם opencode יקראו סקילז מאותה תיקיית ~/.claude/skills. קודקס יחפש אותם ב ~/.codex/skills.

געגועים לספריות קוד פתוח

22/03/2026

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

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

מה הפסדנו פה? אני לא בטוח. שלחתי את לאבבל לבנות לי משחק תרגול צלילים בגיטרה. זה כאן אם אתם רוצים לנסות. המעניין שם זה שאת צוואר הגיטרה לאבבל צייר לבד באמצעות SVG. בעולם הישן ציור צוואר גיטרה ב SVG היה בעיניי האופציה האחרונה. קודם הייתי מחפש ספריית קוד פתוח ובמקרה הגרוע מצייר את זה ב HTML ו CSS. הסוכן יצר קומפוננטה של גיטרה שנראית ממש אחלה ועובדת עבור המשחק לא פחות טוב מ react-fretboard או react-guitar, עם קוד ציור יפה ב SVG. אפשר לראות את הקוד שלו כאן:

https://github.com/ynonp/fret-play-learn/blob/main/src/components/GuitarFretboard.tsx

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

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