בגדול המאמר הזה נכתב לאחר כמה וכמה דיונים ושאלות ואחרי כבר יותר משנה שאני כותב קוד בעזרת בינה מלאכותית, GitHub copilot וחבריהם השונים. ללא ספק, מדובר בשינוי משמעותי של השוק והעבודה אבל מצד שני – צריך גם להרגע עם תחזיות אופטימיות/אפוקליפטיות מופרעות. אני חושב שדי ברור כבר, אחרי יותר משנה עם הבינה המלאכותית, שחזונות נוסח: ״אני אומר לבינה המלאכותית מה לעשות והיא תבנה את כל המערכת שאני רוצה בזמן שאני מתנדנד על הערסל ושותה פינה קולדה״ כנראה שלא יתממשו ומהצד השני הפטרות זלזול של ״זה רק מנוע סטטיסטי שיוצר ערימות של קוד עם מלא באגים״ גם לא בדיוק נכונות.
אז מה כן? זה מה שניסיתי לכתוב פה – אני מרגיש שבאמת התפקיד שלי כמתכנת השתנה ואני אנסה להמחיש אותו פה באמצעות כמה דוגמאות טכניות מאד שקרו לי בחיים האמיתיים. אני אביא קצת קוד אבל זה פוסט קצת תיאורטי.
כשהתחלתי להשתמש בבינה מלאכותית – בהתחלה עם קופיילוט (שלא אהבתי בהתחלה ואחר כך בזכות קולגה בשם רועי בן יוסף למדתי לעבוד איתו), צ׳אט ג׳יפיטי 3 (שמאד אהבתי), גיליתי שלמרות הדמואים המרהיבים והמדהימים, יש כמה חסרונות. חסרונות שחלק מהן השתנו או התעדכנו בשנה האחרונה אבל בבסיס יש פה בעיה מרכזית שאני לא רואה איך אפשר לפתור: הבינה המלאכותית עושה מה שאומרים לה לעשות.
אני אמחיש באמצעות דוגמה קטנה (כל הדוגמאות הן מ GitHub copilot, code whisper או GPT4 דרך הגרסה בתשלום). הייתי צריך לייצר פונקצית תמצות שיוצרת האש בפייתון. זה מה שקיבלתי:
import hashlib
def hash_string(input_string):
# Create a sha256 hash object
hash_object = hashlib.sha256()
# Update the hash object with the bytes-like object (the string, encoded)
hash_object.update(input_string.encode())
# Get the hexadecimal representation of the digest
hex_dig = hash_object.hexdigest()
return hex_dig
# Example usage
input_string = "Hello, world!"
hashed_string = hash_string(input_string)
print(f"Original String: {input_string}")
print(f"Hashed String: {hashed_string}")
הקוד הזה עובד ובאמת מעולה. האם יש פה בעיית אבטחה ופרטיות? התשובה היא כמובן חד משמעית: תלוי. תלוי בשימוש. מי שיש לו ידע או ניסיון בקריפטוגרפיה יגיד שיש סיכוי שהבינה המלאכותית טעתה פה – כי היא לא הוסיפה salt. טקסט מג׳ונרט שנועד למנוע שינוי. חלק אחר (יותר קטן) יגידו שיש כאן טעות כי לא הוצע שימוש כפול בתמצות שנפוץ במקרים מסוימים. חלק אחר יעיר, ובצדק, שיש פונקציות תמצות מומלצות יותר לססמאות.
צודקים, אבל טועים. בקונטקסט מסוים SHA-256 הוא מעולה והקוד הזה מצוין ועובד היטב. בקונטקסט אחר הוא לא טוב. ד״ר ארז ויסברד שעובד איתי אמר לי, בתשובה לשאלה שלי בנושא שפונקצית תמצות זה כמו כובע מצחיה – לחבוש כובע כשאתה מסתובב בחוץ ביום חם זה רעיון מצוין. מיותר כשאתה בבית במזגן ואסון כאשר אתה נכנס איתו למסעדת יוקרה עם קוד לבוש. כלומר הכל תלוי בקונטקסט. הקוד הזה טוב? לא טוב? תלוי איפה אני משתמש בו.
אתן עוד דוגמה. ביקשתי ליצור קוד שבודק ולידיות של כתובת מייל. השאילתה שלי היתה Create a JavaScript code that checks if the email address is valid. זו התשובה שקיבלתי:
function validateEmail(email) {
// Regular expression for basic email validation
const regex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return regex.test(String(email).toLowerCase());
}
// Example usage
const email1 = "[email protected]";
console.log(`${email1}: ${validateEmail(email1)}`); // Should log: [email protected]: true
const email2 = "not-an-email";
console.log(`${email2}: ${validateEmail(email2)}`); // Should log: not-an-email: false
הקוד הזה עובד, תקין ולגיטימי. א-ב-ל מתכנתים עם יותר ניסיון יעקמו את האף. הם יגידו שביטוי רגולרי, במיוחד לבדיקת מייל, הוא פוטנציאל לנזק ועדיף להשתמש בספריות ולידציה. אם אני משתמש בו בצד הלקוח, יגידו וגם בצדק שעדיף מכל הבחינות להשתמש ב-type=email ב-input הישר ב-HTML ולקבל מהקופסה בדיקת אימייל שגם נגישה, עובדת ובלי קוד בכלל. אבל – האם הקוד הזה רע? הקוד שלעיל עובד, אין בו בעיית אבטחה, אין בו שום דבר רע – אם אני מממש אותו למשל בצד שרת, ב-POC, במקום שבו אני לא יכול להשתמש ב-dependency של ספרית ולידציה או אפילו במיקרו בקר (כן! עם ג׳אווהסקריפט) הוא יהיה מעולה, אבל במקומות אחרים הוא יהיה לא טוב. הכל תלוי בקונטקסט.
אני אמחיש עם דוגמה נוספת. ערכתי קוד בג׳אווהסקריפט וביקשתי באמצעות GitHub copilot להוסיף לאובייקט שנכנס לתוך ה-localStorage גם פרמטר בשם tkn. זו הקוד שהוא הציע:
// Example object with username, token, and id
const userObject = {
username: 'userExample',
tkn: 'someSecureToken', // Token for authentication
id: 123 // User's unique identifier
};
// Function to store the user object in localStorage
function storeUserObject(data) {
localStorage.setItem('userDetails', JSON.stringify(data));
}
// Function to retrieve the user object from localStorage
function getUserObject() {
const storedData = localStorage.getItem('userDetails');
if (storedData) {
return JSON.parse(storedData);
}
return null; // Or any other appropriate handling for missing data
}
// Storing the user object
storeUserObject(userObject);
// Retrieving the user object
const retrievedUserObject = getUserObject();
console.log(retrievedUserObject);
כמובן שזה קוד נפלא שעובד היטב. אבל, וזה אבל גדול – מה זה ה-tkn הזה? אם זה טוקן של כניסה – לשים את זה בצד הלקוח במקום שבו כל XSS סורר יכול לקחת אותו – זה לא רעיון טוב. אם זה טוקן אחר או שזה ראשי תבות של משהו אחר כמובן שאין שום בעיה. אבל הבינה המלאכותית לא יודעת את זה. היא תעשה מה שאבקש ממנה ותעשה את זה היטב – אבל היא לא יודעת מה אני יודע ומה לא.
הבנה של הסביבה שהקוד פועל בה והקונטקסט הם קריטיים
יש לא מעט דוגמאות נוספות לכך שקוד שעובד הוא מעולה אבל יותר חשוב מזה היא הבנה של הקונטקסט והסביבה שבה הקוד פועל. לייצר קוד שעושה טופס לוגין כל אחד יכול ובקלות וגם בשניות. אבל לחשוב על הקונטקסט שבו הטופס הזה נמצא, מה הוא אמור לעשות ומה לא. מה הרגולציה שהוא צריך לעמוד בה אם בכלל ואיך הוא מתחבר לחלקים אחרים במערכת – זה משהו שהבינה המלאכותית לא יכולה לדעת אם לא תתנו לה את המידע הזה. כי זו הצרה עם מחשבים – בסופו של יום הם עושים את מה שאומרים להם לעשות.
פינת ה״אני יכול לפתור את זה!״
עם מספיק RAG, קונטקסט או prompt engineering אפשר לפתור את הכל. הבינה המלאכותית תייצר לי קוד שמתאים והולם ברוב המקרים אם אני אספק לה את כל המידע. אם אני אבקש ממנה לייצר לי סכמת מסד נתונים עם נורמליזציה, היא תעשה את זה במקום טבלת הענק המקורית. אם אני אומר לה שפונקצית התמצות משרתת סיסמה של משתמשים במערכת מאובטחת מאד שלא נדרשת ל-scale, היא תיתן לי פתרון טוב – אבל אני צריך לדעת במה להאכיל אותה ובמה לא. אני צריך לדעת מה הקונטקסט.
וידיעת הקונטקסט וחשיבות הבנת האספקטים הגדולים יותר של הקוד תמיד היתה חשובה אבל עכשיו, בעידן ייצור הקוד בקלות, היא מתחילה להיות חשובה מאד.
התפקיד החדש של המתכנת (?)
בעבר, כשחמי היה מתכנת, אי אז בשנות השמונים העליזות, חלק ניכר מעבודתו היה לחשוב על שימושי זכרון ולכתוב בעצמו את החלקים שניהלו אותו. הוא זה שמימש את ה-Garbage collector בתוכנה שלו ובדק מתי אפשר לשחרר זכרון ואיך. בעבר המרות של מידע – למשל Big Endians\Little Endians היו חלק מהעבודה וגורמים לבאגים (!!!) הדברים האלו, שהיו חלק משמעותי מעבודת המתכנת – הם בבחינת זכרון רחוק היום. יש סיכוי שלכתוב קוד ממשי שעושה דברים – בטח ובטח דברים אטומיים – יהיו זכרון רחוק בעתיד. כבר עכשיו העבודה שלי כמתכנת השתנתה – במקום לכתוב קוד בפועל – אני מייצר קוד עם הבינה המלאכותית (שגם זו עבודה אם צריך להוסיף RAG או לעבוד עם context) ובודק אותו בשבע עיניים כדי לראות אם הוא מתאים וכמובן מאד מאד מקפיד על תהליכי CI כדי שלא ייכנסו לי כל מיני שנינגנס ומרעין בישין לקוד.
אני צריך להבין בקוד ולקרוא קוד ולדעת לכתוב קוד – אבל הפוקוס של העבודה השתנה – מלכתוב את הקוד ללוודא שהקוד שג׳ונרט עובד ועובד בהתאם לקונטקסט. לכתוב קוד שיוצר משהו מאפס הוא כנראה נחלת העבר, לראות איך הקוד הזה עובד ואיפה זה כבר התפקיד החדש שלנו (אולי, אני לא נביא) וזו הנקודה שאני רוצה להעביר ומקווה שהצלחתי.
13 תגובות
הבעיה הגדולה היא שAI הוא לחלוטין לא AI, או במילים אחרות החלק של הintelegence הוא לפחות מוטל מאוד בספק.
הAI הגנרטיבי הוא למעשה מנוע חיפוש שטוב מאוד בלזהות את ההקשר של השאילתה ולמצוא בסיס להפקת תוכן עם אותו הקשר.
אחת הבעיות היא שקשה לודא שאכן סיכום ההקשרים נותן תשובה שהיא חד משמעית נכונה בהקשר של מקצועות מדויקים שלא יכולים להסתפק ב"כמעט נכון" מאחר שבשביל לוודא את זה אתה צריך להבין את "תחום" הבעיה, ואם אתה מבין אותו למה אתה רוצה בכלל לעשות איטרציות על תשובות שהן בפוטנציאל רק "כמעט".
הדוגמא של וידוא כתובת האימייל היא מצוינת לצורך הענין, האם אתה מבין את התקנים של כתובות האימייל לדעת האם הקוד מספק, ואולי אתה צריך להגביל את כתובת האימייל לכתובות ברשת הכללית ולמנוע כתובות מקומיות. הבעיה עם הקוד שמוצג פה היא שהן שום הקשר שמסביר אותו ואת המגבלות שלו למרות שסביר להניח שהוא לקוח מstackoverflow ושם אתה לפיות יכול לשאול.
בסופו של דבר זה בשביל אנשים שהם לא מהנדסי תוכנה אלא codemonkeys ובשבילם זה רק תחליף (סביר להניח שטוב יותר) לשימוש בגוגל. כמובן שיש גם לcodemonkeys מקום בעולם בנישות שבהן תכנות הוא חלק צדדי למה שאותו אדם עושה והדרישות שלו הן ברמה של סקריפט קטן לשימוש מזדמן פחות או יותר.
עבור מהנדסי תוכנה כתיבת קוד אמורה להיות חלק שולי מהעבודה שלהם והשלמת קוד אוטומטית היא ענין מעולה, השאלה היא האם תחזוקה של קוד כזה (שהיא עלות מרכזית בכל פרויקט שהוא מתקוון להתקיים שנים) יותר זולה מתחזוקה של קוד שאותו מתכנת כותב.
(דרך אגב סביר להניח שיש סיבות טובות למה פרויקטים גדולם כמו וורדפרס לא משתמשים ב type=email עד כמה שאני יודע)
תגובה מעולה. באמת. תודה רבה שכתבת 🙏
בנוגע ל type=email, אין שום סיבה שלא להשתמש בו עד כמה שאני יודע.
זה לא שזה רע להגביל את הקלט בצורה כזו, אבל ממש קשה להתאים את התצוגה לצרכים אם הם אפילו טיפה שונים מההנחות שעושה הדפדפן. כדוגמא פשוטה אני עובד עם דפדפן באנגלית אבל מעדיף לקרוא את הטקסט של האתר בעברית. בשביל אנשים כמוני האתר עדיין צריך לפתח קוד להציג את ה"שגיאה" בעברית (והJS הרלבנטי לא לחלוטין טריביאלי) אז מה חסכנו? וזה עוד לפני הבעיה שאם יש לך הודעות שגיאה שלא ניתן לממש על ידי החוקים שהדפדפן יודע לוודא, אתה תגיע למצב של הודעות שגיאה שמוצגות בצורה שונה באותו טופס.
תודה על הפוסט. יגרום לי לבחון מחדש שימוש בקו-פיילוט ודומיו.
אני כן תוהה לעצמי וחושש שזה ידרדר את יכולות התכנות שלי.
יש הבדל בין לפתור תרגיל באינפי, לבין לקרוא פתרון שלו. הראשון מכריח אותך להבין לעומק את הבעיה, השני מאכיל אותך בכפית בדרך ה״בטוחה״ לפתרון (בתקווה שהיא נכונה).
אני חושש שהכישורים שלי כמתכנת יתנוונו(ובוודאי לא ישתפרו) בהסתמכות יתר על קוד מג׳ונרט.
מכיוון אחר – האם היית מגייס לצוות מתכנת שבראיון הטכני פותח צ׳טג׳יפיטי ומעתיק פתרון משם?
מסכים מאד צריך כן לתכנת וכן לדעת לתכנת כדי לא להתנוון. בנוגע לגיוס – אני משתדל לגייס לפי מה שאני מחפש ובוחן על כך כאשר אני משתדל שהמבחן המקצועי יהיה קרוב כמה שיותר למציאות. כאשר מדובר בתפקידים זוטרים יחסים זה קל יותר – למשל אם אני מחפש מתכנת אינפרא פרונט, אני אבדוק איך הוא מייצר קומפוננטות ואני אכן אתן לו לעבוד עם ChatGPT אבל אני כן אוודא שהקומפוננטות שנוצרו עוברות את הטסטים ואת הלינטרים והן בנויות בהתאם לסטנדטים. הרי גם בעבודה הוא ישתמש בזה.
בתפקידים טכניים אחרים ויותר בכירים זה פחות רלוונטי – למשל בתהליך הזה פחות אכפת לי מהדרך שבה פותרים אלא מה שחשוב הוא הסדר או פרמטרים אחרים:
https://internet-israel.com/%d7%a4%d7%99%d7%aa%d7%95%d7%97-%d7%90%d7%99%d7%a0%d7%98%d7%a8%d7%a0%d7%98/%d7%a2%d7%91%d7%95%d7%93%d7%94-%d7%91%d7%94%d7%99%d7%99-%d7%98%d7%a7/%d7%90%d7%99%d7%9a-%d7%9e%d7%a8%d7%90%d7%99%d7%99%d7%a0%d7%99%d7%9d-%d7%a1%d7%a0%d7%99%d7%95%d7%a8%d7%99%d7%9d/
ההקבלה שאני חושב עליה היא כמו יסודות מתמטיקה- שלמדנו באוניברסיטה אנאליזת פורייה התלוננו נורא על הקושי ורמת הדקויות המתמטיות והתיאוריה שבקשו ממנו, וחשבנו שזו הגזה שאינה לצורך. כשעבדתי בתעשייה בתור אלגורתמי של עיבוד אותות הבנתי כמה זה חושב- אפשר לעבוד בעיבוד אותות בלי להבין מה זה בסיס אוטונורמאלי או משפט הדגימה של שאנון, אבל מי ששולט בזה יהיה אלגוריתמאי טוב יותר.
אותו הדבר עם קוד- אפשר לבקש מהAI לג'נרט לך הכל אבל ברור שמי שמבין לעומק שכל שורה יהיה מתכנת טוב יותר
דוגמה מצוינת.
Big endian / little endian לא נעלם בעולם האמבדד.
גם בDICOM זה עוד קיים
האמת שזו נחמה די עלובה, לדעת שבסוף מה שישאר למתכנת זה לדעת מה הוא עושה…
כל הדוגמאות שהבאת יכלו להיפתר בהוספת קונטקסט. לצורך הענין סוכן AI עתידי יבין מהקונטקסט של הקוד שמדובר באתר אינטרנט, ולידציה בצד לקוח וכו, בלי צורך שהמפתח בכלל יבין את ההבדל.
אני לא חושב שזו נחמה עלובה 🙂 אני בטוח שהיו כאלו שהתבאסו שהם לא צריכים לטפל בפוינטרים או בהמרות מידע לפני שלושים שנה.
אבל כתבתי עוד משהו – שאולי יסייע:
https://internet-israel.com/%d7%a4%d7%99%d7%aa%d7%95%d7%97-%d7%90%d7%99%d7%a0%d7%98%d7%a8%d7%a0%d7%98/%d7%91%d7%a0%d7%99%d7%99%d7%aa-%d7%90%d7%aa%d7%a8%d7%99-%d7%90%d7%99%d7%a0%d7%98%d7%a8%d7%a0%d7%98-%d7%9c%d7%9e%d7%a4%d7%aa%d7%97%d7%99%d7%9d/%d7%9c%d7%9e%d7%94-%d7%9b%d7%93%d7%90%d7%99-%d7%9c%d7%94%d7%9b%d7%99%d7%a8-%d7%a4%d7%99%d7%a6%d7%b3%d7%a8%d7%99%d7%9d-%d7%97%d7%93%d7%a9%d7%99%d7%9d-%d7%a9%d7%9c-css/
יפה כתבת
אחלה דוגמאות
ויופי של הסבר
תודה!!!