Monolith — יתרונות, חסרונות ו-Strangler Fig
מה זה?
ה-Task Manager API שנבנה לאורך הקורס — Controllers, Services, Repositories — כולו רץ כתהליך אחד, נפרס יחד. זה מונוליט (Monolith): אפליקציה אחת שלמה. עובד מצוין בהתחלה — עד שהצוות גדל, חלקים שונים צריכים להתעדכן בקצב שונה, וכל שינוי קטן דורש לבנות ולפרוס הכל מחדש. מיקרוסרביסים פותרים את זה, אבל לא בקפיצה אחת — Strangler Fig הוא הדפוס לפירוק הדרגתי.
מילות מפתח שחשוב לזכור
• Monolith — אפליקציה שלמה אחת, נפרסת ורצה כיחידה אחת, גם אם מאורגנת פנימית בשכבות (Controller/Service/Repository)
• Microservices — פירוק לשירותים עצמאיים קטנים, כל אחד נפרס ומתעדכן בנפרד
• Strangler Fig Pattern — פירוק הדרגתי של מונוליט: פונקציונליות חדשה נבנית כשירות נפרד, ישן מהגר בהדרגה, בלי “big bang rewrite”
• Coupling (צימוד) — כמה חלקים תלויים זה בזה; מונוליט לרוב צימוד גבוה בין מודולים פנימיים
flowchart TB
subgraph Monolith["Monolith — everything together"]
C1["Tasks Controller"] --> S1["Task Service"]
C2["Users Controller"] --> S2["User Service"]
S1 --> DB[("Single DB")]
S2 --> DB
end
flowchart TB
subgraph Micro["Microservices — separate and independent"]
TS["Task Service<br/>(deployed separately)"] --> TDB[("Task DB")]
US["User Service<br/>(deployed separately)"] --> UDB[("User DB")]
TS <-.->|"network communication"| US
end
הסבר עיקרי
מונוליט לא “רע” — הוא ברירת המחדל הנכונה להתחלה — כל הפרויקטים לאורך הקורס עד כה היו מונוליטים, ובצדק: פיתוח, בדיקה ופריסה של מערכת אחת פשוטים בהרבה מניהול כמה שירותים נפרדים. הבעיה מתחילה כשהצוות/המערכת גדלים — שינוי קטן ב-Users דורש לבנות ולפרוס מחדש גם את Tasks, Orders וכל השאר, גם אם הם לא השתנו כלל.
Strangler Fig — למה לא לפרק הכל בבת אחת — “Big Bang Rewrite” (עצירת כל הפיתוח, פירוק מלא, ואז המשך) הוא מסוכן ויקר — לוקח חודשים, בלי ערך עסקי חדש בינתיים, וסיכון גבוה לשבור דברים. Strangler Fig פותר את זה: בונים פונקציונליות חדשה כשירות נפרד מההתחלה; פונקציונליות קיימת מפורקת בהדרגה, מודול אחד בכל פעם, כשיש לכך הצדקה עסקית — המונוליט “מצטמצם” בהדרגה בעוד המערכת ממשיכה לעבוד לאורך כל התהליך.
Coupling הוא הסימפטום שמסמן מתי לשקול פירוק — לא “יש לנו הרבה קוד” אלא “מודול A ומודול B כל כך תלויים זה בזה ששינוי באחד תמיד שובר את השני”. אם TaskService ו-UserService (בתוך אותו מונוליט) כמעט אף פעם לא “נוגעים” זה בזה, הם כבר מועמדים טבעיים לפיצול לשירותים נפרדים — הצימוד הפנימי כבר נמוך.
יתרונות
מונוליט: פיתוח ופריסה פשוטים, עסקאות (Transactions) עקביות בקלות בין מודולים, ניפוי שגיאות (Debugging) ישיר בתוך תהליך אחד. מיקרוסרביסים: כל שירות נפרס ומתעדכן עצמאית, צוותים שונים עובדים במקביל בלי להתנגש, כשל בשירות אחד לא בהכרח מפיל את כולם.
חסרונות
מונוליט: פריסה אחת = כל השינויים יחד, קשה לצוותים גדולים לעבוד במקביל בלי להתנגש, כשל אחד עלול להפיל הכל. מיקרוסרביסים: מורכבות תפעולית גדולה יותר (רשת, ניטור, פריסה נפרדת לכל שירות), עקביות בין שירותים דורשת תכנון קפדני (Kafka שכבר נלמד הוא חלק מהפתרון).
נקודות חשובות
• מונוליט הוא ברירת מחדל טובה להתחלה — לא “טעות” שצריך לתקן תמיד
• Strangler Fig מפרק בהדרגה, לא בבת אחת — פונקציונליות חדשה כשירות, ישנה מהגרת לפי הצדקה
• Coupling גבוה בין מודולים הוא הסימן לשקול פירוק, לא “כמות קוד” בפני עצמה
• מיקרוסרביסים פותרים בעיית ארגון/קנה-מידה, לא בעיה טכנית מובנית מאליה בכל פרויקט
טעויות נפוצות
• לפרק לפי מיקרוסרביסים “כי זה מודרני”, בלי בעיה אמיתית של קנה-מידה/צוות שמצדיקה זאת
• לנסות Big Bang Rewrite במקום Strangler Fig — סיכון גבוה מיותר
• להתעלם מ-Coupling פנימי לפני פירוק — שירותים שנחתכו לאורך “קו תפר” שגוי נשארים תלויים זה בזה דרך הרשת, גרוע יותר מבתוך אותו תהליך
סיכום
מונוליט הוא אפליקציה שלמה אחת, נפרסת יחד — ברירת מחדל מצוינת להתחלה. מיקרוסרביסים מפרקים למערכות עצמאיות, פותרים בעיות של קנה-מידה וצוותים גדולים, במחיר מורכבות תפעולית. Strangler Fig הוא דפוס הפירוק המומלץ — הדרגתי, לפי הצדקה עסקית, לא Big Bang Rewrite מסוכן. Coupling נמוך בין מודולים הוא הסימן שמערכת “מוכנה” לפירוק בקו התפר הנכון.
דוקומנטציה רשמית
Martin Fowler — Strangler Fig Application
תרגילים
תרגיל 1 — זיהוי Coupling
המשימה: קחו את ה-Task Manager API (מהפרויקטים המסכמים) וסמנו אילו מודולים (Tasks/Users/וכו’) כמעט לא “נוגעים” זה בזה, לעומת אילו תלויים זה בזה הדוקות.
בדיקה: רשימה עם נימוק לכל מודול — האם הוא מועמד טוב לפיצול, ולמה.
תרגיל 2 — תכנון Strangler Fig
המשימה: תכננו (בכתב, בלי קוד) תוכנית פירוק הדרגתית של מודול אחד מתוך ה-API הקיים לשירות נפרד, בשלושה שלבים.
בדיקה: התוכנית מראה איך המערכת ממשיכה לעבוד בכל שלב, לא רק “לפני” ו"אחרי".
פרויקט מסכם
המשימה: כתבו ניתוח קצר (מסמך) על מונוליט קיים (יכול להיות Task Manager API מהקורס) — מתי (אם בכלל) הגיוני לפרק אותו למיקרוסרביסים.
דרישות:
- זיהוי לפחות 2 “קווי תפר” טבעיים (מודולים בעלי Coupling נמוך ביניהם)
- נימוק עסקי — למה כדאי/לא כדאי לפרק כרגע (גודל צוות, קצב שינויים, עומס)
- תוכנית Strangler Fig בת 3 שלבים לפחות לאחד הקווים שזוהו
בדיקה: הניתוח מבוסס על Coupling אמיתי בקוד, לא רק “מודולים שנשמעים נפרדים”; תוכנית הפירוק הדרגתית ולא Big Bang.
מה בפרק הבא
בפרק הבא — Bounded Context: איך מחליטים בדיוק איפה לחתוך — עקרונות DDD בסיסיים לפירוק לפי יכולת עסקית, לא לפי טבלת DB או שכבה טכנית.