ארכיטקטורת שכבות מוסברת¶
אם כתבתם אי פעם אפליקציית ווב עם קונטרולרים, שירותים (services), ומודלים של מסד נתונים - אתם כבר משתמשים בארכיטקטורת שכבות, גם אם אף אחד לא הסביר לכם את זה בשם הזה. זו ככל הנראה הארכיטקטורה הכי נפוצה בעולם, כי היא פשוט הגיונית ברמת האינטואיציה.
הרעיון המרכזי - חלוקת עבודה לפי תפקיד¶
ארכיטקטורת שכבות (layered architecture) מחלקת את המערכת לשכבות אופקיות, כשכל שכבה אחראית על סוג אחד של אחריות, ומדברת רק עם השכבה שממש מתחתיה. המבנה הקלאסי כולל בדרך כלל שלוש עד ארבע שכבות:
- שכבת הצגה (Presentation Layer). הכל מה שקשור לאיך המשתמש מתקשר עם המערכת - דפי ווב, API endpoints, ממשק שורת פקודה. השכבה הזאת מקבלת קלט מהמשתמש ומציגה לו תוצאות, בלי לדעת בעצמה איך העסקה מבוצעת.
- שכבת לוגיקה עסקית (Business Logic Layer). כאן נמצאים החוקים והתהליכים האמיתיים של המערכת - חישוב הנחות, אימות הרשאות, כללי אישור הזמנה. השכבה הזאת לא יודעת אם הבקשה הגיעה מדפדפן או מאפליקציית מובייל, ולא יודעת אם הנתונים נשמרים ב-Postgres או ב-MongoDB.
- שכבת גישה לנתונים (Data Access Layer). אחראית על כל התקשורת עם מסד הנתונים - שאילתות, שמירה, עדכון. השכבה הזאת מספקת ממשק נקי לשכבה שמעליה, בלי לחשוף פרטים טכניים כמו איך בדיוק בנויה שאילתת SQL.
- שכבת מסד הנתונים (Database Layer). לפעמים נספרת כשכבה נפרדת - זה מקום האחסון הפיזי בפועל.
הכלל שהופך את זה לארכיטקטורה, לא סתם תיקיות¶
חלוקה לקבצים בלבד היא לא מה שהופך את זה לארכיטקטורת שכבות אמיתית. הכלל המחייב הוא שכל שכבה מדברת רק עם השכבה שמתחתיה ישירות, ולא מדלגת. שכבת ההצגה לא ניגשת ישירות למסד הנתונים - היא תמיד עוברת דרך שכבת הלוגיקה העסקית. אם קונטרולר ב-Flask כותב שאילתת SQL ישירות בתוכו, ויתרתם על ההפרדה, וקיבלתם קוד מבולגן שנראה כמו שכבות אבל לא מתנהג כמו שכבות.
הכלל הזה חשוב כי הוא נותן שני יתרונות מרכזיים - כל שינוי בשכבה אחת נשאר מבודד, וכל שכבה אפשר להחליף בלי לגעת בשאר. רוצים להחליף את מסד הנתונים? רק שכבת גישת הנתונים משתנה. רוצים להוסיף אפליקציית מובייל בנוסף לאתר? רק שכבת ההצגה מקבלת תוסף, שכבת הלוגיקה העסקית נשארת בדיוק כמו שהיא.
דוגמה מהחיים האמיתיים¶
נניח שרוצים לבצע פעולה "רישום משתמש חדש". שכבת ההצגה מקבלת את הבקשה מה-API, מוודאת שהשדות הבסיסיים קיימים בפורמט תקין, ומעבירה אותה לשכבת הלוגיקה העסקית. שם, UserRegistrationService בודק שהאימייל לא כבר בשימוש, מוודא שהסיסמה עומדת בדרישות אבטחה, ומחשב ערכים נגזרים כמו תאריך תפוגה של תקופת ניסיון. רק אז הוא קורא לשכבת גישת הנתונים כדי לשמור את המשתמש בפועל. שכבת ההצגה בכלל לא יודעת שיש כלל כזה או אחר, ושכבת גישת הנתונים בכלל לא יודעת למה המשתמש נוצר.
היתרונות שהופכים את זה לברירת מחדל טובה¶
- קלה להבנה. כמעט כל מפתח מכיר את המבנה הזה, אז חברי צוות חדשים מתמצאים מהר.
- בדיקות ממוקדות. אפשר לבדוק את שכבת הלוגיקה העסקית בנפרד משכבת ההצגה או מסד הנתונים.
- הפרדת אחריות ברורה. קל לדעת איפה לחפש כשמשהו נשבר - אם התצוגה שגויה, מסתכלים בשכבת ההצגה, אם החישוב שגוי, בשכבת הלוגיקה.
המגבלות שכדאי להכיר¶
ארכיטקטורת שכבות לא חפה מבעיות. השכבות מבודדות מבחינת קוד, אבל הן עדיין רצות באותו תהליך ונפרסות יחד - זה עדיין בעצם מונוליט מבפנים, רק מאורגן. ובמערכות גדולות מאוד, בקשה שצריכה לעבור דרך כל השכבות בכל פעם יכולה להוסיף תקורת ביצועים מיותרת אם לא נזהרים. וכן, יש נטייה של מפתחים לפעמים "לחתוך פינות" ולדלג שכבות כשלוחצים בזמנים - וברגע שזה קורה, כל היתרון של הארכיטקטורה נשחק.
ארכיטקטורת שכבות היא בדיוק סוג הבסיס שאנחנו מתחילים ממנו בקורס ארכיטקטורת תוכנה, לפני שעוברים לארכיטקטורות מורכבות יותר כמו מיקרוסרביסים או ארכיטקטורה מונעת אירועים - כי הבנה טובה של שכבות היא התשתית להבין כל דבר אחר.
מתלבטים איך לחלק פרויקט קיים לשכבות בלי לפרק הכל מחדש? דברו איתנו בדיסקורד.
לסיכום¶
ארכיטקטורת שכבות מחלקת מערכת לפי תפקיד - הצגה, לוגיקה עסקית, וגישה לנתונים - כשכל שכבה מדברת רק עם זו שמתחתיה. זו לא הארכיטקטורה הכי מתוחכמת שיש, אבל היא פשוטה, מוכרת, וברירת מחדל מצוינת לרוב הפרויקטים. הכלל היחיד שבאמת חשוב לשמור עליו הוא לא לדלג שכבות, גם כשזה מפתה לחסוך זמן.