רשומות

איך אני נשאר רלוונטי בעידן ה-AI

תמונה
בכל כמה שנים יש “רעידת אדמה” בעולם ההיי-טק. פעם זה היה ה־Cloud, אחר כך Docker ו-Kubernetes, אחר כך המעבר למיקרו-סרוויסים. היום זה ה-AI. פתאום בכל שיחה שומעים על Copilot, על Agents, על LLMs. כולם מדברים על איך זה ישנה את הדרך שבה אנחנו כותבים קוד, מתכננים מוצרים, ואפילו חושבים על העבודה שלנו. בשנה האחרונה במיקרוסופט שמים דגש גדול על AI — בהטמעת כלים, בשילוב רכיבי AI בקוד שלנו, וגם בשימוש יומיומי בפרודוקטיביות כמו כתיבת דוקומנטציה ובדיקות. ובכל פעם שאני שומע על עוד גל פיטורים "בשם ההתייעלות והעברת אחריות ל-AI" — אני עוצר לחשוב: האם הנתיב שאני הולך בו הוא הנתיב הנכון לעתיד הזה? כי מצד אחד, אני סיניור במוצר עם אלפי לקוחות, עם עבודה שוטפת אינסופית — תיקוני באגים, שיחות עם לקוחות, תכנון פיצ'רים וגרסאות. ומצד שני, יש עולם שרץ מסביבי במהירות מטורפת, ואני לא רוצה למצוא את עצמי "לא רלוונטי" עוד כמה שנים. אף אחד לא יודע באמת איך השוק ייראה, אבל הפוסט הזה מסכם את המחשבות והמסקנות שלי — ומה אני באופן אישי בוחר לעשות כדי להישאר רלוונטי. להיות Early adopter - אבל לא...

בראסט ה Enums טובים יותר

תמונה
     כשאנחנו מתחילים לגעת בשפות תכנות, פעמים רבות אנחנו מנסים לחקות את מה שאנחנו כבר יודעים ומכירים משפות קודמות בשפה אחרת. זו אמנם יכולה להיות דרך להכנס לכתיבת קוד מהר יותר, אבל כשנוקטים בגישה הזו עלולים לפספס יכולות ייחודיות לשפה שנותנות דרכים הרבה יותר יעילות ועוצמתיות לפתור בעיות. בכל שפת תכנות יש מבני נתונים בסיסיים שמאפשרים ייצוג של אפשרויות שונות, ובמקרים רבים כשנרצה להשתמש בכאלה נפנה ל enums. באצמצעות enums נוכל לייצג אוסף מוגדר של ערכים, אבל ב-Rust יש להם יכולות מתקדמות שמקנות להם גמישות ועוצמה המקדימות בהרבה את מה שמוכר לנו משפות אחרות.  הפוסט הזה ידבר על למה enums ב-Rust כל כך ייחודיים ואיך ניתן להשתמש בהם לפולימורפיזם בצורה שלא אפשרית ברוב השפות. Enums בראסט ברוב השפות, enums מייצגים אוסף קבוע וסגור של ערכים שניתן לבחור מתוכם. לדוגמה, אפשר להשתמש ב-enum כדי לייצג ימים בשבוע, צבעים או סוגי אירועים. אבל enums מסורתיים הם בדרך כלל מבנים די מוגבלים. ב-Rust, לעומת זאת, enums הם הרבה יותר גמישים; הם מאפשרים לכל variant (או ערך) לשאת נתונים משלו ולהשתמש במערכת ה...

קודמתי לדרגת סיניור במיקרוסופט - מה למדתי בדרך

