שאלות ראיון
שאלות ראיון לתפקיד מהנדס תוכנה
תרגלו שאלות ראיון לתפקיד מהנדס תוכנה בנושאי תבניות פתרון בשאלות קוד, מבני נתונים, אלגוריתמים, תכנון מערכות, ניפוי באגים, בדיקות ושיקול דעת בפרודקשן, וגם שאלות התנהגותיות על שיתוף פעולה. השתמשו ברשימת השאלות הממוקדת הזו לצד המדריך המלא: מדריך ראיון לתפקיד מהנדס תוכנה.
19 שאלות
6 קטגוריות
מהנדס תוכנה
עודכן במאי 2026
מערכים, מחרוזות ו-Hash Map
מערכים, מחרוזות ו-hash map הם הבסיס של ראיונות טכניים ראשוניים רבים. המראיינים משתמשים בהם כדי לבדוק משמעת בעבודה עם אינדקסים, ספירת תדירויות, שני מצביעים, חלון נע ודיוק במימוש.
גישה: חיפוש המשלים
גישת ה-brute force בודקת כל זוג, וזה לוקח O(n^2). גישה טובה יותר משתמשת ב-hash map שממפה כל ערך לאינדקס שלו. בזמן סריקת המערך, לכל מספר x הערך הדרוש הוא target - x. אם המשלים הזה כבר קיים במפה, נחזיר את האינדקס הנוכחי ואת האינדקס השמור. אחרת, נשמור את x עם האינדקס שלו ונמשיך. רעיון הנכונות המרכזי הוא שכאשר מעבדים את אינדקס i, המפה מכילה בדיוק את הערכים מהאינדקסים הקודמים. כלומר, אם זוג תקין מסתיים ב-i, נמצא אותו מיד. כך גם נמנע שימוש באותו איבר פעמיים, כי ההתאמה נעשית רק מול איברים קודמים. סיבוכיות הזמן היא O(n), כי כל ערך מוכנס ונבדק פעם אחת. סיבוכיות המקום היא O(n) עבור המפה. מקרי קצה כוללים ערכים כפולים, מספרים שליליים, אפס, ומצב שבו אין זוג תקין, אם הבעיה מאפשרת זאת.
שאלות המשך צפויות
מה משתנה אם המערך ממוין?
ומה אם צריך להחזיר את כל הזוגות ולא רק זוג אחד?
איך נמנעים מהחזרת אותו איבר פעמיים?
גישה: חלון נע עם האינדקס האחרון שבו הופיע כל תו
נשתמש בחלון נע שתמיד מכיל תווים ייחודיים. נחזיק מצביע left ומפה מכל תו לאינדקס האחרון שבו הופיע. נעבור עם right על המחרוזת. אם התו הנוכחי כבר הופיע בתוך החלון הנוכחי, נזיז את left למיקום אחד אחרי האינדקס הקודם שלו. לאחר מכן נעדכן את האינדקס של התו ונתעד את אורך החלון המקסימלי. הפרט החשוב הוא ש-left זז רק קדימה. אם תו הופיע לפני החלון הנוכחי, הוא לא אמור לכווץ את החלון. לכן העדכון הוא left = max(left, lastSeen[char] + 1). סיבוכיות הזמן היא O(n), כי כל תו מעובד פעם אחת והמצביע left זז רק קדימה. סיבוכיות המקום היא O(k), כאשר k הוא גודל קבוצת התווים. מקרי קצה כוללים מחרוזת ריקה, מחרוזת שכל תוויה ייחודיים, מחרוזת שכל תוויה חוזרים, ו-Unicode אם השפה מתייחסת לתווים באופן שונה מבייטים.
שאלות המשך צפויות
ומה אם הקלט מכיל תווי Unicode?
איך הייתם מחזירים את תת-המחרוזת עצמה?
ומה אם כל תו יכול להופיע לכל היותר פעמיים?
גישה: מפתח קנוני
לאנגרמות יש אותו הרכב תווים. ניצור מפתח קנוני לכל מילה ונקבץ את המילים לפי המפתח הזה ב-hash map. המפתח הישיר ביותר הוא תווי המילה בסדר ממוין. לדוגמה, "eat", "tea" ו-"ate" ממופות כולן ל-"aet". אם המחרוזות קצרות, מיון של כל מילה הוא פשוט ואמין. אם האלפבית מוגבל לאותיות אנגליות קטנות והמחרוזות ארוכות, וקטור תדירויות של 26 מונים יכול להיות מהיר יותר, כי הוא חוסך מיון של O(k log k) לכל מילה. סיבוכיות הזמן עם מיון היא O(n * k log k), כאשר n הוא מספר המחרוזות ו-k הוא האורך הממוצע של מחרוזת. עם ספירה על אלפבית קבוע היא יכולה להיות O(n * k). סיבוכיות המקום היא O(n * k) עבור הפלט והמפתחות. מקרי קצה כוללים מחרוזות ריקות, כפילויות, כללים לאותיות גדולות/קטנות ותווים שאינם באנגלית.
שאלות המשך צפויות
מתי עדיף להשתמש במפתח תדירויות במקום במיון?
איך הייתם מטפלים בקיבוץ שאינו תלוי באותיות גדולות/קטנות?
ומה אם קבוצת התווים אינה קבועה?
רשימות מקושרות, עצים וגרפים
בעיות של מצביעים וסריקה בודקות אם אתם מנהלים מצב בקפידה. החלק הקשה הוא בדרך כלל לא התחביר, אלא להגדיר מה מייצג כל מצביע, תור, מחסנית או קבוצת צמתים שכבר בוקרו.
גישה: שלושה מצביעים: previous, current, next
נשתמש בשלושה מצביעים. previous מתחיל כ-null, ו-current מתחיל בראש הרשימה. לכל צומת נשמור next = current.next, נפנה את current.next אל previous, ואז נקדם את previous ל-current ואת current ל-next. כאשר current הופך ל-null, previous הוא הראש החדש. השמורה היא ש-previous מצביע על החלק שכבר עבר היפוך, ו-current מצביע על הצומת הראשון שעוד לא עבר היפוך. חובה לשמור את next לפני שמשנים את current.next; אחרת שאר הרשימה הולך לאיבוד. סיבוכיות הזמן היא O(n). סיבוכיות המקום היא O(1). מקרי קצה כוללים רשימה ריקה, צומת בודד, ווידוא שהראש המקורי הופך לזנב כש-next שלו מוגדר ל-null.
שאלות המשך צפויות
איך הייתם הופכים רק תת-רשימה ממיקום m עד n?
איך הייתם הופכים רשימה ברקורסיה?
איך מזהים מעגל לפני ההיפוך?
גישה: אילוצי טווח
טעות נפוצה היא לבדוק רק אם כל צומת גדול מהבן השמאלי שלו וקטן מהבן הימני שלו. זה לא מספיק, כי כל תת-העץ חייב לעמוד באילוצים שמכתיבים הצמתים הקודמים לו במסלול מהשורש. נשתמש ב-DFS עם גבול תחתון וגבול עליון. לכל צומת נוודא ש-lower < node.value < upper. הבן השמאלי מקבל את אותו גבול תחתון, והערך הנוכחי משמש לו כגבול עליון. הבן הימני מקבל את הערך הנוכחי כגבול תחתון ואת אותו גבול עליון. אם צומת כלשהו חורג מהטווח שלו, נחזיר false. סיבוכיות הזמן היא O(n), כי כל צומת נבדק פעם אחת. סיבוכיות המקום היא O(h) עבור עומק הרקורסיה, כאשר h הוא גובה העץ. מקרי קצה כוללים כפילויות, גבולות min/max של מספרים שלמים, עץ ריק ועצים לא מאוזנים. כדאי לברר אם מותרות כפילויות, ואם כן, באיזה צד.
שאלות המשך צפויות
איך הייתם פותרים את זה בעזרת סריקת inorder?
ומה אם מותרות כפילויות?
מהו עומק הרקורסיה במקרה הגרוע?
גישה: חיפוש לרוחב לפי שכבות מרחק
נמדל כל תא פתוח כצומת בגרף, וכל צעד למעלה, למטה, שמאלה או ימינה כקשת במשקל שווה. מכיוון שלכל צעד אותה עלות, BFS מוצא את המסלול הקצר ביותר. נתחיל מתא המקור, נכניס אותו לתור עם מרחק 0 ונסמן אותו כמבוקר. לכל תא שנשלף מהתור, נבדוק שכנים תקינים שלא בוקרו, שנמצאים בגבולות הרשת ואינם מכשולים. בפעם הראשונה שמגיעים ליעד, המרחק הוא מינימלי. הנכונות נובעת מכך ש-BFS מעבד צמתים בסדר עולה של מרחק. ברגע שתא בוקר, הגעה אליו מאוחר יותר לא יכולה לתת מסלול קצר יותר בגרף לא ממושקל. סיבוכיות הזמן היא O(rows * cols), כי כל תא מבוקר לכל היותר פעם אחת. סיבוכיות המקום היא O(rows * cols) עבור התור וקבוצת המבוקרים. מקרי קצה כוללים נקודת התחלה או סיום חסומה, מקור שזהה ליעד, היעדר מסלול, והשאלה אם מותרים צעדים באלכסון.
שאלות המשך צפויות
מה משתנה אם מותרת תנועה באלכסון?
ומה אם מעבר דרך מכשולים כרוך בעלות נוספת במקום להיות בלתי אפשרי?
איך הייתם משחזרים את המסלול עצמו?
גישה: מפת visited מכל צומת מקורי לצומת המשוכפל שלו
נשתמש ב-hash map שממפה כל צומת מקורי לצומת המשוכפל שלו. במהלך DFS או BFS, כשמבקרים בצומת מקורי, ניצור עבורו עותק אם עדיין לא קיים. לאחר מכן נשכפל כל שכן ברקורסיה או באיטרציה ונוסיף את השכן המשוכפל לרשימת השכנויות של הצומת המשוכפל. מפת ה-visited פותרת שתי בעיות: היא מונעת לולאות אינסופיות בגרפים עם מעגלים, ושומרת על הפניות משותפות כך שלגרף המשוכפל יש אותה טופולוגיה כמו לגרף המקורי. סיבוכיות הזמן היא O(V + E), כאשר V הוא מספר הצמתים ו-E מספר הקשתות. סיבוכיות המקום היא O(V) עבור המפה ומחסנית הסריקה או התור, לא כולל גרף הפלט. מקרי קצה כוללים קלט null, לולאות עצמיות, גרפים לא קשירים אם הבעיה מצפה לשכפול רק מצומת התחלה, ורשומות שכנים כפולות.
שאלות המשך צפויות
איך הייתם מטפלים בגרף לא קשיר?
מה משתנה בגרף מכוון?
איך נמנעים מרקורסיה אינסופית?
תכנות דינמי ו-Backtracking
שאלות של תכנות דינמי ו-Backtracking בודקות הגדרת מצב. התשובות החזקות ביותר מסבירות את ההחלטה בכל מצב, את נוסחת הנסיגה, ולמה יש תת-בעיות חופפות או למה הגיזום עובד.
גישה: DP מלמטה למעלה לפי הסכום
נגדיר את dp[a] כמספר המטבעות המינימלי הדרוש להרכבת הסכום a. נאתחל dp[0] = 0 ואת כל שאר הערכים כאינסוף. לכל סכום מ-1 עד היעד, ננסה כל מטבע. אם a - coin אינו שלילי, dp[a] = min(dp[a], dp[a - coin] + 1). בסוף, אם dp[target] הוא אינסוף, נחזיר -1. נוסחת הנסיגה עובדת כי המטבע האחרון בפתרון אופטימלי חייב להיות אחד מערכי המטבעות. אם ערכו של המטבע האחרון הוא c, הסכום הנותר הוא target - c, וגם אותו צריך לפתור באופן אופטימלי. סיבוכיות הזמן היא O(amount * number of coins). סיבוכיות המקום היא O(amount). מקרי קצה כוללים סכום 0, סכומים שאי אפשר להרכיב, מטבע בערך 1, ערכי מטבעות כפולים וסכומי יעד גדולים.
שאלות המשך צפויות
איך הייתם מחזירים את המטבעות עצמם?
מה משתנה אם אפשר להשתמש בכל מטבע פעם אחת בלבד?
איך הייתם סופרים במקום זאת את מספר הצירופים?
גישה: DP לפי מיקום הסיום, ואז אופטימיזציה עם חיפוש בינארי
פתרון DP ברור מגדיר את dp[i] כאורך תת-הסדרה העולה הארוכה ביותר שמסתיימת באינדקס i. לכל i נבדוק כל j קודם. אם nums[j] < nums[i], אז nums[i] יכול להאריך את תת-הסדרה שמסתיימת ב-j, ולכן dp[i] = max(dp[i], dp[j] + 1). התשובה היא max(dp). זה לוקח זמן O(n^2) ומקום O(n). הגישה המשופרת ב-O(n log n) מחזיקה מערך tails, שבו tails[length - 1] הוא ערך הסיום הקטן ביותר האפשרי של תת-סדרה עולה באורך הזה. לכל מספר נחפש בחיפוש בינארי את ה-tail הראשון שגדול ממנו או שווה לו, ונחליף אותו. האורך של tails הוא אורך ה-LIS. בראיון, סביר להציג קודם את פתרון ה-DP ב-O(n^2) אם הזמן מוגבל, ואז לדון בגרסה המשופרת. מקרי קצה כוללים כפילויות, מערכים יורדים, קלט ריק, והשאלה אם תת-הסדרה חייבת להיות עולה ממש.
שאלות המשך צפויות
איך הייתם משחזרים את תת-הסדרה?
מה משתנה עבור תת-סדרות לא יורדות?
למה החלפה של tail לא גורמת לאבד את התשובה?
גישה: בניית תחיליות תקינות בלבד
נשתמש ב-Backtracking עם שני מונים: open לסוגרי הפתיחה שנוספו ו-close לסוגרי הסגירה שנוספו. בכל שלב אפשר להוסיף סוגר פתיחה אם open < n, ואפשר להוסיף סוגר סגירה אם close < open. התנאי השני מבטיח שכל תחילית נשארת תקינה, כך שלעולם לא נייצר מחרוזות לא תקינות שיהיה צריך לסנן אחר כך. כשאורך המחרוזת הנוכחית מגיע ל-2n, נוסיף אותה לתוצאה. כך נחקרות רק תחיליות תקינות, ומצבים בלתי אפשריים נגזמים מוקדם. מספר הפלטים התקינים הוא מספר קטלן ה-n-י, ולכן גודל הפלט הוא שקובע את זמן הריצה. סיבוכיות המקום כוללת עומק רקורסיה O(n) ואת הפלט. מקרי קצה כוללים n = 0 או n = 1, בהתאם להגדרת הבעיה.
שאלות המשך צפויות
למה מותר לסגור רק כאשר close < open?
איך הייתם מטפלים בכמה סוגים של סוגריים?
האם אפשר לייצר את התוצאות בסדר לקסיקוגרפי?
ראיונות תכנון מערכות
ראיונות תכנון מערכות (System Design) בוחנים בגרות הנדסית. בתפקידים ברמת Mid, המטרה היא ארכיטקטורה בסיסית וזרימת נתונים. בתפקידים בכירים, הרף כולל פשרות, צווארי בקבוק, אמינות, observability ואחריות תפעולית.
גישה: דרישות ← API ← יצירת מזהים ← אחסון ← נתיב ההפניה ← סקייל
דרישות: משתמשים שולחים URL ארוך ומקבלים URL קצר. כשמישהו נכנס ל-URL הקצר, צריך להפנות אותו במהירות. יכולות אופציונליות כוללות כינויים מותאמים אישית, תפוגה, אנליטיקס, זיהוי ספאם וחשבונות משתמש. ממשקי API מרכזיים: createShortUrl(longUrl, optionalAlias, expiration) ו-redirect(shortCode). מודל הנתונים: shortCode, longUrl, userId, createdAt, expiresAt, status, ומטא-דאטה של אנליטיקס במידת הצורך. ליצירת מזהים יש כמה אפשרויות: מזהים עוקבים (auto-increment) בקידוד base62, קודי base62 אקראיים עם בדיקת התנגשויות, או יצירת מזהים מבוזרת. מזהה עוקב הוא פשוט, אבל חושף את נפח השימוש אם לא מסווים אותו. מזהים אקראיים קלים לביזור, אבל דורשים טיפול בהתנגשויות. בסקייל בינוני, base62 אקראי עם אילוץ ייחודיות במסד הנתונים הוא פתרון סביר. נתיב הקריאה הוא החשוב ביותר. ההפניה צריכה להיות מהירה: טעינת shortCode מה-cache, ובהיעדרו פנייה למסד הנתונים, אימות תפוגה/סטטוס, ואז החזרת HTTP 301 או 302. משתמשים ב-302 אם חשובים אנליטיקס או שינויי יעד, וב-301 להפניות קבועות עם caching חזק יותר בדפדפן. סקייל: שמירת קודים קצרים חמים ב-Redis או ב-edge cache, חלוקה ל-shards לפי shortCode במידת הצורך, אחסון אנליטיקס באופן אסינכרוני דרך תור, הגבלת קצב ליצירת קישורים, והרצת בדיקות ספאם/נוזקות. ננטר את זמן ההשהיה של ההפניות, שיעור הפגיעה ב-cache, שיעור השגיאות, דיווחים על ניצול לרעה ורוויית מסד הנתונים.
שאלות המשך צפויות
איך הייתם מייצרים קודים קצרים ייחודיים?
האם הייתם משתמשים בהפניות 301 או 302?
איך הייתם תומכים באנליטיקס בלי להאט את ההפניות?
גישה: משתמשים ← פוסטים ← fanout ← דירוג ← קריאות ← עקביות
קודם כול נבהיר את סוג הפיד: פיד מבוסס מעקב, פיד המלצות או פיד משולב. נניח פיד מבוסס מעקב, שבו משתמשים יוצרים פוסטים והעוקבים שלהם רואים אותם לפי רלוונטיות או לפי עדכניות. אובייקטים מרכזיים: משתמשים, קשרי מעקב, פוסטים, מדיה, פריטי פיד, לייקים/תגובות ומאפייני דירוג. ממשקי ה-API כוללים createPost, getFeed, followUser, unfollowUser ו-interactWithPost. יש שני מודלים נפוצים ליצירת פיד. Fanout-on-write דוחף פוסטים חדשים למאגרי הפיד של העוקבים ברגע יצירת הפוסט. כך הקריאות מהירות, אבל הכתיבות יקרות עבור משתמשים עם עוקבים רבים. Fanout-on-read מחשב את הפיד בזמן הבקשה על ידי שליפת פוסטים מהחשבונות שהמשתמש עוקב אחריהם. כך הכתיבות זולות, אבל הקריאות איטיות יותר. גישה היברידית נפוצה: fanout-on-write למשתמשים רגילים, ו-fanout-on-read או טיפול מיוחד לחשבונות של סלבריטאים. ארכיטקטורה: שירות הפוסטים כותב פוסטים, שירות הגרף שומר את קשרי המעקב, שירות הפיד מתחזק את צירי הזמן של הפיד, שירות הדירוג מדרג פוסטים מועמדים, ה-cache שומר פידים חמים, והמדיה נשמרת באחסון אובייקטים/CDN. נשתמש בתורים ל-fanout אסינכרוני ולעדכוני דירוג. פשרות: עדכניות הפיד מול איכות הדירוג, עקביות של שינויי מעקב, טיפול במשתמשים סלבריטאים, ביטול תוקף של cache, ספאם, חסימות פרטיות ומילוי חוסרים (backfill) אחרי כשלים בתור. ננטר את זמן הטעינה של הפיד, העדכניות, העיכוב ב-fanout, המעורבות, שיעור הפגיעה ב-cache, שגיאות דירוג ודיווחים על ניצול לרעה.
שאלות המשך צפויות
איך הייתם מטפלים במשתמשים עם מיליוני עוקבים?
איך הייתם מדרגים פריטים בפיד?
מה קורה אם תור ה-fanout מתעכב?
גישה: חיבורים ← זרימת הודעות ← שמירה ← מסירה ← אמינות
דרישות: הודעות אחד-על-אחד והודעות קבוצתיות, מסירה למשתמשים מחוברים ולא מחוברים, היסטוריית הודעות, אישורי קריאה, חיווי הקלדה והתראות פוש. נבהיר אם נדרשים הצפנה מקצה לקצה, קבצים מצורפים וסנכרון בין כמה מכשירים. הלקוחות מחזיקים חיבורי WebSocket לשירות gateway. כשמשתמש שולח הודעה, ה-gateway מאמת אותה, מקצה או מקבל מפתח idempotency, כותב את ההודעה לאחסון עמיד, מפרסם אירוע ומוסר אותה לנמענים המחוברים דרך החיבורים הפעילים שלהם. משתמשים לא מחוברים מקבלים התראות פוש ויכולים לשלוף את ההיסטוריה מאוחר יותר. מודל הנתונים: שיחה, משתתף, הודעה, מצב מסירה, מצב קריאה ומכשיר/סשן. האחסון צריך לאפשר קריאות יעילות לפי שיחה וזמן. מסד נתונים רלציוני יכול להספיק בסקייל בינוני; בסקייל גדול יותר משתמשים במאגרים מבוזרים. קבצים מצורפים צריכים להישמר באחסון אובייקטים, ולא במסד הנתונים של ההודעות. סוגיות אמינות: שליחות כפולות, מסירה שלא לפי הסדר, התחברויות מחדש, הודעות שהוחמצו, fanout לקבוצות גדולות ודיוק סטטוס הנוכחות. נשתמש במפתחות idempotency, במספרים סידוריים עולים מונוטונית לכל שיחה, באישורי קבלה (acknowledgements), בלוגיקת ניסיונות חוזרים ובממשקי API לסנכרון מההודעה האחרונה שנראתה. ננטר את זמן ההשהיה בשליחת הודעות, שיעור ההצלחה במסירה, מספר חיבורי ה-WebSocket, שיעור ההתחברויות מחדש, העיכוב בתורים, כשלים בהתראות פוש ושגיאות כתיבה לאחסון.
שאלות המשך צפויות
איך הייתם מבטיחים את סדר ההודעות?
איך הייתם תומכים בכמה מכשירים לכל משתמש?
מה הייתם שומרים עבור אישורי קריאה?
ניפוי באגים, בדיקות ושיקול דעת בפרודקשן
ראיונות רבים להנדסת תוכנה כוללים היום תרחישים מעשיים של ניפוי באגים, בדיקות או פרודקשן. השאלות האלה מבדילות בין מועמדים שיודעים לכתוב קוד לבין מועמדים שיודעים לתפעל תוכנה באחריות.
גישה: אימות ← תיחום ← שינויים אחרונים ← פירוק לפי תלויות ← צמצום נזק
קודם כול אוודא שהאות אמיתי. אבדוק אם העלייה בזמן ההשהיה מופיעה בכמה מערכות ניטור, והאם היא משפיעה על p50, p95, p99 או רק על endpoint מסוים. אוודא גם אם המשתמשים מרגישים בה. אחר כך אתחם את הבעיה לפי endpoint, אזור, availability zone, פלח לקוחות, גרסה, שרת, תלות וסוג בקשה. עלייה גלובלית מרמזת על תלות משותפת או על פריסה. עלייה מצומצמת מצביעה על נתיב, שאילתה, לקוח או אזור תשתית ספציפיים. לאחר מכן אבחן שינויים אחרונים: פריסות, שינויי קונפיגורציה, מיגרציות של מסד נתונים, קפיצות בתעבורה, feature flags, שינויים ב-cache או תקלות בשירותי downstream. אפרק את זמן ההשהיה לפי spans של השירותים בעזרת traces. אבדוק את זמני השאילתות במסד הנתונים, שיעור הפגיעה ב-cache, העיכוב בתורים, CPU, זיכרון, garbage collection, thread pools, connection pools וממשקי API חיצוניים. אם משתמשים מושפעים, צמצום הנזק קודם לאיתור מושלם של שורש הבעיה. אפשר לבצע rollback, לכבות feature flag, להגדיל קיבולת, לעקוף תלות איטית או להאריך את ה-TTL של ה-cache אם זה בטוח. אחרי ההתאוששות, אתעד את שורש הבעיה, את הפער בזיהוי ואת תוכנית המניעה.
שאלות המשך צפויות
ומה אם רק זמן ההשהיה ב-p99 עלה?
איך הייתם מחליטים אם לבצע rollback?
אילו דשבורדים הייתם רוצים?
גישה: מקרי יחידה ← גבולות ← קלטים לא תקינים ← שמורות
אתחיל בהבהרת הכללים: סוגי ההנחות, צבירת הנחות, תפוגה, סכום רכישה מינימלי, זכאות משתמשים, עיגול מטבע, והאם מסים או משלוח נכללים. בדיקות היחידה צריכות לכסות מקרים רגילים, מקרי גבול, קלטים לא תקינים ואינטראקציות בין כללים. לדוגמה: ללא הנחה, הנחה באחוזים, הנחה בסכום קבוע, הנחה גדולה מסכום הביניים, סכום מינימלי שמתקיים בדיוק, סכום שנמצא ממש מתחת לסף, הנחה שפג תוקפה, משתמש שאינו זכאי, כמה הנחות במקביל אם הדבר מותר, ועיגול אגורות. אבדוק גם שמורות: המחיר הסופי לעולם לא שלילי, ההנחה לא עולה על סכום הביניים הזכאי, מבצעים שפג תוקפם לא חלים, וחישוב חוזר נותן תמיד אותה תוצאה. אם הקוד נוגע בתשלומים, אוסיף בדיקות אינטגרציה מול שירות התמחור ובדיקות snapshot לפלטי החשבוניות. לבטיחות בפרודקשן, אתעד בלוג את החלטות ההנחה עם קודי סיבה, כדי שהתמיכה וצוות הפיתוח יוכלו לאבחן תלונות על תמחור בלי לנחש.
שאלות המשך צפויות
איך הייתם בודקים עיגול מטבע?
מה צריך לקרות אם שירות המבצעים לא זמין?
אילו בדיקות שייכות לבדיקות יחידה ואילו לבדיקות אינטגרציה?
גישה: נכונות ← תחזוקתיות ← סיכון ← בהירות
הגישה שלי לסקירת קוד היא בשכבות. ראשית, האם הקוד פותר את הבעיה המיועדת ושומר על נכונות? שנית, האם הוא תחזוקתי: שמות ברורים, גבולות סבירים, בלי מורכבות מיותרת וסגנון עקבי? שלישית, מה הסיכון: מיגרציות, מקביליות, אבטחה, ביצועים, תאימות לאחור ו-observability? רביעית, האם הבדיקות מספיקות להתנהגות שהשתנתה? סקירת קוד טובה אינה הפגנת עליונות. היא צריכה לשפר את הקוד ולשמור על קצב העבודה של הצוות. חשוב לי להפריד בין בעיות חוסמות להצעות. באג נכונות, בעיית אבטחה או סיכון במיגרציה הם חוסמים. העדפה לגבי שמות או ריפקטורינג קטן יכולים להיות לא חוסמים. בנוסף, אחפש הקשר חסר: התנהגות מוצר לא ברורה, מקרי קצה שלא נבדקו, נתיבי כשל שקטים, טיפול חלש בשגיאות והיעדר מדדים סביב שינויים מסוכנים.
שאלות המשך צפויות
איך מתמודדים עם חילוקי דעות בסקירת קוד?
מה הופך הערה לחוסמת?
איך נמנעים מהאטת הצוות?
שאלות התנהגותיות ושיתוף פעולה
ראיונות התנהגותיים בהנדסה מתמקדים באחריות אישית, שיתוף פעולה, שיקול דעת טכני, התמודדות עם עמימות ולמידה מטעויות. תשובות חזקות כוללות השלכות טכניות אמיתיות.
גישה: הקשר ← אפשרויות ← פשרות ← החלטה ← תוצאה
בחרו החלטה שכרוכות בה פשרות אמיתיות: פיתוח עצמי מול רכישה, SQL מול NoSQL, מונולית מול שירותים, תיקון מהיר מול ריפקטורינג עמוק יותר, או עקביות חזקה מול זמינות. התחילו בהקשר ובאילוצים, ואז הסבירו אילו אפשרויות שקלתם. תשובה חזקה מגדירה את הפשרה בבירור. לדוגמה: "אפשרות A אפשרה לנו לשחרר תוך שבוע, אבל הגדילה את העומס התפעולי. אפשרות B לקחה שלושה שבועות, אבל הסירה צוואר בקבוק בסקייל." אחר כך הסבירו אילו נתונים הכריעו את ההחלטה: תעבורה, דדליין של לקוח, היסטוריית תקלות, קיבולת הצוות או מפת הדרכים לטווח הארוך. סיימו בתוצאה ובמה שלמדתם. אם ההחלטה לא הייתה מושלמת, ציינו מה הייתם עושים אחרת. מראיינים מעריכים שיקול דעת בוגר יותר מהעמדת פנים שכל החלטה הייתה מובנת מאליה.
שאלות המשך צפויות
מי לא הסכים איתכם?
מה היה משנה את ההחלטה שלכם?
איך מדדתם אם ההחלטה עבדה?
גישה: תקלה ← השפעה ← תגובה ← שורש הבעיה ← מניעה
אם אפשר, השתמשו בתקלה אמיתית. התחילו בהשפעה על המשתמשים: מה נשבר, מי הושפע ועד כמה זה היה חמור. אחר כך הסבירו מה היה התפקיד שלכם בתגובה: זיהוי, טריאז', rollback, צמצום הנזק, תקשורת או ניתוח שורש הבעיה. התשובות הטובות ביותר מראות תעדוף רגוע. בזמן תקלה, השבת השירות חשובה יותר מהוכחת תיאוריה. ציינו איך השתמשתם בלוגים, מדדים, traces, feature flags, rollbacks או בדיקות של תלויות. אחרי צמצום הנזק, הסבירו את שורש הבעיה ואת המניעה. מניעה טובה יכולה לכלול בדיקות טובות יותר, פריסה בטוחה יותר, ניטור, כוונון התראות, runbooks, circuit breakers, backpressure או אמצעי הגנה במיגרציות. הימנעו מהאשמת אנשים. צוותים חזקים משפרים את המערכות כך שיהיה קשה יותר לחזור על אותה טעות.
שאלות המשך צפויות
איך תקשרתם במהלך התקלה?
איזו התראה הייתה תופסת את זה מוקדם יותר?
מה הצוות שינה בעקבות זאת?
גישה: מטרה משותפת ← אילוצים ← אפשרויות ← פשרות ← החלטה
אתחיל ביישור קו סביב מטרת המשתמש ומטרת העסק. הרבה חילוקי דעות אינם באמת עניין של הנדסה מול מוצר; הם נובעים מהנחות שונות. אסביר את האילוץ הטכני בבירור: מורכבות, סיכון לאמינות, לוח זמנים, תחזוקתיות, אבטחה או ביצועים. לאחר מכן אציע אפשרויות במקום פשוט לומר לא. לדוגמה: לשחרר MVP קטן יותר, להשתמש זמנית בתהליך ידני, להסתיר את הפיצ'ר מאחורי flag, לחלק את העבודה הטכנית לשלבים, או לבחור תכנון פשוט יותר שעדיין פותר את בעיית הליבה של המשתמש. אם הפשרה משמעותית, אתעד את האפשרויות, הסיכונים וההמלצה כדי שההחלטה תהיה שקופה. המטרה היא לא שההנדסה תנצח. המטרה היא שהצוות יקבל החלטה ברורה בעיניים פקוחות.
שאלות המשך צפויות
ומה אם צוות המוצר מתעקש על האפשרות המסוכנת?
איך מסבירים חוב טכני למי שאינם אנשי פיתוח?
מתי הייתם מעבירים את הנושא להכרעה בדרג גבוה יותר?
תרגלו את התשובות האלה בזמן אמת
Interview Pilot נותן לכם הצעות תשובה של Copilot בזמן אמת במהלך ראיונות אמיתיים, כדי שתוכלו לענות בבהירות כשהשאלות האלה עולות.