📌 נראה בסדר
ביקשתי מ AI ליצור תוכנית דוגמה באיזה קורס וקיבלתי את הקוד הזה:
https://github.com/ynonp/googledics-ai-demo
יש פה כמה דברים שקל ממש לראות למה הם שבורים:
1. כל הקוד יושב בקובץ App.tsx במקום חלוקה לקבצים
2. מספרים קסומים מפוזרים באפליקציה (5 צבעים, 20 מסמכים אחרונים, הצגת מקסימום 4 משתמשים מחוברים, אורך מקסימלי של שם 32 תווים).
3. טקסטים מפוזרים בקוד ולא בקובץ תרגום.
יותר קשה לזהות שהאפליקציה בנתה מנגנון Router קטן משלה שכנראה לא יגדל יפה, ש person.name מגיע מ localStorage וכולנו בטוחים שהוא מחרוזת אבל אם הוא מתקלקל שם אין מנגנון התאוששות והסוכן לקח עורך טקסט קוד פתוח בשם tiptap ומימש עליו שכבת עריכה משותפת במקום לקחת את ספריית העריכה המשותפת של טיפטפ שגם היא בקוד פתוח ומתוחזקת על ידי אותם אנשים.
דוגמה נוספת מאפליקציה אחרת היא השורה:
כן שורה אחת במקור, ככה זה נראה מחולק לשורות:
פקודת void לפני הקריאה ל whenSynced תופסת את העין - פקודה זו מבטלת את כלל ה lint שתופס Promises שאין להן catch, כלומר הסוכן אומר פה לטייפסקריפט "עזוב אותי אני יודע מה אני עושה שום דבר לא יישבר פה". בתוך קובץ קוד כשה linter לא צועק קשה יותר לשים לב שאין טיפול בשגיאות.
כשלא מבינים מה זה עושה כל קוד "נראה בסדר".
ביקשתי מ AI ליצור תוכנית דוגמה באיזה קורס וקיבלתי את הקוד הזה:
https://github.com/ynonp/googledics-ai-demo
יש פה כמה דברים שקל ממש לראות למה הם שבורים:
1. כל הקוד יושב בקובץ App.tsx במקום חלוקה לקבצים
2. מספרים קסומים מפוזרים באפליקציה (5 צבעים, 20 מסמכים אחרונים, הצגת מקסימום 4 משתמשים מחוברים, אורך מקסימלי של שם 32 תווים).
3. טקסטים מפוזרים בקוד ולא בקובץ תרגום.
יותר קשה לזהות שהאפליקציה בנתה מנגנון Router קטן משלה שכנראה לא יגדל יפה, ש person.name מגיע מ localStorage וכולנו בטוחים שהוא מחרוזת אבל אם הוא מתקלקל שם אין מנגנון התאוששות והסוכן לקח עורך טקסט קוד פתוח בשם tiptap ומימש עליו שכבת עריכה משותפת במקום לקחת את ספריית העריכה המשותפת של טיפטפ שגם היא בקוד פתוח ומתוחזקת על ידי אותם אנשים.
דוגמה נוספת מאפליקציה אחרת היא השורה:
void this.local.whenSynced.then(()=>{if(!this.destroyed){if(navigator.onLine)this.provider.connect();else this.setStatus('offline');}});כן שורה אחת במקור, ככה זה נראה מחולק לשורות:
void this.local.whenSynced.then(() => {
if (!this.destroyed) {
if (navigator.onLine) {
this.provider.connect();
} else {
this.setStatus('offline');
}
}
});פקודת void לפני הקריאה ל whenSynced תופסת את העין - פקודה זו מבטלת את כלל ה lint שתופס Promises שאין להן catch, כלומר הסוכן אומר פה לטייפסקריפט "עזוב אותי אני יודע מה אני עושה שום דבר לא יישבר פה". בתוך קובץ קוד כשה linter לא צועק קשה יותר לשים לב שאין טיפול בשגיאות.
כשלא מבינים מה זה עושה כל קוד "נראה בסדר".
GitHub
GitHub - ynonp/googledics-ai-demo
Contribute to ynonp/googledics-ai-demo development by creating an account on GitHub.
📌 ממצב תכנון למצב למידה
בעקבות כמה המלצות הפסקתי לפני כמה חודשים להשתמש ב Plan Mode. במבחן התוצאה הניסוי היה מוצלח, התוצאות שקיבלתי היו ברמה דומה לתוצאות עם Plan Mode. יותר מזה, שמתי לב שעבורי סוכן חכם "מתכנן" שמעביר לסוכן טיפש למימוש לא ממש עובד. התוצאה תמיד יוצאת פחות טוב מאשר אם אני נותן לסוכן החכם גם לממש.
ויש לזה סיבה - הסוכנים היום מריצים לולאות וכלים שמראים להם כשדברים לא עובדים ואז הם יכולים לחזור אחורה ולשנות חלקים בתוכנית. שיטת מפל המים שלא עבדה לבני אדם לא עובדת גם לסוכנים. גם הם מגלים דברים במהלך כתיבת הקוד ולפעמים צריכים לשנות כיוון.
אבל ככל שהפסקתי להשתמש במצב תכנון שמתי לב שאני גם מפסיק לתכנן וכך כל משקל העבודה של הפיצ'ר עבר לשלב ה Code Review. פעם ראשונה שהגעתי ל Code Review עוד קראתי כל שורה אבל עם הזמן עברתי לקרוא פחות ופחות עד שכבר לא הכרתי את המוצר.
"מצב תכנון" ככפתור בתוך הסוכן הוא די מיותר. מספיק לכתוב בכותרת של הפרומפט "עכשיו מתכננים" והסוכן יודע לא לשנות קוד. אבל מצב תכנון כשיטת עבודה, עם פרומפט נכון, יכול להיות חלק מאוד חשוב מהתהליך:
1. מתחילים ב grill me - מבקשים מהסוכן שישאל אתכם שאלות טכניות על הפיצ'ר כדי לוודא שכולם מיושרים. אפשר להתקין את הסקיל או לבקש בעצמכם.
2. ממשיכים ב"סכם את כל מה שדיברנו לתוכנית", קוראים את התוכנית ורואים שאנחנו מבינים כל מקרה קצה. אפשר ורצוי לקחת את התוכנית לסוכן אחר או למודל אחר ולחפש עוד מקרי קצה והשפעות על כלל המערכת.
תכנון טוב עוזר לנו לבוא עם ציפייה ל Code Review. אנחנו מצפים לראות קוד מסוים, בדיקות מסוימות, שינויים מסוימים במערכת. בצורה כזאת גם ה Code Review יהיה קל יותר וגם בסוף העבודה על הפיצ'ר אנחנו מבינים יותר טוב מה נכנס למערכת.
ביקשתי מ ChatGPT לכתוב לי כמה פרומפטים שאוכל להשתמש כדי להפוך את מצב תכנון למצב למידה, הנה ההצעות שקיבלתי:
בעקבות כמה המלצות הפסקתי לפני כמה חודשים להשתמש ב Plan Mode. במבחן התוצאה הניסוי היה מוצלח, התוצאות שקיבלתי היו ברמה דומה לתוצאות עם Plan Mode. יותר מזה, שמתי לב שעבורי סוכן חכם "מתכנן" שמעביר לסוכן טיפש למימוש לא ממש עובד. התוצאה תמיד יוצאת פחות טוב מאשר אם אני נותן לסוכן החכם גם לממש.
ויש לזה סיבה - הסוכנים היום מריצים לולאות וכלים שמראים להם כשדברים לא עובדים ואז הם יכולים לחזור אחורה ולשנות חלקים בתוכנית. שיטת מפל המים שלא עבדה לבני אדם לא עובדת גם לסוכנים. גם הם מגלים דברים במהלך כתיבת הקוד ולפעמים צריכים לשנות כיוון.
אבל ככל שהפסקתי להשתמש במצב תכנון שמתי לב שאני גם מפסיק לתכנן וכך כל משקל העבודה של הפיצ'ר עבר לשלב ה Code Review. פעם ראשונה שהגעתי ל Code Review עוד קראתי כל שורה אבל עם הזמן עברתי לקרוא פחות ופחות עד שכבר לא הכרתי את המוצר.
"מצב תכנון" ככפתור בתוך הסוכן הוא די מיותר. מספיק לכתוב בכותרת של הפרומפט "עכשיו מתכננים" והסוכן יודע לא לשנות קוד. אבל מצב תכנון כשיטת עבודה, עם פרומפט נכון, יכול להיות חלק מאוד חשוב מהתהליך:
1. מתחילים ב grill me - מבקשים מהסוכן שישאל אתכם שאלות טכניות על הפיצ'ר כדי לוודא שכולם מיושרים. אפשר להתקין את הסקיל או לבקש בעצמכם.
2. ממשיכים ב"סכם את כל מה שדיברנו לתוכנית", קוראים את התוכנית ורואים שאנחנו מבינים כל מקרה קצה. אפשר ורצוי לקחת את התוכנית לסוכן אחר או למודל אחר ולחפש עוד מקרי קצה והשפעות על כלל המערכת.
תכנון טוב עוזר לנו לבוא עם ציפייה ל Code Review. אנחנו מצפים לראות קוד מסוים, בדיקות מסוימות, שינויים מסוימים במערכת. בצורה כזאת גם ה Code Review יהיה קל יותר וגם בסוף העבודה על הפיצ'ר אנחנו מבינים יותר טוב מה נכנס למערכת.
ביקשתי מ ChatGPT לכתוב לי כמה פרומפטים שאוכל להשתמש כדי להפוך את מצב תכנון למצב למידה, הנה ההצעות שקיבלתי:
“Build this plan with me in Learn mode. As you make each important decision, explain the concept behind it, the alternatives you considered, and why you chose this approach. Don’t just give me the finished plan.”
“Don’t immediately make the whole plan for me. At important decision points, ask me what I think we should do and why. Then critique my reasoning, teach me anything I’m missing, and continue building the plan.”
“Whenever we reach an important choice in the plan, ask me to predict what you would choose before telling me. After I answer, explain the correct reasoning and update the plan.”
“For each major section of the plan: first teach me the relevant concept briefly, then ask me 1–2 questions to check my understanding, then use it to make the actual planning decision.”
“Make the plan, but every few major decisions stop and test whether I understand what we’ve decided, why we decided it, and what tradeoffs we accepted. If I misunderstand something, teach it again before continuing.”
“While creating the plan, occasionally ask me to explain or defend a decision in my own words. Push back on weak reasoning like a good teacher would.”
“Start by explaining your reasoning in detail. As I demonstrate that I understand, give me more of the planning decisions to make myself. Step in when my reasoning has gaps.”
“After we finish the plan, don’t just summarize it. Test me on it: ask why the major choices were made, what alternatives we rejected, what assumptions the plan depends on, and what I’d change if those assumptions changed.”
“Teach me this plan by showing me the common mistakes someone might make at each stage. Ask me to identify the mistake before explaining it.”
“Use Learn mode. Help me produce the plan, but optimize equally for the quality of the plan and for my understanding. Teach concepts just before they become relevant, ask me to predict important decisions, periodically test my understanding, correct misconceptions, and gradually make me take over more of the reasoning. At the end, test whether I could reconstruct and adapt the plan without your help.”
“Plan this with me, not for me. Make sure I could explain every important decision by the end.”
❤1
אפשר להשתמש בפרומפט אחד מכאן או שילוב של כמה באותה תוכנית. הדבר החשוב הוא לצאת משלב התכנון עם הבנה מלאה של הבעיה כדי להגיע מוכנים וביקורתיים ל Code Review שאחרי.
📌 רעיונות מסדרים, פתרונות נקודתיים
האם יש אמת אחת שמתאימה לכל מערכות התוכנה או שלכל מערכת יש את הכיוון והאופי שלה?
אם אתם מאלה שחושבים שיש אמת אחת, דרך אחת שמתאימה לכולם, המשיכו לקרוא. הפוסט הזה לא בשבילכם.
נשארתם? יופי. אז אם אנחנו מסכימים שלמערכות שונות יש אופי שונה למה כולנו משתמשים באותם מודלים ושואלים אותם את אותן שאלות? איך המודל אמור לדעת מה האופי של המערכת לפני שמייצר את התשובה?
סוכני קידוד מנסים לעזור. הם נותנים למודל דרך לקרוא חלק מהקוד. הם מריצים Linters שאולי שומרים על Code Style מסוים. הם מריצים את הבדיקות. אבל זה רק חלק מהתמונה.
החלק השני הוא הרעיונות המסדרים. רעיונות כמו:
1. מינימליזם - במערכת שלנו אנחנו בונים את הקוד הכי קטן שפותר את הבעיה. אנחנו לא רוצים לפתור בעיות נוספות ולא מוכנים לשלם אפילו מחיר קטן על התאמת הקוד לבעיות מהעתיד.
2. ביצועים - אצלנו בצוות יש תרבות של שמירה על ביצועים. אנחנו מתגאים שהמערכת שלנו נטענת מהר, תופסת מעט מקום ויעילה יותר מהמתחרים. כל שינוי קוד נמדד בהשפעה שלו על הביצועים ואנחנו שמחים לשלם בזמן פיתוח בשביל שיפור אפילו שולי בזמן הטעינה והריצה של התוכנית.
3. תכנות דפנסיבי - המשתמשים שלנו משוגעים והמערכת שלנו צריכה להתאים לכל מצב. אנחנו כותבים קוד גמיש שתמיד מוצא את הדרך לעבוד ולא להתרסק.
4. מהירות פיתוח - אנחנו סטארט-אפ שנאבק למצוא התאמת מוצר לשוק. זה ה Pivot השלישי שלנו. אנחנו בונים קוד שאפשר לשנות מהר, בלי סכימות, לא 100% עובד אבל בעיקר לא מסבך אותנו עם מיגרציות יקרות כשצריך לקחת צעד אחורה ולשנות מסלול.
5. המפתח הכי צעיר שלנו עובד פה 8 שנים. כולם מכירים את הקוד לעומק ומבינים כל שורה וכל פסיק. אנחנו כותבים קוד קצר ומדויק ולא מבזבזים תווים על הערות או הסברים ארוכים.
הרשימה היא רק דוגמה - אתם בוחרים את הפילוסופיה של המערכת שלכם. הדבר החשוב שתהיה לכם אחת.
ואחרי שבחרתם תוכלו לשמור אותה בקובץ AGENTS.md תחת סעיף Philosophy או Coding Approach כדי לקבל מהסוכן הערות שמתאימות לאותה פילוסופיה לדוגמה:
כשהגישה שלכם כתובה בצורה ברורה הרבה יותר קל לקלוד לענות על שאלות כמו "מה עשיתי לא בסדר" או "באיזו מידה הקוד החדש תואם את הפילוסופיה של המערכת".
האם יש אמת אחת שמתאימה לכל מערכות התוכנה או שלכל מערכת יש את הכיוון והאופי שלה?
אם אתם מאלה שחושבים שיש אמת אחת, דרך אחת שמתאימה לכולם, המשיכו לקרוא. הפוסט הזה לא בשבילכם.
נשארתם? יופי. אז אם אנחנו מסכימים שלמערכות שונות יש אופי שונה למה כולנו משתמשים באותם מודלים ושואלים אותם את אותן שאלות? איך המודל אמור לדעת מה האופי של המערכת לפני שמייצר את התשובה?
סוכני קידוד מנסים לעזור. הם נותנים למודל דרך לקרוא חלק מהקוד. הם מריצים Linters שאולי שומרים על Code Style מסוים. הם מריצים את הבדיקות. אבל זה רק חלק מהתמונה.
החלק השני הוא הרעיונות המסדרים. רעיונות כמו:
1. מינימליזם - במערכת שלנו אנחנו בונים את הקוד הכי קטן שפותר את הבעיה. אנחנו לא רוצים לפתור בעיות נוספות ולא מוכנים לשלם אפילו מחיר קטן על התאמת הקוד לבעיות מהעתיד.
2. ביצועים - אצלנו בצוות יש תרבות של שמירה על ביצועים. אנחנו מתגאים שהמערכת שלנו נטענת מהר, תופסת מעט מקום ויעילה יותר מהמתחרים. כל שינוי קוד נמדד בהשפעה שלו על הביצועים ואנחנו שמחים לשלם בזמן פיתוח בשביל שיפור אפילו שולי בזמן הטעינה והריצה של התוכנית.
3. תכנות דפנסיבי - המשתמשים שלנו משוגעים והמערכת שלנו צריכה להתאים לכל מצב. אנחנו כותבים קוד גמיש שתמיד מוצא את הדרך לעבוד ולא להתרסק.
4. מהירות פיתוח - אנחנו סטארט-אפ שנאבק למצוא התאמת מוצר לשוק. זה ה Pivot השלישי שלנו. אנחנו בונים קוד שאפשר לשנות מהר, בלי סכימות, לא 100% עובד אבל בעיקר לא מסבך אותנו עם מיגרציות יקרות כשצריך לקחת צעד אחורה ולשנות מסלול.
5. המפתח הכי צעיר שלנו עובד פה 8 שנים. כולם מכירים את הקוד לעומק ומבינים כל שורה וכל פסיק. אנחנו כותבים קוד קצר ומדויק ולא מבזבזים תווים על הערות או הסברים ארוכים.
הרשימה היא רק דוגמה - אתם בוחרים את הפילוסופיה של המערכת שלכם. הדבר החשוב שתהיה לכם אחת.
ואחרי שבחרתם תוכלו לשמור אותה בקובץ AGENTS.md תחת סעיף Philosophy או Coding Approach כדי לקבל מהסוכן הערות שמתאימות לאותה פילוסופיה לדוגמה:
This commit mostly matches the Philosophy section in AGENTS.md. The coupon list is stored as a JSON column instead of a new table, which fits "Development speed": no migration to undo if we pivot again. One deviation: the new CouponValidator handles currency mismatches and expired-but-grace-period coupons, neither of which exists in the product today. Per "Minimalism," I'd remove both branches and keep only the expiry check.
כשהגישה שלכם כתובה בצורה ברורה הרבה יותר קל לקלוד לענות על שאלות כמו "מה עשיתי לא בסדר" או "באיזו מידה הקוד החדש תואם את הפילוסופיה של המערכת".
📌 לפעמים קוד טוב עדיף על קוד ידידותי לסוכן
אם החלטתם על Refactor כדי שהקוד יהיה יותר ברור ואחרי השינוי אתם מגלים שגם ל AI הרבה יותר קל לבנות פיצ'רים למערכת והוא עושה פחות טעויות אין שום בעיה.
אבל מה קורה אם עשיתם את אותו Refactor וגיליתם שהוא הביא את המערכת שלכם למצב שלכם יותר קל לקרוא אותה אבל לסוכן יותר קשה?
ניסוי שהראיתי לאחרונה בקורס חשף בדיוק את התופעה הזאת:
1. הקוד החדש מכיל קבצים יותר קטנים, אפיון יותר נקי, בדיקות טובות יותר.
2. עבודה על הקוד החדש לקחה יותר טוקנים.
לא משנה כמה הוספנו הסברים ב AGENTS.md או בסקילים בסוף קלוד היה צריך לעבור על יותר קבצים, לחפש ביותר מקומות וספציפית התיקון שהיינו צריכים היה יותר קשה לביצוע עם הקוד החדש.
האם זה אומר שהריפקטור מוטעה? אני חושב שלא. כל מבנה של קוד שנבחר יגרום לפיצ'רים מסוימים להיות קלים יותר ואחרים להיות קשים יותר. זה נכון גם לקוד של בני אדם. השיקולים בבחירת ארכיטקטורה לא נגמרים ב"מה קל ל AI".
אם החלטתם על Refactor כדי שהקוד יהיה יותר ברור ואחרי השינוי אתם מגלים שגם ל AI הרבה יותר קל לבנות פיצ'רים למערכת והוא עושה פחות טעויות אין שום בעיה.
אבל מה קורה אם עשיתם את אותו Refactor וגיליתם שהוא הביא את המערכת שלכם למצב שלכם יותר קל לקרוא אותה אבל לסוכן יותר קשה?
ניסוי שהראיתי לאחרונה בקורס חשף בדיוק את התופעה הזאת:
1. הקוד החדש מכיל קבצים יותר קטנים, אפיון יותר נקי, בדיקות טובות יותר.
2. עבודה על הקוד החדש לקחה יותר טוקנים.
לא משנה כמה הוספנו הסברים ב AGENTS.md או בסקילים בסוף קלוד היה צריך לעבור על יותר קבצים, לחפש ביותר מקומות וספציפית התיקון שהיינו צריכים היה יותר קשה לביצוע עם הקוד החדש.
האם זה אומר שהריפקטור מוטעה? אני חושב שלא. כל מבנה של קוד שנבחר יגרום לפיצ'רים מסוימים להיות קלים יותר ואחרים להיות קשים יותר. זה נכון גם לקוד של בני אדם. השיקולים בבחירת ארכיטקטורה לא נגמרים ב"מה קל ל AI".
📌 לקחים מפרק ג׳וניורים תעסוקה ואפוקליפסת AI של עושים תוכנה
הקשבתי לעמית ודנה השבוע בעושים תוכנה, רוב הפרק היה מאוד מעניין ואני ממליץ להאזין. אלה הנקודות המרכזיות שאני מסכם לעצמי:
1. המרחק בין ג'וניורים לסניורים התקצר - תעשיית התוכנה אף פעם לא היתה חזקה בלתגמל נסיון (הבדיחה כשגדלתי היתה שצריך לעשות אקזיט עד גיל 40 כי אחרי זה לא תהיה לך עבודה). עמית ודנה שיתפו, וגם אני שמתי לב לזה, שהיום נסיון נהיה אפילו הרבה פחות חשוב. דברים שפעם היית צריך שנתיים כדי ללמוד אנשים מצליחים להכיר ולהיות פרודוקטיביים בהם כבר אחרי כמה שבועות. ה AI מקצר את תהליך הלמידה ומקצר את הדרך מהיכרות שטחית להכנסת קוד פרודקשן למערכות.
2. הרף עלה - לכו לקלוד ותגידו לו ליצור לכם מערכת X. התוצאה היא ה Baseline החדש. עמית אמר את זה בבירור בפרק, הוא לא היה מגייס בן אדם שחוזר אליו עם תוצאה ברמה שקלוד היה נותן. אז מה הציפייה? להיות ספציפיים, להכיר טכנולוגיה, לדחוף את ה AI לקצה, כשמגישים פיתרון להראות את עצמכם ואת האופי שלכם והבחירות שלכם בתוך קוד הפיתרון.
3. פיטורים לא תמיד קשורים אליכם - חברות קטנות מצליחות להגיע רחוק ומנכ"לים של חברות גדולות רואים את זה ומקנאים. אם המטרה שלך היא לייצר מוצרים טובים יותר, לקחת נתח שוק גדול יותר ולהרוויח יותר לא בטוח שיותר עובדים זה ייתרון. במיוחד בהינתן AI. ואני מוסיף על הדברים שלהם שעוד אין לנו פרדיגמה טובה איך לשתף פעולה על פרויקט תוכנה בין מספר בני אדם וסוכני קידוד. ככל שמהירות הפיתוח עולה אנחנו מבזבזים יותר זמן על תקשורת ותיאומים ונוצר מצב שלפעמים להוסיף מפתח שני לפרויקט כבר מאט את הפרויקט משמעותית.
מה עושים? אין תשובות טובות. כנראה לאף אחד. בינתיים אפשר לשים לב לשאלות, ללמוד איך ליצור תוכנה טוב יותר בעולם של ה AI וללמוד למצוא את הערך הייחודי שלנו שאנחנו מביאים לכל פרויקט. הצורך בתרומה אנושית רק מתחזק ככל שסוכני הבינה משתלבים בחיינו.
הקשבתי לעמית ודנה השבוע בעושים תוכנה, רוב הפרק היה מאוד מעניין ואני ממליץ להאזין. אלה הנקודות המרכזיות שאני מסכם לעצמי:
1. המרחק בין ג'וניורים לסניורים התקצר - תעשיית התוכנה אף פעם לא היתה חזקה בלתגמל נסיון (הבדיחה כשגדלתי היתה שצריך לעשות אקזיט עד גיל 40 כי אחרי זה לא תהיה לך עבודה). עמית ודנה שיתפו, וגם אני שמתי לב לזה, שהיום נסיון נהיה אפילו הרבה פחות חשוב. דברים שפעם היית צריך שנתיים כדי ללמוד אנשים מצליחים להכיר ולהיות פרודוקטיביים בהם כבר אחרי כמה שבועות. ה AI מקצר את תהליך הלמידה ומקצר את הדרך מהיכרות שטחית להכנסת קוד פרודקשן למערכות.
2. הרף עלה - לכו לקלוד ותגידו לו ליצור לכם מערכת X. התוצאה היא ה Baseline החדש. עמית אמר את זה בבירור בפרק, הוא לא היה מגייס בן אדם שחוזר אליו עם תוצאה ברמה שקלוד היה נותן. אז מה הציפייה? להיות ספציפיים, להכיר טכנולוגיה, לדחוף את ה AI לקצה, כשמגישים פיתרון להראות את עצמכם ואת האופי שלכם והבחירות שלכם בתוך קוד הפיתרון.
3. פיטורים לא תמיד קשורים אליכם - חברות קטנות מצליחות להגיע רחוק ומנכ"לים של חברות גדולות רואים את זה ומקנאים. אם המטרה שלך היא לייצר מוצרים טובים יותר, לקחת נתח שוק גדול יותר ולהרוויח יותר לא בטוח שיותר עובדים זה ייתרון. במיוחד בהינתן AI. ואני מוסיף על הדברים שלהם שעוד אין לנו פרדיגמה טובה איך לשתף פעולה על פרויקט תוכנה בין מספר בני אדם וסוכני קידוד. ככל שמהירות הפיתוח עולה אנחנו מבזבזים יותר זמן על תקשורת ותיאומים ונוצר מצב שלפעמים להוסיף מפתח שני לפרויקט כבר מאט את הפרויקט משמעותית.
מה עושים? אין תשובות טובות. כנראה לאף אחד. בינתיים אפשר לשים לב לשאלות, ללמוד איך ליצור תוכנה טוב יותר בעולם של ה AI וללמוד למצוא את הערך הייחודי שלנו שאנחנו מביאים לכל פרויקט. הצורך בתרומה אנושית רק מתחזק ככל שסוכני הבינה משתלבים בחיינו.
👍1
📌 שבתות וחגים - מה קורה כשהמודל מנסה יותר מדי
נתתי ל Sol את הפרומפט הבא כדי לבנות תוכנית פייתון שמדלגת על שבתות וחגים, למשל בשביל לא לשלוח מייל או לחייב לקוחות בשבת:
התוצאה היתה מרשימה. זה קובץ ה calendar.py שהוא יצר:
נתתי ל Sol את הפרומפט הבא כדי לבנות תוכנית פייתון שמדלגת על שבתות וחגים, למשל בשביל לא לשלוח מייל או לחייב לקוחות בשבת:
create a new python project with uv
the app is a cron scheduler we should start it via a CLI
cron.py cronfile
cronfile is in the same format as any regular crontab EXCEPT it has a twist
each line also has a boolean indicating if the request should execute in Jewish holidays and Saturdays
(called "skip_shabatot_vehagim")
If skip_shabatot_vehagim is set that line shouldn't execute on Jewish holidays and Saturdays with religious date
boundaries
התוצאה היתה מרשימה. זה קובץ ה calendar.py שהוא יצר:
"""Protected intervals, starting the evening before each sacred civil date."""
import math
from dataclasses import dataclass
from datetime import UTC, date, datetime, timedelta
from functools import lru_cache
from zoneinfo import ZoneInfo
from astral import Observer, SunDirection
from astral.sun import sunset, time_at_elevation
from pyluach.dates import HebrewDate
class BoundaryError(ValueError):
"""The location has no calculable sunset or nightfall for a required date."""
@dataclass(frozen=True)
class ReligiousCalendar:
timezone: ZoneInfo = ZoneInfo("Asia/Jerusalem")
latitude: float = 31.778
longitude: float = 35.235
israel: bool = True
start_offset_minutes: float = 0
nightfall_degrees: float = 8.5
nightfall_minutes: float | None = None
def __post_init__(self) -> None:
for name, value, lower, upper in (
("latitude", self.latitude, -90, 90),
("longitude", self.longitude, -180, 180),
("start offset", self.start_offset_minutes, 0, 180),
("nightfall degrees", self.nightfall_degrees, 1, 30),
):
if not math.isfinite(value) or not lower <= value <= upper:
raise ValueError(f"{name} must be between {lower} and {upper}")
if self.nightfall_minutes is not None and (
not math.isfinite(self.nightfall_minutes)
or not 0 < self.nightfall_minutes <= 240
):
raise ValueError("nightfall minutes must be greater than 0 and at most 240")
@lru_cache(maxsize=1024) # noqa: B019 - bounded cache of immutable configurations
def protected_date(self, day: date) -> bool:
if day.weekday() == 5:
return True
hebrew = HebrewDate.from_pydate(day)
# Pyluach numbers Nissan as 1 and Tishrei as 7. Only holidays on
# which work is prohibited are included, rather than minor holidays.
sacred = {
(7, 1),
(7, 2), # Rosh Hashanah (two days also in Israel)
(7, 10), # Yom Kippur
(7, 15),
(7, 22), # Sukkot and Shemini Atzeret / Simchat Torah
(1, 15),
(1, 21), # First and last days of Pesach
(3, 6), # Shavuot
}
if not self.israel:
sacred |= {(7, 16), (7, 23), (1, 16), (1, 22), (3, 7)}
return (hebrew.month, hebrew.day) in sacred
@lru_cache(maxsize=1024) # noqa: B019 - bounded cache of immutable configurations
def interval(self, day: date) -> tuple[datetime, datetime]:
observer = Observer(self.latitude, self.longitude)
try:
start = sunset(observer, day - timedelta(days=1), self.timezone)
start = start.astimezone(UTC) - timedelta(minutes=self.start_offset_minutes)
if self.nightfall_minutes is not None:
end = sunset(observer, day, self.timezone).astimezone(UTC)
end += timedelta(minutes=self.nightfall_minutes)
else:
end = time_at_elevation(
observer,
-self.nightfall_degrees,
day,
SunDirection.SETTING,
self.timezone,
with_refraction=False,
).astimezone(UTC)
❤1
except ValueError as error:
raise BoundaryError(
f"cannot calculate religious boundaries for {day}"
) from error
if end <= start:
raise BoundaryError(f"invalid religious boundaries for {day}")
return start, end
def is_protected(self, when: datetime) -> bool:
if when.tzinfo is None or when.utcoffset() is None:
raise ValueError(
"religious boundary checks require a timezone-aware datetime"
)
local_day = when.astimezone(self.timezone).date()
instant = when.astimezone(UTC)
# Yesterday covers a nightfall after midnight at high latitudes.
# Tomorrow covers Friday and holiday-eve evenings. Intersecting
# intervals naturally keep consecutive holy days protected.
for delta in (-1, 0, 1):
day = local_day + timedelta(days=delta)
if self.protected_date(day):
start, end = self.interval(day)
if start <= instant < end:
return True
return False
הקובץ כולל את רשימת החגים מובנית, המרה לתאריך עברי ואפילו בדיקת שעות כדי לא לבצע משימות בערב חג אבל כן לאפשר משימות אחרי צאת שבת.
אם הייתי נותן ל AI להריץ איטרציית שיפור על הקוד הוא כנראה היה מבין שאין צורך להגדיר את רשימת החגים בתוך הפונקציה
protected_date ואפשר להוציא אותה למשתנה של המודול כדי לשפר ביצועים ולקצר קצת את הקוד.ובכל זאת הייתי נזהר מלהשתמש בקוד כזה במערכת שלי. הקוד גבולי מדי, הוא חושב שהוא יודע הכל ועושה מאמץ למצוא בדיוק את שעת השקיעה כדי לזהות מתי נכנסת שבת. המאמץ לעשות את הדבר הנכון בא על חשבון מרווחי ביטחון בריאים.
תיקון טוב במקרה הזה היה הפרומפט:
replace sunset calculation with a healthy safe buffer
זה הקובץ אחרי התיקון:
"""Conservative local-clock buffers around Shabbat and Jewish holidays."""
from dataclasses import dataclass
from datetime import UTC, date, datetime, time, timedelta
from functools import lru_cache
from zoneinfo import ZoneInfo
from pyluach.dates import HebrewDate
@dataclass(frozen=True)
class ReligiousCalendar:
timezone: ZoneInfo = ZoneInfo("Asia/Jerusalem")
israel: bool = True
protection_start: time = time(15, 0)
protection_end: time = time(23, 0)
def __post_init__(self) -> None:
for boundary in (self.protection_start, self.protection_end):
if boundary.tzinfo is not None or boundary.second or boundary.microsecond:
raise ValueError("protection times must be local HH:MM times")
if self.protection_end < self.protection_start:
raise ValueError("protection end must not be earlier than protection start")
@lru_cache(maxsize=1024) # noqa: B019 - bounded cache of immutable configurations
def protected_date(self, day: date) -> bool:
if day.weekday() == 5:
return True
hebrew = HebrewDate.from_pydate(day)
# Pyluach numbers Nissan as 1 and Tishrei as 7. Only holidays on
# which work is prohibited are included, rather than minor holidays.
sacred = {
(7, 1),
(7, 2), # Rosh Hashanah (two days also in Israel)
(7, 10), # Yom Kippur
(7, 15),
(7, 22), # Sukkot and Shemini Atzeret / Simchat Torah
(1, 15),
(1, 21), # First and last days of Pesach
(3, 6), # Shavuot
}
if not self.israel:
sacred |= {(7, 16), (7, 23), (1, 16), (1, 22), (3, 7)}
return (hebrew.month, hebrew.day) in sacred
@lru_cache(maxsize=1024) # noqa: B019 - bounded cache of immutable configurations
def interval(self, day: date) -> tuple[datetime, datetime]:
start = datetime.combine(
day - timedelta(days=1), self.protection_start, self.timezone
)
end = datetime.combine(day, self.protection_end, self.timezone)
return start.astimezone(UTC), end.astimezone(UTC)
def is_protected(self, when: datetime) -> bool:
if when.tzinfo is None or when.utcoffset() is None:
raise ValueError(
"religious boundary checks require a timezone-aware datetime"
)
local_day = when.astimezone(self.timezone).date()
instant = when.astimezone(UTC)
# Tomorrow covers the buffered eve. Overlapping intervals keep
# consecutive holy days continuously protected.
for delta in (0, 1):
day = local_day + timedelta(days=delta)
if self.protected_date(day):
start, end = self.interval(day)
if start <= instant < end:
return True
return False
גם קוד פשוט יותר וגם עונה טוב יותר למטרה האמיתית של הפרומפט הראשון.
אז מה זה אומר שמפתחים עוברים להיות אנשי Product ומאפיינים? סוג של. מה שחשוב היום בעבודה של מפתחים הוא ראייה מערכתית. להבין איך המערכת צריכה להיראות, איזה מנגנונים בקוד אנחנו רוצים לבנות ואיפה אנחנו רוצים דווקא לוותר על המנגנון המתוחכם בשביל משהו פשוט שיהיה יותר יציב. להבין איך הקוד מתחבר לדרישות ואיך לבחור את המימוש שיענה טוב יותר גם על הדרישות שלא נמצאות בפרומפט.
📌 סנטינל בפייתון 3.15
פייתון 3.15 יצא ואחרי החגיגות וההתקנות הלכתי לקרוא את רשימת השינויים. חלק מהם ממש מעולים כמו האפשרות לייבא עם lazy כדי לשפר את זמן העלייה של הסקריפט, המעבר ל UTF-8 כברירת מחדל, מילון קפוא וכמובן הפרופיילר החדש שדוגם חיצונית את התוכנית במקום לבדוק מתוך הסקריפט כמו שעשינו בעבר.
ויחד איתם פיצ'ר אחד בשם sentinel שאני בכלל לא בטוח שעדיין נחוץ.
סנטינל, או בעברית זקיף או שומר, הוא ערך מיוחד שנועד לתאר את המצב בו הפונקציה שלנו לא יכולה להחזיר מה שביקשו ממנה. לדוגמה נכתוב פונקציה לחיפוש האינדקס הראשון בו מופיע פריט מסוים ברשימה:
אם אני מחפש והפריט נמצא ברשימה הפונקציה תחזיר את האינדקס שלו. אם אני מחפש והפריט אינו ברשימה היא תחזיר None:
אבל מה קורה אם None הוא דווקא ערך שיכול להיות מוחזר גם באופן רגיל מהפונקציה? במצב כזה נהיה בבעיה כי לא נדע להבדיל בין המצב שפונקציה מחזירה None בתור מצד רגיל למצב בו היא מחזירה None רק כי אין לה משהו אחר להחזיר.
דוגמה טובה היא הפונקציה next של פייתון שמחזירה את הדבר הבא מאיטרטור:
קריאה ל next אחרי שהאיטרטור נגמר זורקת חריג בשם StopIteration כי אין לו יותר מה להחזיר. הפונקציה next עצמה לא יכולה להחזיר זקיף כי כל ערך שנבחר היה יכול להופיע באופן רגיל בערך ההחזר שלה.
אגב next עצמה מאפשרת למי שקורא לה לבחור את הזקיף וכך מתמודדת עם הבעיה:
כך שאם אתם כן צריכים את הכתיבה בלי ה Exception יש פיתרון.
ומה לגבי sentinel? בעיקר לא מזיק:
הזקיף הוא ערך מיוחד שאנחנו יכולים להחזיר כדי לסמן לעצמנו שאין ערך. כל פעם שמפעילים sentinel מקבלים ערך מיוחד חדש אפילו אם הטקסט שמתאר אותו הוא זהה. זקיף שורד העתקות וגם השמה למשתנים נוספים וגם pickling:
אז מה הבעיה עם הפיצ'ר? אני חושב שהוא פשוט מיותר:
1. המנגנונים הקיימים כמו להחזיר None או לזרוק שגיאה מכסים את רוב המקרים.
2. אם בכל זאת חייבים ערך מיוחד שיהיה שונה מ None אפשר להגדיר לבד class.
בעולם שבו סוכנים יכתבו את רוב הקוד הייתי שמח לראות פחות פיצ'רים בשפות ויותר אפשרויות להרחיב את השפות עם מנגנונים שאנחנו (כלומר הסוכן שלנו) נכתוב.
פייתון 3.15 יצא ואחרי החגיגות וההתקנות הלכתי לקרוא את רשימת השינויים. חלק מהם ממש מעולים כמו האפשרות לייבא עם lazy כדי לשפר את זמן העלייה של הסקריפט, המעבר ל UTF-8 כברירת מחדל, מילון קפוא וכמובן הפרופיילר החדש שדוגם חיצונית את התוכנית במקום לבדוק מתוך הסקריפט כמו שעשינו בעבר.
ויחד איתם פיצ'ר אחד בשם sentinel שאני בכלל לא בטוח שעדיין נחוץ.
סנטינל, או בעברית זקיף או שומר, הוא ערך מיוחד שנועד לתאר את המצב בו הפונקציה שלנו לא יכולה להחזיר מה שביקשו ממנה. לדוגמה נכתוב פונקציה לחיפוש האינדקס הראשון בו מופיע פריט מסוים ברשימה:
def first_index(needle, haystack):
for index, item in enumerate(haystack):
if item == needle:
return index
אם אני מחפש והפריט נמצא ברשימה הפונקציה תחזיר את האינדקס שלו. אם אני מחפש והפריט אינו ברשימה היא תחזיר None:
print(first_index('a', ['x', 'y', 'a', 'b', 'a']))
2
print(first_index('foo', ['x', 'y', 'a', 'b', 'a']))
Noneאבל מה קורה אם None הוא דווקא ערך שיכול להיות מוחזר גם באופן רגיל מהפונקציה? במצב כזה נהיה בבעיה כי לא נדע להבדיל בין המצב שפונקציה מחזירה None בתור מצד רגיל למצב בו היא מחזירה None רק כי אין לה משהו אחר להחזיר.
דוגמה טובה היא הפונקציה next של פייתון שמחזירה את הדבר הבא מאיטרטור:
>>> items = iter(['a', 'b', 'c'])
>>> print(next(items))
a
>>> print(next(items))
b
>>> print(next(items))
c
>>> print(next(items))
Traceback (most recent call last):
File "<python-input-4>", line 1, in <module>
print(next(items))
~~~~^^^^^^^
StopIteration
קריאה ל next אחרי שהאיטרטור נגמר זורקת חריג בשם StopIteration כי אין לו יותר מה להחזיר. הפונקציה next עצמה לא יכולה להחזיר זקיף כי כל ערך שנבחר היה יכול להופיע באופן רגיל בערך ההחזר שלה.
אגב next עצמה מאפשרת למי שקורא לה לבחור את הזקיף וכך מתמודדת עם הבעיה:
>>> items = iter(['a', 'b', 'c'])
>>> print(next(items, None))
a
>>> print(next(items, None))
b
>>> print(next(items, None))
c
>>> print(next(items, None))
None
>>> print(next(items, None))
None
>>> print(next(items, None))
None
>>>
כך שאם אתם כן צריכים את הכתיבה בלי ה Exception יש פיתרון.
ומה לגבי sentinel? בעיקר לא מזיק:
>>> items = iter(['a', 'b', 'c'])
>>> missing = sentinel('MISSING')
>>> print(next(items, missing))
a
>>> print(next(items, missing))
b
>>> print(next(items, missing))
c
>>> print(next(items, missing))
MISSING
>>> print(next(items, missing))
MISSING
>>> print(next(items, missing))
MISSING
>>> next(items, missing) is missing
True
>>>
הזקיף הוא ערך מיוחד שאנחנו יכולים להחזיר כדי לסמן לעצמנו שאין ערך. כל פעם שמפעילים sentinel מקבלים ערך מיוחד חדש אפילו אם הטקסט שמתאר אותו הוא זהה. זקיף שורד העתקות וגם השמה למשתנים נוספים וגם pickling:
>>> x = sentinel('x')
>>> y = sentinel('x')
>>> z = x
>>> x is x
True
>>> x is z
True
>>> x is y
False
>>>אז מה הבעיה עם הפיצ'ר? אני חושב שהוא פשוט מיותר:
1. המנגנונים הקיימים כמו להחזיר None או לזרוק שגיאה מכסים את רוב המקרים.
2. אם בכל זאת חייבים ערך מיוחד שיהיה שונה מ None אפשר להגדיר לבד class.
בעולם שבו סוכנים יכתבו את רוב הקוד הייתי שמח לראות פחות פיצ'רים בשפות ויותר אפשרויות להרחיב את השפות עם מנגנונים שאנחנו (כלומר הסוכן שלנו) נכתוב.
📌 סנטינל בפייתון 3.15
פייתון 3.15 יצא ואחרי החגיגות וההתקנות הלכתי לקרוא את רשימת השינויים. חלק מהם ממש מעולים כמו האפשרות לייבא עם lazy כדי לשפר את זמן העלייה של הסקריפט, המעבר ל UTF-8 כברירת מחדל, מילון קפוא וכמובן הפרופיילר החדש שדוגם חיצונית את התוכנית במקום לבדוק מתוך הסקריפט כמו שעשינו בעבר.
ויחד איתם פיצ'ר אחד בשם sentinel שאני בכלל לא בטוח שעדיין נחוץ.
סנטינל, או בעברית זקיף או שומר, הוא ערך מיוחד שנועד לתאר את המצב בו הפונקציה שלנו לא יכולה להחזיר מה שביקשו ממנה. לדוגמה נכתוב פונקציה לחיפוש האינדקס הראשון בו מופיע פריט מסוים ברשימה:
אם אני מחפש והפריט נמצא ברשימה הפונקציה תחזיר את האינדקס שלו. אם אני מחפש והפריט אינו ברשימה היא תחזיר None:
אבל מה קורה אם None הוא דווקא ערך שיכול להיות מוחזר גם באופן רגיל מהפונקציה? במצב כזה נהיה בבעיה כי לא נדע להבדיל בין המצב שפונקציה מחזירה None בתור מצד רגיל למצב בו היא מחזירה None רק כי אין לה משהו אחר להחזיר.
דוגמה טובה היא הפונקציה next של פייתון שמחזירה את הדבר הבא מאיטרטור:
קריאה ל next אחרי שהאיטרטור נגמר זורקת חריג בשם StopIteration כי אין לו יותר מה להחזיר. הפונקציה next עצמה לא יכולה להחזיר זקיף כי כל ערך שנבחר היה יכול להופיע באופן רגיל בערך ההחזר שלה.
אגב next עצמה מאפשרת למי שקורא לה לבחור את הזקיף וכך מתמודדת עם הבעיה:
כך שאם אתם כן צריכים את הכתיבה בלי ה Exception יש פיתרון.
ומה לגבי sentinel? בעיקר לא מזיק:
הזקיף הוא ערך מיוחד שאנחנו יכולים להחזיר כדי לסמן לעצמנו שאין ערך. כל פעם שמפעילים sentinel מקבלים ערך מיוחד חדש אפילו אם הטקסט שמתאר אותו הוא זהה. זקיף שורד העתקות וגם השמה למשתנים נוספים וגם pickling:
אז מה הבעיה עם הפיצ'ר? אני חושב שהוא פשוט מיותר:
1. המנגנונים הקיימים כמו להחזיר None או לזרוק שגיאה מכסים את רוב המקרים.
2. אם בכל זאת חייבים ערך מיוחד שיהיה שונה מ None אפשר להגדיר לבד class.
בעולם שבו סוכנים יכתבו את רוב הקוד הייתי שמח לראות פחות פיצ'רים בשפות ויותר אפשרויות להרחיב את השפות עם מנגנונים שאנחנו (כלומר הסוכן שלנו) נכתוב.
פייתון 3.15 יצא ואחרי החגיגות וההתקנות הלכתי לקרוא את רשימת השינויים. חלק מהם ממש מעולים כמו האפשרות לייבא עם lazy כדי לשפר את זמן העלייה של הסקריפט, המעבר ל UTF-8 כברירת מחדל, מילון קפוא וכמובן הפרופיילר החדש שדוגם חיצונית את התוכנית במקום לבדוק מתוך הסקריפט כמו שעשינו בעבר.
ויחד איתם פיצ'ר אחד בשם sentinel שאני בכלל לא בטוח שעדיין נחוץ.
סנטינל, או בעברית זקיף או שומר, הוא ערך מיוחד שנועד לתאר את המצב בו הפונקציה שלנו לא יכולה להחזיר מה שביקשו ממנה. לדוגמה נכתוב פונקציה לחיפוש האינדקס הראשון בו מופיע פריט מסוים ברשימה:
def first_index(needle, haystack):
for index, item in enumerate(haystack):
if item == needle:
return index
אם אני מחפש והפריט נמצא ברשימה הפונקציה תחזיר את האינדקס שלו. אם אני מחפש והפריט אינו ברשימה היא תחזיר None:
print(first_index('a', ['x', 'y', 'a', 'b', 'a']))
2
print(first_index('foo', ['x', 'y', 'a', 'b', 'a']))
Noneאבל מה קורה אם None הוא דווקא ערך שיכול להיות מוחזר גם באופן רגיל מהפונקציה? במצב כזה נהיה בבעיה כי לא נדע להבדיל בין המצב שפונקציה מחזירה None בתור מצד רגיל למצב בו היא מחזירה None רק כי אין לה משהו אחר להחזיר.
דוגמה טובה היא הפונקציה next של פייתון שמחזירה את הדבר הבא מאיטרטור:
>>> items = iter(['a', 'b', 'c'])
>>> print(next(items))
a
>>> print(next(items))
b
>>> print(next(items))
c
>>> print(next(items))
Traceback (most recent call last):
File "<python-input-4>", line 1, in <module>
print(next(items))
~~~~^^^^^^^
StopIteration
קריאה ל next אחרי שהאיטרטור נגמר זורקת חריג בשם StopIteration כי אין לו יותר מה להחזיר. הפונקציה next עצמה לא יכולה להחזיר זקיף כי כל ערך שנבחר היה יכול להופיע באופן רגיל בערך ההחזר שלה.
אגב next עצמה מאפשרת למי שקורא לה לבחור את הזקיף וכך מתמודדת עם הבעיה:
>>> items = iter(['a', 'b', 'c'])
>>> print(next(items, None))
a
>>> print(next(items, None))
b
>>> print(next(items, None))
c
>>> print(next(items, None))
None
>>> print(next(items, None))
None
>>> print(next(items, None))
None
>>>
כך שאם אתם כן צריכים את הכתיבה בלי ה Exception יש פיתרון.
ומה לגבי sentinel? בעיקר לא מזיק:
>>> items = iter(['a', 'b', 'c'])
>>> missing = sentinel('MISSING')
>>> print(next(items, missing))
a
>>> print(next(items, missing))
b
>>> print(next(items, missing))
c
>>> print(next(items, missing))
MISSING
>>> print(next(items, missing))
MISSING
>>> print(next(items, missing))
MISSING
>>> next(items, missing) is missing
True
>>>
הזקיף הוא ערך מיוחד שאנחנו יכולים להחזיר כדי לסמן לעצמנו שאין ערך. כל פעם שמפעילים sentinel מקבלים ערך מיוחד חדש אפילו אם הטקסט שמתאר אותו הוא זהה. זקיף שורד העתקות וגם השמה למשתנים נוספים וגם pickling:
>>> x = sentinel('x')
>>> y = sentinel('x')
>>> z = x
>>> x is x
True
>>> x is z
True
>>> x is y
False
>>>אז מה הבעיה עם הפיצ'ר? אני חושב שהוא פשוט מיותר:
1. המנגנונים הקיימים כמו להחזיר None או לזרוק שגיאה מכסים את רוב המקרים.
2. אם בכל זאת חייבים ערך מיוחד שיהיה שונה מ None אפשר להגדיר לבד class.
בעולם שבו סוכנים יכתבו את רוב הקוד הייתי שמח לראות פחות פיצ'רים בשפות ויותר אפשרויות להרחיב את השפות עם מנגנונים שאנחנו (כלומר הסוכן שלנו) נכתוב.
📌 עזוב את ה AI ותתחיל לתכנת
האם זו עצה טובה למתחילים?
נתחיל עם מה שאנחנו יודעים:
1. יש מיומנויות שנשמרות ויש שנשכחות. אנחנו לא שוכחים לרכב על אופניים אבל כן שוכחים איך לכתוב קוד. גם לפני ה AI מפתחים שיצאו לחופשה של כמה חודשים התקשו עם משימות קידוד אפילו פשוטות והיו צריכים תקופת הסתגלות. גם לפני ה AI מפתחים היו צריכים להתאמן לראיונות עבודה ולפתור שוב ושוב את אותם תרגילי ליטקוד.
2. יש מפתחים שעבדו שנים על מערכת ועדיין מכירים רק חלק קטן או ממוקד ממנה בלי להבין את התמונה הגדולה. גם זה קרה הרבה לפני ה AI. כתיבת קוד ידנית היא לא ערובה להיכרות עמוקה עם מערכת תוכנה וכל התהליכים בה.
3. היכרות טובה עם כל שלבי סולם האבסטרקציה עוזרת לאנשים להבין טוב יותר את השלב בו הם נמצאים אבל לא מבטיחה הצלחה. מפתחים שמבינים איך חומרה עובדת, יודעים לקרוא אסמבלי, מכירים את שפת C ויודעים לקרוא את הקוד של הדפדפן יוכלו להבין את הפרטים של פיתוח ווב טוב יותר מחבריהם שעבדו רק בתוך דפדפן, אבל גם פה פגשתי מפתחי ווב טובים משני הסוגים.
אז למה אנחנו חושבים שהיכרות טובה עם שפת תכנות ויכולת כתיבת קוד הכרחיות או לפחות תורמות לבניית מערכות טובות בעידן ה AI? אני חושב שהסיפור הוא פחות הידע הספציפי בשפת תכנות מסוימת ויותר היכולת לעבוד עם אבסטרקציות, לחשוב ולפתור בעיות בתוך המערכת.
מפתחים שיודעים לממש מיון במערך מתוך סט של פעולות פשוטות הם בעלי סיכוי טוב יותר לארגן מערכת מיקרו סרביסים מבוזרת מתוך סט הפעולות הפשוטות שספק הענן נותן להם. את שפת פייתון עצמה אנחנו שוכחים; המיומנות של עבודה דרך אבסטרקציות או בניית מבנים מורכבים מתוך רכיבים פשוטים יותר נשארת איתנו ומתחזקת עם השנים.
ובחזרה לשאלה מהכותרת: "עזוב את ה AI ותתחיל לתכנת" היא עצה שמכוונת למטרה הנכונה דרך הכלי הלא נכון. הבעיה אף פעם לא הייתה מי מקליד את הקוד, אלא מי מקבל את ההחלטות. מתחיל שנותן לסוכן גם לכתוב את הקוד וגם להחליט איך המערכת בנויה לא ילמד הרבה. אבל גם מתחיל שמקליד כל שורה בעצמו ומעתיק את המבנה מטוטוריאל לא ילמד הרבה יותר.
אנחנו לא צריכים להתרחק מסוכני קידוד כדי להתחיל לחשוב. להיפך, סוכני הקידוד יכולים להיות חברים טובים שלנו וללמד אותנו לחשוב. הם יכולים להכריח אותנו לקבל החלטות, לבחון אותנו על ההחלטות האלה ולעמת אותנו עם מקרים שלא צפינו והתפתחויות עתידיות של המערכת שלא תכננו. ההקלדה לא הייתה אף פעם החלק החשוב.
האם זו עצה טובה למתחילים?
נתחיל עם מה שאנחנו יודעים:
1. יש מיומנויות שנשמרות ויש שנשכחות. אנחנו לא שוכחים לרכב על אופניים אבל כן שוכחים איך לכתוב קוד. גם לפני ה AI מפתחים שיצאו לחופשה של כמה חודשים התקשו עם משימות קידוד אפילו פשוטות והיו צריכים תקופת הסתגלות. גם לפני ה AI מפתחים היו צריכים להתאמן לראיונות עבודה ולפתור שוב ושוב את אותם תרגילי ליטקוד.
2. יש מפתחים שעבדו שנים על מערכת ועדיין מכירים רק חלק קטן או ממוקד ממנה בלי להבין את התמונה הגדולה. גם זה קרה הרבה לפני ה AI. כתיבת קוד ידנית היא לא ערובה להיכרות עמוקה עם מערכת תוכנה וכל התהליכים בה.
3. היכרות טובה עם כל שלבי סולם האבסטרקציה עוזרת לאנשים להבין טוב יותר את השלב בו הם נמצאים אבל לא מבטיחה הצלחה. מפתחים שמבינים איך חומרה עובדת, יודעים לקרוא אסמבלי, מכירים את שפת C ויודעים לקרוא את הקוד של הדפדפן יוכלו להבין את הפרטים של פיתוח ווב טוב יותר מחבריהם שעבדו רק בתוך דפדפן, אבל גם פה פגשתי מפתחי ווב טובים משני הסוגים.
אז למה אנחנו חושבים שהיכרות טובה עם שפת תכנות ויכולת כתיבת קוד הכרחיות או לפחות תורמות לבניית מערכות טובות בעידן ה AI? אני חושב שהסיפור הוא פחות הידע הספציפי בשפת תכנות מסוימת ויותר היכולת לעבוד עם אבסטרקציות, לחשוב ולפתור בעיות בתוך המערכת.
מפתחים שיודעים לממש מיון במערך מתוך סט של פעולות פשוטות הם בעלי סיכוי טוב יותר לארגן מערכת מיקרו סרביסים מבוזרת מתוך סט הפעולות הפשוטות שספק הענן נותן להם. את שפת פייתון עצמה אנחנו שוכחים; המיומנות של עבודה דרך אבסטרקציות או בניית מבנים מורכבים מתוך רכיבים פשוטים יותר נשארת איתנו ומתחזקת עם השנים.
ובחזרה לשאלה מהכותרת: "עזוב את ה AI ותתחיל לתכנת" היא עצה שמכוונת למטרה הנכונה דרך הכלי הלא נכון. הבעיה אף פעם לא הייתה מי מקליד את הקוד, אלא מי מקבל את ההחלטות. מתחיל שנותן לסוכן גם לכתוב את הקוד וגם להחליט איך המערכת בנויה לא ילמד הרבה. אבל גם מתחיל שמקליד כל שורה בעצמו ומעתיק את המבנה מטוטוריאל לא ילמד הרבה יותר.
אנחנו לא צריכים להתרחק מסוכני קידוד כדי להתחיל לחשוב. להיפך, סוכני הקידוד יכולים להיות חברים טובים שלנו וללמד אותנו לחשוב. הם יכולים להכריח אותנו לקבל החלטות, לבחון אותנו על ההחלטות האלה ולעמת אותנו עם מקרים שלא צפינו והתפתחויות עתידיות של המערכת שלא תכננו. ההקלדה לא הייתה אף פעם החלק החשוב.
❤1