תמונה
אחרי 10 שנים בתחום, ו3 שנים במיקרוסופט, סוף סוף הגעתי לדרגה המיוחלת - סיניור. את הקריירה שלי התחלתי בצבא, 3 שנים סדיר, שנה וחצי קבע, (בתוך כל זה גם ניהלתי צוות כשנתיים), יצאתי לאזרחות להיות ״סיניור״ בסטארטאפ, הייתי שם שנתיים וקצת ואז התחלתי להתראיין למיקרוסופט. המגייסת פנתה אליי, היו לי ארבעה ראיונות לא רעים בכלל, ואז בשיחת השכר היא אמרה לי ״אתה מיועד לדרגת Software Engineer II״. ישר שאלתי בביטחון מופרז - ״למה לא סיניור? היום אני מתפקד כסיניור ויש לי 7 שנות ניסיון״ ואז היא ענתה משפט שלקח לי קצת זמן להבין כמה הוא נכון - ״כולם פה היו סיניור לפני שהגיעו למיקרוסופט״. אז קיבלתי את ההצעה והזכות להגשים את החלום ולהצטרף למיקרוסופט, והיום, 3 שנים אחרי קודמתי שתי דרגות (מ61 ל 63) וקיבלתי את הטייטל - סיניור. בפוסט הזה אני רוצה לשתף קצת ממה שלמדתי בדרך. למרות שבכל חברה יש מערכת קידומים שונה, אני מאמין שהנקודות הבאות יהיו רלוונטיות לכל עובד בכל חברה. חשוב לי להגיד, זה לא פוסט best practices לקידום, אלא החוויה האישית שהתאימה לפרופיל, לאישיות ולחוזקות שלי ולא בהכרח תהיה דומה בין עובד לעובד. שלושת מעג...

Rust MPSC Channels - צ׳אנלים בראסט

תמונה
אחת התכונות החזקות ביותר בראסט היא מקביליות ואסינכרוניות, וכשמדברים על תכנות אסינכרוני tokio  היא הספרייה הנפוצה ביותר. אחד הפיצ׳רים המרכזיים שטוקיו מאפשרת הוא channels, אשר מאפשרים תקשורת בין חלקים שונים בתכונה שלנו. קיימים בראסט מגוון סוגים של channels שמגיעים ממגוון ספריות (כמו crossbeam , std::mpsc וכו׳). בפוסט אדבר על Tokio Channels, ומתי ואיך נשתמש בהם. מהם צ׳אנלים? כשם כן הם - ״ערוצים״ אשר מאפשרים דרך לשלוח נתונים בין חלקים שונים של תוכנה (בדרך כלל בין threads או tasks). צ׳אנלים מורכבים משני מרכיבים עיקריים:  שולח (Sender):  החלק ששולח נתונים ו מקבל (Receiver): החלק שמקבל נתונים. MPSC (Multi Producer Singler Consumer) הספריה tokio מאפשרת לנו שימוש בצ׳אנלים מסוג MPSC - כלומר, מספר tasks יכולים לשלוח מידע אל מקבל יחיד. וזה נותן לנו יכולת נוחה וישירה להעביר מידע מאיזה סוג שנבחר, אל task מקבל שבו נעבד את המידע ונתמודד איתו. דוגמה פשוטה: בדוגמה הזו אנחנו רואים את יצירת השולח והמקבל tx ו rx. לאחר מכן, יצירת task ברקע ששולח בלולאה 10 מספרים באמצעות tx אל ה task הראשי בו ...

ראסט - פונקציית main נקיה יותר עם Result

תמונה
כחלק מהמסע שלנו לניהול שגיאות נכון  נפל לנו האסימון שלהשתמש ב unwrap או expect  יכול להיות רעיון לא כל כך טוב ועלול להביא לסיום מיידי של הפרוסס שלנו במקרים שאולי לא התכוונו אליהם. אז השתמשנו ב clippy deny unwrap used  שגרם לקומפילציה לא לעבור במידה ונכנס unwrap לקוד. המקום היחיד בו היינו צריכים להשאיר unwrap היה בסט הוולידציות ההתחלתי בעליה של הפרוסס שלנו, בפונקציית ה main. לדוגמה - בניסיון למשוך את הקונפיגורציה הראשונית בעליה - אם נכשלנו מסיבה כלשהי נהרוג את הפרוסס. לימים פונקציית ה main הכילה יותר ויותר ולידציות כאלה ובנוסף גם התחלנו להרוג את הפרוסס שלנו כחלק מתהליך פונקציונאלי תקין במקרים מסויימים (exit code). בפוסט אנסה להציג את האלטרנטיבה שבחרנו לטיפול בשגיאות ב main באמצעות unwrap איך נראה main סטנדרטי הפריע לי בעין לראות כל כך הרבה unwrap וחיפשתי דרך נקייה יותר לנהל את השגיאות שעלולות לצוץ ב main. באחת מעשרות השיחות הטכניות שלי על ראסט עם המנטור שלי , הוא העלה את האופציה פשוט להחזיר result מפונקציית ה main וככה אם תוחזר שגיאה ב main היא תפועפע שכבה אחת והתכנית תסגר...

