ביטול המסתורין של מבוך התוכנה: צלילה עמוקה אל Domain Driven Design (DDD)

כריכת הספר Domain Driven Design
כריכת הספר

שלום לכולם,
בזמן האחרון אני קורא את הספר הנהדר Domain Driven Design (DDD).
ראיתי לא מעט המלצות על הספר הזה בזמן שקראתי דברים אחרים של Uncle Bob ושל Martin Fowler ובעוד כמה מקומות.
כולם ציינו שהספר הזה ישן אבל העקרונות שהוא מלמד עדיין רלוונטים היום, ויש שיגידו שהם קצת נשכחו.
אז החלטתי לצאת למסע ולנסות להבין על מה כל הסיפור

פתיח

פיתוח תוכנה יכול להיות משימה מרתיעה, בדומה לניווט ביער צפוף: מלא בז'רגון טכני, מסובך באבסטרקציות, ורדוף על ידי איום המורכבות.
בניית מערכות עבור דומיינים מורכבים, עם החוקים ההזויים שלהם והשוני הגדול בין כל אחד, יכול לבלבל כל אחד מאתנו.
אבל מסתבר שיש כמה אנשים שהשקיעו זמן ומחשבה על איך אפשר לשפר את התהליך.
אחד מהם הוא Eric Evans, מחבר הספר Domain Drive Design (DDD).

בלב ה-DDD: יישור הקוד עם המציאות של הדומיין

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

דמיינו בניית פלטפורמת מסחר אלקטרוני. עם DDD, אנחנו לא נתמקד רק ב-UML, איך נבנה את ה-DB שלנו, ואיזה API אנחנו צריכים לפתח; אלא אנחנו נצטרך לצלול גם לעולם התוכן, ההזמנות, המוצרים, ניהול המלאי ועיבוד התשלומים. אנחנו נצטרך להתמודד עם מושגים כמו: הנחות, קידום מכירות וחוקי משלוח. הבנה מעמיקה של הדומיין הופכת לבסיס של קבלת ההחלטות שלנו, כי בלעדיה אנחנו כנראה נפספס פרטים חשובים שיעלו לנו ביוקר מאוחר יותר.

שפה משותפת Ubiquitous Language: סגירת הפער בין קוד לדומיין

הדבר המרכזי איתו מתחיל אריק אוונס את הספר שלו הוא הדיבור על השפה האחידה – Ubiquitous Language. זוהי לא שכבה פיזית בתוך הארכיטקטורה אלא עקרון קריטי בחשיבה. הוא מעודד בחום פיתוח שפה משותפת עם כל ה-stakeholders בפרויקט, כולל מפתחים, אנאליסטים, ומומחי דומיין. דמיינו שכולם מדברים את אותה השפה, בלי קשר לידע הטכני שלהם! כמה בעיות זה יכול לפתור לנו.
השפה המשותפת הזאת יוצרת הבנה עמוקה יותר ומעודדת שיתוף טוב יותר בין כולם, ובעיקר מוודאת שהתוכנה משקפת את הדומיין.

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

Ubiquitous Language
Ubiquitous Language

בניית מצודת הדומיין: יצירת מודלים עשירים ושכבות

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

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

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

אבל DDD מזהה שמורכבת יכולה להתגנב בעדינות. כדי להיאבק בזה, אריק מציג את גישת השכבות שלו:

  • שכבת התצוגה: היוזרים שלנו עובדים ישירות מול השכבה הזאת, היא מטפלת באלמנטים של ה-UI, הקלט מהמשתמש, ובפלט בהתבסס על המודל של הדומיין והמידע שלו.
  • שכבת האפליקציה: בשכבה הזאת אנחנו עושים תיאום עם הלוגיקה העסקית שלנו, קוראים לאובייקטים של הדומיין ומתאמים אינטראקציות ביניהם. השכבה הזאת משמשת כמטווח בין שכבת התצוגה לשכבת הדומיין.
  • שכבת הדומיין: זהו הלב של ה-DDD. כאן ישהה כל המודל של הדומיין, ה-enteties, value objects, aggregates וכו' (נדבר על כל אלה תכף). השכבה הזאת מייצרת אינקפסולציה את עיקר הלוגיקה העיסקית וחוקי הדומיין מהשכבות האחרות. בסופו של דבר רוב הספר של אריק מתרכז בשכבה הזאת
  • שכבת התשתית: השכבה הזאת מספקת תשתית תמיכה טכנית. היא כוללת גישה ל-DB, הודעות ואיוונטים, ושירותים חיצוניים. יש לה אינטרקציה עם שכבת הדומיין בצורה לא ישירה דרך אינטרפייסים ו-repositories.

מעבר לתבניות: שינוי מחשבתי

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

מקונספט לקוד: אבני הבניין של DDD
בוא נרד קצת למטה ונהיה קצת יותר טכניים.
בחלק הזה אנחנו נסקור את אבני הבניין שבונות את הדומיין של המודל בקוד:

