לדלג לתוכן

מתכננים מערכת צ'אט לפני שכותבים שורת קוד אחת

יש הבדל עצום בין "לדעת להשתמש ב-WebSocket" לבין "לדעת לתכנן מערכת צ'אט". הפרויקט הזה הוא תרגיל תכנון - כותבים מסמך עיצוב (design doc) למערכת צ'אט בזמן אמת בסגנון פשוט של וואטסאפ או סלאק, לפני שנוגעים בקוד בכלל. זה בדיוק סוג התרגיל שמפריד בין מתכנת שיודע לכתוב פונקציה, לבין מהנדס שיודע לתכנן מערכת.

למה בכלל לתכנן לפני שכותבים קוד

תכנון לפני קוד נשמע כמו בירוקרטיה מיותרת, אבל זה בדיוק ההפך. מסמך עיצוב קצר חושף בעיות לפני שהן עולות לכם בשבועות של קוד שצריך לזרוק. זו גם מיומנות שנבדקת ישירות בראיונות עבודה בכירים תחת השם "System Design", ובניגוד לרושם הראשוני, אפשר לתרגל אותה לגמרי לבד - גם בלי לבנות את המערכת בפועל.

שלב 1 - מגדירים דרישות בסיסיות

לפני שקופצים לפתרון, צריך לשאול מה בדיוק המערכת חייבת לספק. עבור צ'אט, הדרישות הבסיסיות הן: מסירת הודעות בזמן אמת בין שני משתמשים או קבוצה, שמירת היסטוריית הודעות שנטענת כשמשתמש נכנס לשיחה, וידיעה אם משתמש מחובר כרגע (online presence). כבר בשלב הזה כדאי לשאול שאלות כמו - האם צריך אישורי "נקרא" (read receipts)? האם צריך תמיכה בקבוצות או רק שיחות אישיות? התשובות משפיעות ישירות על ההחלטות הבאות.

שלב 2 - למה WebSocket ולא polling

הדרך הנאיבית להעביר הודעות היא שהלקוח ישאל את השרת שוב ושוב "יש הודעות חדשות?" (polling). זה עובד, אבל זה בזבזני - רוב הבקשות חוזרות עם "אין כלום חדש", וזה גם מוסיף השהיה בין רגע שליחת ההודעה לרגע שהיא מגיעה. WebSocket פותר את זה בכך שהוא פותח חיבור אחד פתוח בין הלקוח לשרת, ששני הצדדים יכולים לשלוח דרכו הודעות בכל רגע בלי לפתוח בקשה חדשה כל פעם. זה בדיוק ההבדל בין להתקשר כל דקה לשאול "יש חדש?" לבין להשאיר שיחה פתוחה שבה כל צד מדבר כשיש לו מה להגיד.

שלב 3 - סכמת מסד נתונים להודעות

כאן מתחיל החלק שדורש חשיבה אמיתית. טבלת הודעות בסיסית צריכה שדות כמו מזהה שיחה, מזהה שולח, תוכן, וחותמת זמן. הנקודה הקריטית היא איך מאנדקסים אותה - כל שאילתה נפוצה היא "תביא לי את ה-50 ההודעות האחרונות בשיחה מסוימת", ולכן אינדקס מורכב על שילוב של מזהה שיחה וחותמת זמן חוסך המון זמן תגובה כשמספר ההודעות גדל. שיחה נפרדת - טבלה שמחזיקה את רשימת המשתתפים בכל שיחה, כדי לדעת מי בכלל רשאי לראות אותה.

שלב 4 - איך יודעים מי מחובר

מצב "online" נשמר בדרך כלל לא במסד הנתונים הראשי אלא במטמון מהיר כמו Redis, כי הוא משתנה כל הזמן ולא צריך היסטוריה שלו - רק את המצב הנוכחי. כשמשתמש מתחבר, השרת מסמן אותו כמחובר; כשהחיבור נסגר או אחרי חוסר פעילות, הוא מסומן כמנותק. זה שיקול תכנון קלאסי - לא כל נתון שייך לאותו סוג אחסון.

שלב 5 - שיקולי סקיילינג ברמה גבוהה

כשמערכת גדלה, שרת אחד לא מספיק להחזיק את כל חיבורי ה-WebSocket. הפתרון הנפוץ הוא כמה שרתים שכל אחד מחזיק חלק מהחיבורים, עם שכבת תקשורת בין השרתים (למשל תור הודעות) שמעבירה הודעה משרת שבו יושב השולח לשרת שבו יושב המקבל. זו לא רמת פירוט שצריך לממש בפרויקט לימודי, אבל חשוב להבין את הרעיון - ברגע שיש יותר ממשתמש אחד לשרת, הצ'אט הופך לבעיית תיאום בין שרתים, לא רק בעיית קוד.

מה מקבלים מהתרגיל הזה

אפילו בלי לכתוב שורת קוד אחת, כתיבת מסמך העיצוב הזה מלמדת יותר על ארכיטקטורה מאשר קורס שלם על תחביר. זה מכריח אתכם לחשוב על trade-offs במקום פתרונות "נכונים" מוחלטים, וזו בדיוק החשיבה שנדרשת בעבודה אמיתית כמהנדסי תוכנה בכירים.

אם אתם רוצים ללמוד לתכנן מערכות כאלה בצורה שיטתית, כולל דוגמאות נוספות ותרגול על מקרים אמיתיים, בקורס ארכיטקטורת תוכנה שלנו אנחנו עוברים בדיוק על התהליך הזה, שלב אחר שלב.

רוצים לשתף את מסמך העיצוב שלכם ולקבל פידבק? יש לנו קהילה בדיוק בשביל זה.

הצטרפו לקהילה בדיסקורד