Rust Builder Pattern

תמונה
אחד הדברים שלקח לי זמן להתרגל אליהם בראסט היה העובדה שאין method overloading וגם אין תמיכה בערכים דיפולטיים לפרמטרים של בפונקציות. כלומר, באותו ה namespace תוכל להיות לנו רק פונקציה אחת עם אותו השם וכשאנחנו מגדירים פונקציה אנחנו לא נוכל לקבוע לפרמטרים שלה ערכים דיפולטיים כדי להקל על המשתמש ב API. זאת להבדיל משפות כמו C#, C++, Java שתומכות ביכולות. בפוסט הזה נדבר על איך Builder Pattern יכול לעזור לנו להתגבר על המגבלות הללו. מה זה Builder Pattern ה"בילדר" היא תבנית עיצוב ממשפחת ה " creational " שמאפשרת לנו לייצר אובייקטים בצורה של הדרגתית וגמישה יותר משימוש ב constructor רגיל. באמצעות הבילדר נוכל להפריד את הרכבת שדות האובייקט מיצירתו בפועל.  התבנית שמישה ב Rust במיוחד משום שבאמצעותה אנחנו יכולים לייצר מבנים (structs) מורכבים, לבחור אילו שדות נרצה לאתחל, וגם לתת ערך דיפולטי לאיזה שדה שנרצה. מימוש ה Builder נתחיל בלייצר struct פשוט של Person שיכיל שדות שנהפוך לאופציונאליים בעוד רגע באמצעות הבילדר. השלבים הבאים יהיו: 1. נייצר מבנה של PersonBuilder שיהיה אחראי על בניית הא...

איך התחלנו לנהל שגיאות ב Rust (חלק ג' - anyhow)

תמונה
אם הגעת לכאן במקרה אני ממליץ להתחיל בפוסט הראשון והשני על מנת לקבל רקע. החלק השלישי במסע שלנו לניהול שגיאות היה ההטמעה של anyhow . הספרייה מספקת מספר פיצ'רים נחמדים מאוד שמקלים על הפיתוח ומייפים את הקוד, מייעלים את ניהול השגיאות, ואפילו עוזרים לאחר השגיאה בניתוח שלה. anyhow::Result כמו שבפוסט הקודם ראינו שאפשר להשתמש ב box dyn Error כערך החזרה של השגיאות שלנו וכך לאפשר פעפוע של כל שגיאה שמממשת את Error trait - הספרייה anyhow נותנת לנו type נוח יותר לשימוש ובשימוש בו אנחנו לא צריכים לציין את סוג השגיאה שלנו. אבל יש בעיה קטנה, אם נשתמש ב anyhow באופן הזה אמנם נרוויח את היכולת לבצע פעפוע של כל שגיאה מבלי להוסיף אותה ל TomerCodeError type שהגדרנו בפוסט הקודם, אבל אנחנו מאבדים את השימוש בשגיאה המותאמת אישית שהגדרנו ובכל יכולות ה formatting שהגדרנו לה. בשביל לפתור את הבעיה הזו כל מה שצריך לעשות זה לגרום לשגיאה שאליה anyhow::Result מתייחס להיות אותה שגיאה שהגדרנו. את זה נעשה באמצעות הגדרת alias ל type באופן הבא: כאן בעצם הגדרנו טיפוס Result משלנו, שאיבר השגיאה בו הוא TomerCodeError ועכשי...