אבני הבניין של Domain Drive Design
אבני הבניין של Domain Drive Design
  • ישויות – Entities: עמודי התווך של הזהויות במערכת
    • מזהה ייחודי – כל entity מקבלת מזהה ייחודי שמפריד אותה מכל שאר האובייקטים במערכת, כולל כאלו שיש להם את אותם שדות בדיוק כמוהו.
    • התמדה – ל-entities יש זמן חיים גדול יותר מתהליך בודד במערכת, ולכן בדרך כלל אנחנו נשמור אותם באיזשהו DB.
    • בעלי שינוי – ה-entities הם mutable, כלומר אנחנו יכולים לשנות את הערכים שלהם לאורך זמן. זה מייצג את האופי המתפתח של הדומיין.
    • לדוגמה: במערכת של e-commerce, לקוח הוא entity עם מזהה ייחודי (סוג של ID), עם מידע שנשמר לאורך זמן (השם שלו, הכתובת וכו'), ומידע שנאגר לאורך זמן (היסטוריית הזמנות).
  • אובייקטים של מידע – Value Objects: אובייקטים ללא מזהה ייחודים שתפקידים להעביר מידע.
    • תיאור של מאפיינים או תכונות – אובייקטים מהסוג הזה מעשירים entities וקונספטים אחרים של הדומיין.
    • לא ניתנים לשינוי: אובייקטים מהסוג הזה הם Immutable. כלומר אחרי שיצרנו אותם אנחנו לא רשאים לשנות את הערכים שלהם.
    • זהים לפי ערכים ולא מזהה: שני value objects הם זהים אך ורק אם כל השדות שלהם זהים.
    • דוגמה:הזמנה יכולה לכלול שני אובייקטים:
      • הראשון הוא רשימה של entities אשר שייכים להזמנה הזאת, כלומר אילו מוצרים אנחנו שולחים.
      • השני הוא הכתובת של המשלוח – וזהו value object כי אין לזה מזהה והוא לא יכול להשתנות.
  • מקבצים – Aggregates: מאגרים של אובייקטים הקשורים אחד לשני.
    • קלאסטר של entities ושל value objects: הם יוצרים יחידה מלוכדת של עקביות, עם אובייקט שהוא הראש של הקלאסטר – aggregate root – שמהווה נקודת כניסה עבור אינטראקציות חיצוניות לקלאסטר.
    • שומר על אינווריאנטים: מוודא שהשינויים שרוצים לבצע על האובייקטים בתוכו שומרים על הלוגיקה שלהם.
    • דוגמה: במערכת e-commerce הזמנה יכולה להיות aggregate. היא מחזיקה תחתיה את כל המוצרים שאנחנו שולחים, את הלקוח, הכתובת ושאר הפרטים של ההזמנה. עדכון של כמות אחד המוצרים שמזמינים משפיעה על כמות הפרטים הכוללת של ההזמנה ושל המחיר הסופי, ולכן אנחנו צריכים לאגור הכל תחת root אחד כדי לשמור על עקביות.
  • מאגרים – Repositories: אלו הם שערים למידע של הדומיין.
    • הכמסה של הגיון שמירה ל-DB: האובייקטים האלו מהווים אבסטרקציה לאיך שומרים ומאחזרים מידע של אובייקטי הדומיין, וחוסכים לשכבת הדומיין את הצורך בלהבין בתשתית שאתה אנחנו עובדים.
    • מציע ממשק מרכזי לדומיין: מאשר למפתחים לבצע אינטראקציות עם אובייקטים של הדומיין בלי לחשוב יותר מדי על הפרטים הטכניים של איך הם עובדים.
    • דוגמה: למשל יכול להיות לנו OrderRepository שהוא ידאג לטפל בכל השמירה, אחזור, ועדכון של הזמנות עם המידע שלהם.
  • שירותים – Services: מתאמים לוגיקה של הדומיין
    • הכמסה של התנהגות של קשורה ל-entity או value object: האובייקטים מסוג service מטפלים בלוגיקה מסובכת שקשורה לכמה aggregates שונים.
    • שומר את הפוקוס על הקונספטים של הדומיין: הם בעצם מאפשרים לשמור את האובייקטים של הדומיין נקיים מבעיות טכניות ומחשבות על תשתית.
    • דוגמה: PaymentService , שירות תשלומים יכול לבצע אינטראקציה עם OrderAggregate ועם לקוחות ועם שירות תשלומים צד שלישי על מנת להכניס הגיון של ביצוע תשלומים אצלנו במערכת.
  • מפעלים – Factories: בדומה מאוד ל [[Factory Design Pattern]], הם אחראים ליצירה של כל האובייקטים במערכת.
    • אחראים שאובייקטים נוצרים בצורה עקבית ותקינה. ולפעמים אוכף היגיון של הדומיין בזמן היצירה.
    • מאפשרים גישה גמישה ו-testable בתוך המודל.
    • דוגמה: OrderFactory אחראי לוודא וליצור הזמנות במערכת. הוא מוודא שכל השדות הנדרשים ממולאים בצורה תקינה, ואוכף הגיון עסקי לפי שמוסיפים את ההזמנה למערכת.

המסע אל DDD: לאמץ את האתגר ולקצור את הפירות

ללמוד איך לשלוט ב-DDD זה מסע מתמשך, זהו לא היעד או המטרה שלנו. זה דורש למידה מתמשכת לאורך זמן, ניסוי וטעיה, והתבוננות לאחור. אבל עבור אלו שמוכנים לצלול אל מעמקי הדומיין, לאמץ את ה-mindset של DDD היתרונות הם משמעותיים:

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

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

קריאה נוספת

אם אתם רוצים להעמיק את הידע שלכם ב-DDD אז אני ממליץ על הרשימת הקריאה הבאה:

  • הספר עצמו: "Domain Driven Designs" מאת Eric Evan: אין כמו לקרוא את הספר עצמו כדי לקבל מאריק את התובנות שלו, ומהדוגמאות שלו להבין מה הוא מנסה ללמד.
  • בבלוג של Martin Fowler : מרטין כותב הרבה על DDD ונותן כמה דוגמאות נחמדות. בעיקר כדאי לקרוא את השימוש שלו ב-designs מסובכים
  • הספר "Implementing Domain-Driven Design" מאת Vaughn Vernon's: זהו מדריך פרקטי של איך לוקחים את העקרונות של אריק ומממשים אותם בפרויקט גדול.

סיכום

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

השאר תגובה

Scroll to Top