עיצוב חניון - שאלת ראיון OOP קלאסית¶
בניגוד למקרי הבוחן הקודמים שדיברנו עליהם, שהתמקדו בתשתית מבוזרת - שרתים, מסדי נתונים, קנה מידה - שאלת "עצבו חניון" שייכת למשפחה אחרת לגמרי. היא לא בודקת אם אתם יודעים לבנות מערכת שרצה על אלף שרתים, אלא אם אתם יודעים לחשוב נכון על תכנות מונחה עצמים - איך מזהים מחלקות, אחריות, ויחסים ביניהן מתוך תיאור בעיה בשפה חופשית.
שלב 1 - למה שואלים את זה בכלל¶
חניון הוא דוגמה טובה כי הוא מספיק מוכר לכולם - כל מי שהחנה רכב מבין אינטואיטיבית איך זה אמור לעבוד - אבל מכיל מספיק מורכבות אמיתית כדי לבדוק חשיבה מסודרת. יש בו סוגי כלים שונים, סוגי מקומות חניה שונים, ותמחור שתלוי במשתנים. המראיין לא מחפש קוד מושלם, אלא תהליך חשיבה - איך ניגשים לפירוק בעיה מעורפלת למחלקות קונקרטיות.
שלב 2 - זיהוי המחלקות הבסיסיות¶
הצעד הראשון הוא לזהות את שמות העצם המרכזיים בבעיה, כי הם מועמדים טבעיים למחלקות - ParkingLot (החניון עצמו), ParkingSpot (מקום חניה בודד), Vehicle (רכב), Ticket (כרטיס כניסה). זיהוי ראשוני כזה נותן שלד לדבר עליו, גם אם הוא ישתנה כשמעמיקים.
class Vehicle:
def __init__(self, license_plate, vehicle_type):
self.license_plate = license_plate
self.vehicle_type = vehicle_type
class ParkingSpot:
def __init__(self, spot_id, spot_type):
self.spot_id = spot_id
self.spot_type = spot_type
self.vehicle = None
def is_available(self):
return self.vehicle is None
def park(self, vehicle):
self.vehicle = vehicle
def remove(self):
self.vehicle = None
שלב 3 - הורשה - סוגי רכבים וסוגי מקומות¶
חניון אמיתי תומך בכמה סוגי רכבים - אופנוע, רכב פרטי, משאית - וכמה סוגי מקומות חניה שמתאימים להם. כאן נכנסת הורשה בצורה טבעית - Motorcycle, Car ו-Truck יכולים לרשת ממחלקת בסיס Vehicle, כל אחת עם גודל שונה. ParkingSpot יכול להיות CompactSpot, RegularSpot או LargeSpot, וכל סוג מקום מגדיר אילו סוגי רכבים מתאימים לו. זו נקודה טובה בראיון להראות שאתם לא מוסיפים הורשה סתם, אלא רק במקום שבו יש התנהגות שונה אמיתית בין תתי הסוגים.
שלב 4 - אלגוריתם איתור מקום חניה פנוי¶
השאלה המעניינת האמיתית היא איך ParkingLot מוצא מקום חניה פנוי מתאים לרכב נתון, ביעילות. פתרון נאיבי - לעבור על כל המקומות אחד אחד עד למציאת מקום פנוי מהסוג הנכון. פתרון טוב יותר - להחזיק רשימה נפרדת של מקומות פנויים לכל סוג מקום, כדי לא לסרוק מקומות תפוסים בכל חיפוש. שיפור נוסף הוא לחשוב על קרבה לכניסה - אם יש כמה מקומות פנויים מתאימים, עדיף להציע את הקרוב ביותר לכניסה, מה שדורש מבנה נתונים שמסודר גם לפי מיקום פיזי, לא רק לפי סוג.
שלב 5 - תמחור - דוגמה מצוינת ל-Strategy¶
תמחור חניה משתנה - שעתי, יומי, מחיר שונה לפי סוג רכב, הנחות למינוי. במקום להטמיע if-else ארוך בתוך ParkingLot שבודק כל מקרה, זו נקודה מצוינת ליישם תבנית Strategy - כל מדיניות תמחור היא מחלקה נפרדת שמיישמת אותה מתודה, למשל calculate_fee(duration, vehicle_type), ו-ParkingLot פשוט מחזיק הפניה לאסטרטגיית התמחור הנוכחית ומפעיל אותה. זה מאפשר להוסיף מדיניות תמחור חדשה - למשל תעריף מיוחד לחגים - בלי לגעת בקוד הקיים בכלל.
שלב 6 - מקרי קצה שכדאי להעלות ביוזמתכם¶
מראיין טוב יעריך אם תעלו לבד מקרי קצה - מה קורה כשהחניון מלא, מה קורה אם אותו רכב מנסה להיכנס פעמיים, איך מטפלים באובדן כרטיס חניה. גם אם לא תספיקו לממש את כולם בקוד, עצם ההעלאה שלהם מראה חשיבה מסודרת שחורגת מהמקרה הפשוט וההצלחה בלבד.
שאלות עיצוב מונחה עצמים כמו חניון בודקות זווית שונה מעיצוב מערכות מבוזרות, אבל חשובה לא פחות - יכולת לתרגם דרישה מעורפלת למודל קוד מסודר. בקורס ארכיטקטורת תוכנה שלנו עוברים גם על שאלות מהסוג הזה, לצד מקרי הבוחן המבוזרים יותר.
התכוננתם לשאלת עיצוב OOP בראיון ורוצים לתרגל עוד? הצטרפו לקהילה בדיסקורד ותביאו שאלה לתרגול.
לסיכום¶
עיצוב חניון בודק יכולת יסודית - לזהות מחלקות ואחריות מתוך תיאור בעיה בשפה חופשית, להשתמש בהורשה רק במקום שבו יש התנהגות שונה אמיתית, ולבחור תבניות עיצוב מתאימות כמו Strategy עבור לוגיקה שמשתנה. זו שאלה קטנה יחסית בהיקף שלה, אבל היא בודקת יסודות שחוזרים בכל מערכת קוד גדולה יותר.