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

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

לקחים שלמדתי על עלויות

25/11/2025

  1. לתקן קוד יותר זול מלשכתב מערכת.

  2. יותר זול לבחור שפת תכנות שאני מכיר מאשר שפת תכנות שאני רוצה ללמוד.

  3. יותר זול לבחור שפת תכנות שהרבה אנשים מכירים משפה שרק אני מכיר.

  4. מונוליט יותר זול ממיקרו סרביסס.

  5. שרת יותר זול מ Serverless.

  6. מוצר מדף בתשלום הרבה פעמים יותר זול מפתרון חינמי.

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

  8. פיתוח פתרון לבעיה שאני מכיר יותר זול מפיתוח פתרון גנרי.

  9. לעבוד נכון יותר זול מלעבוד מהר.

ומה שלכם?

אתה דווקא לא נראה כמו אחד שמשתמש ב AI

24/11/2025

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

זה יעבור.

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

Real Programmers

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

להשתמש ב AI כדי לחסוך זמן אומר שה AI יכתוב לי סקריפט שמשנה מרכאות כפולות לגרש בודד בקבצי YAML, מריץ אותו על ערימה של קבצים ואז מתקן את הסקריפט כי הוא פספס כמה מקרי קצה וממשיך באיטרציה עד שכל הקבצים נכונים. כן יכולתי לכתוב את הסקריפט הזה לבד אבל יש לי דברים יותר טובים לעשות בשעה הזאת. או למפות בכל הקודבייס איזה חלקים מפעילים פונקציה מסוימת ובאיזה תנאים היא תופעל (כי יש בדרך המון if-ים). זה גם יכול להיות לקבל הסבר על פונקציה מסוימת או צורת כתיבה מסוימת במקום ללכת לחפש בגוגל ולראות מהר חלופות שיתאימו לסטנדרטים של הקוד. כמובן לקבל תקציר של שינויים ב diff מסוים ואפילו לתרגם מ Options API ל Composition API ב vue.

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

כת הקוד הקדוש

23/11/2025

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

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

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

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

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

ואם זה נכשל?

22/11/2025

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

let (feature_values, _) = features
    .append_with_names(&self.config.feature_names)
    .unwrap();

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

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

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

if save_data(items):
    report_success()

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

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

נ.ב. זה הסיפור המלא של קלאודפלייר לסקרנים. הוא מרתק: https://blog.cloudflare.com/18-november-2025-outage/

הדברים שלא אמרתי בוובינר היום על Prompt Engineering

21/11/2025

כשתכננתי וובינר על Prompt Engineering הייתי בטוח שאדבר בעיקר על איך לבנות פרומפטים: על הערך של להזכיר למודל בהתחלה שהוא מתכנת חכם או מתרגם מוכשר, על איך כדאי לו לחשוב צעד אחרי צעד ומה האורך האידאלי של פרומפט ואם כדאי להשתמש ב Markdown או ב XML כשבונים את הפרומפט.

אבל האמת שכל אלה הם לא הדברים החשובים.

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

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

אפשר למצוא סיכום של הנקודות המרכזיות שדיברנו עליהן בוידאו סיכום כאן: https://youtu.be/TQPZZawYW34?si=EUZWzmlW-7NYh2Z2

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

https://www.tocode.co.il/talking_ai

בואו נדבר עוד פעם על הודעות קומיט

20/11/2025

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

אלה התירוצים שאני שומע הכי הרבה מחברים וחברים לעבודה:

  1. ממילא אף אחד לא יקרא את זה.

  2. זה רק לבדיקה כדי שאוכל לדחוף את השינוי.

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

והתשובות בקצרה:

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

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

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

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

יותר טוב מ ChatGPT - תרגיל שיפור קוד בפייתון

19/11/2025

נתון הקוד הבא:

import sys

def print_1(text):
    print(f"*{text}*")

def print_2(text):
    print(text)

def print_3(text):
    print(f"# {text}")

def handle(output_type, text):
    method_name = f"print_{output_type}"
    globals()[method_name](text)

if __name__ == "__main__":
    handle(*sys.argv[1:])

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

המשך קריאה

אילוצים

18/11/2025

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

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

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

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

שיחות עם AI (חלק 284)

17/11/2025

ש. שומע AI אני מנסה לכתוב את הקוד הזה ב vue אבל sass מתלונן:

<style lang="scss" scoped>
.text {
    @apply h-8 rounded-lg !px-2 z-50 bg-slate-50 dark:bg-slate-800 items-center gap-4 ml-0 mb-0 shadow-md border border-slate-75 dark:border-slate-700/50;
}

הסבר את הבעיה והצע פתרון.

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

ש. זה לא הגיוני. שם הקלאס !px-2 מגיע מטיילווינד והוא מוסיף את המאפיין important. בלעדיו זה אולי יתקמפל אבל הקוד לא יעבוד כמו שהתכוונתי.

ת. כמובן אתה צודק איך לא ראיתי את זה. אפשר במקום לפצל את השורה ולכתוב את ה important כמאפיין נפרד של padding-left כלומר:

@apply h-8 rounded-lg z-50 bg-slate-50 dark:bg-slate-800 items-center gap-4 ml-0 mb-0 shadow-md border border-slate-75 dark:border-slate-700/50;
padding-left: 0.5rem !important;
padding-right: 0.5rem !important;

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

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

מריץ כלי ...

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

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

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

ש. זה עדיין לא עובד - מקבלים את אותה שגיאה.

ת. אה ברור טוב זה בגלל שהקלאס שלך מכיל מקף ואחריו מספר וזה מבלבל את sass. אתה צריך פשוט להפסיק להשתמש בסימני קריאה בקלאסים שלך. הנה אני מחליף לך את ה !px-2 בגירסה שעובדת עם הגדרת ה important במאפיינים נפרדים.


זה היה יכול להמשך כך עוד שעות אבל האמת שהתעייפתי מהשיחה אתו. מחקתי את כל תיקיית node_modules והתקנתי הכל מחדש ו-הפתעה הכל התחיל לעבוד.

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

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

אתם לא בונים את ריילס

16/11/2025

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

import json

class BaseItem:
    def __init__(self):
        with open("settings.json", encoding="utf8") as f:
            self.settings = json.load(f)

class Item(BaseItem):
    pass

if __name__ == "__main__":
    item = Item()

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

תשומת לב לפרט הזה יכולה לחסוך הרבה כאב ראש למי שקורא את הקוד, כלומר התיקון יהיה:

import json

class BaseItem:
    def __init__(self, settings_file_path):
        with open(settings_file_path, encoding="utf8") as f:
            self.settings = json.load(f)

class Item(BaseItem):
    pass

if __name__ == "__main__":
    item = Item(settings_file_path="settings.json")

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

לפעמים אנשים שומעים את זה וחושבים "טוב אבל היופי בקוד זה שיש קונבנציות. אנחנו בונים מערכת וכל מי שמבין את המערכת צריך לדעת מה השמות של קבצי ההגדרות ושכל Item צריך קובץ הגדרות בסיסי וממילא לכולם יש קובץ settings.json בגיטהאב ואנחנו לא חושבים על זה". אפשר גם להיזכר בפריימוורקים שאנחנו אוהבים כמו ריילס וב Convention over Configuration ולהסביר שאנחנו בונים פה קונבנציות ואנשים צריכים להכיר את הקונבנציות ואחרי שיכירו אותן כולם יעבדו יותר מהר.

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