2021-03-10

תכנון ופיתוח תוכנה: מידול קונספטואלי

כבר כמה זמן שאני רוצה לזקק את תחום תכנון (Design) יעיל של תוכנה. זה תחום שיש בו מקום למיומנות רבה, אבל מאתגר מאוד ללמד. בכדי להתמודד עם האתגר, אתמקד בפן אחד (להלן Divide & Conquer) של אומנות ה Design: מידול.

"מידול", כצפוי, הוא מונח overloaded עם כמה משמעויות נפוצות. נעשה לרגע סדר בדברים:

  • משתמשים במונח "מידול" כתהליך ההצגה של העיצוב (Design). כמטאפורה: אדריכל שבונה מודל מוקטן של הבית בכדי להציג אותו ללקוחות.
    • כאן נכנסות "שפות מידול" (UML, ERM, ADL), ומתודולוגיות מסוימות (C4, ATAM, 4+1 Views). הטכניקות הללו מעט ארכאיות לתקופתנו ואני לא מתכוון לעסוק בהן.
  • משתמשים במונח "מידול" כדי לתאר רעיון של יצירת מודל מפורט/מדויק שיחליף את הקוד / נחולל קוד ממנו. כאן המודל הוא פורמאלי, מדויק, ודורש עבודה ותחזוקה רבה. ניתן לאפיין כאן שתי גישות עיקריות:
    • מידול מבנה או נתונים - בגישות כמו Model Driver Architecture (קרי MDA), או מידול של בסיסי נתונים.
    • Semantic Modeling עבור מערכות לעיבוד שפה טבעית או Ontology modeling (אונטולוגיה - הגדרת קשרים בין מונחים) ליישומים יותר כללים של בינה מלאכותית.
    • אני לא מתכוון לעסוק בנושאים הללו בפוסט.
  • משתמשים במודל "מידול" כתהליך ביניים באיסוף דרישות, תיאור העולם / צרכים / דרישות בצורה מאורגנת ומדויקת יותר - לפני שמייצרים את העיצוב הטכני וכותבים קוד. הדרך המקובלת ביותר לתאר מודל מסוג זה היא מודל קונספטואלי (Conceptual Modeling) ועליו אני הולך לדבר בפוסט הזה.
    • על אף שראיון המודל הקונספטואלי נמצא בשימושים כבר עשורים, רבים מקשרים אותו למתודולוגית ה Domain-Driven-Design (בקיצור: DDD) - שהביאה אותו לחזית הבמה / הפכה אותו לקצת יותר מדובר ופופלארי בתחילת שנות ה 2000.



פאק! מעולם לא הגדרתי מודל קונספטואלי. האם זה אומר שאני עושה Design גרוע?!


תנו לי להרגיע: היה לכם מודל קונספטואלי בכל ה Designs שעשיתם. פשוט לא ידעתם את זה.

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

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

הבעיה במודלים קונספטואליים היא שאנשים שונים בונים לעצמם בראש מודלים שונים, כל אחד "והאמת שלו". למה זו בעיה? האם לא טוב שיש מעט שונות (Diversity) / נקודות מבט מגוונות?

ראו גם: Mental modelRepresentation (psychology), and Cognitive model

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

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

משמעות נוספת של האמירה הזו היא שלא ננסה אפילו "למדל" את כל הביזנס ומה שקורה בו - אלא רק איים מרכזים / חשובים בביזנס - שגורמים לנו לבעיה בכתיבת המערכת.


איך מגדירים מודל?

כל תרשים או טקסט הם טובים מספיק. המרכיבים שבעזרתם מגדירים מודלים מורכבים בעיקר מ:

  • ישויות (Entities)
  • קשרים (Relations)
  • תכונות (attributes) של הישויות. אולי גם מתודות.
  • הכללה / ריבוי-צורות.
  • הבחנה בין מחלקה/קבוצה למופע (instance).
  • כלי עזר: טקסט.
  • כלי עזר: קוד.

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

הדרכים הנפוצות להגדיר מודל, שאני נתקלתי בהן, הן pseudo-UML (לא צריך לדקדק), קוד, או פשוט מסמך וורד/מצגת.

מודל אינו נכון / לא נכון, אלא יעיל / לא יעיל.

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


דוגמה למודל קונספטואלי


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

הנה, למשל, כמה אפשרויות למודלים שונים לכסף (Money), איזה הוא המוצלח לדעתכם?

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

הערה: לא פעם אנשים יתקשו לתאר את המודלים ש"יש להם בראש", אל אף שהוא עקבי ולעתים אף מפורט. אם אלו אנשי-תוכנה, לפעמים עוזר לבקש פשוט מאוד לכתוב קוד / סכמה של בסיס נתונים כדי לנסות ולשחרר את "מחסום התקשורת".

ובכן, מתוך ארבעת המודלים של Money, איזה מודל הוא המתאים / המוצלח ביותר?

כמובן, כמובן - שכל מודל מתאים לכל סיטואציה. יש מערכות / מקרים בהם מודל #4 הוא מספיק טוב - ואז מודל מורכב יותר יסרבל את הפיתוח ללא סיבה. יש פעמים שמודל #3 הוא טבעי ויש מקרים בהם הוא לא-קשור-למציאות.

שווה לציין שהמודל הוא ספציפי לביזנס ולמערכת הספציפית. אין טעם למדל פרטים שלא רלוונטיים לביזנס הספציפי ו/או המערכת לא מתכוונת לכסות ולטפל בהם.

המודל גם מתאר tradeoffs טכנולוגיים. במקרה שלנו: מחשב ספרתי, בו כל מספר הוא כפולה של 2, אינו יכול לייצג בדיוק מספר כמו 1.1 - סכום לגיטימי לחלוטין לכסף. יש דרכים שונות להתמודד עם האתגר, ולא "לאבד" סנטים בעקבות פעולות חשבוניות / פעולות עיגול. למשל: שימוש ב Big Decimal או הייצוג הסנטים כמספר שלם (Long).

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


תהליך יצירת המודל הקונספטואלי, מתוך מסמך אקדמי משעמם.




אז איך אפשר "לדפוק" מודל קונספטואלי?


עד כה, יכול להיות שאתם אומרים לעצמכם: "ברור!" \ "זה פשוט" \ "זה בדיוק מה שאני כבר עושה". כל זה - טוב ויפה. 

בכל זאת, פעולות מידול פעמים רבות מבוצעות בצורה מגושמת ולא כ"כ יעילה. אולי כדאי להתבונן על כמה דרכים בהן תהליך המידול יכול להשתבש:


"האחרון להבין ולזהות" 

הבעיה הנפוצה ביותר, כנראה, שלא מבינים שמדובר בבעיית מידול / תקשורת. מנסים למצוא את הפתרונות במקום אחר, ואולי פשוט להתעלם:

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

"מודל טוב מדי"

זה אולי לא נשמע כ"כ רע - אבל זו טעות נפוצה וכואבת. 

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

הכל נעשה מכוונה טובה, אבל חשוב לשים לב שתהליך מידול לא הופך בטעות ל Over-Engineering. הוא בקלות יכול להגיע לשם.


"מודל נאיבי"

לא פעם אפשר לסיים את עבודת המידול בשיחה קצרה בת 30 דקות: הצלחה גדולה (!), ויוצאים לדרך.

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

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

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

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


מודל אלגנטי יותר מהביזנס

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

  • לכל מכירה יש תעודת משלוח אחת - בעוד בביזנס, בשל מורכבות אופרטיבית, לעתים מנפיקים (בטעות) שתי תעודות משלוח שונות לאותה ההזמנה.
  • זיכוי יהיה כסכום החיוב - בעוד בפועל לעתים מזכים יותר או פחות בשל נסיבות ("פיצוי", "קיזוז") שונות שלא נכנסות למודל.
תת-וריאציה היא פשוט תקלות טכניות (הרבה פעמים: בצד התוכנה), שאנו נוטים לשכוח / לא מכירים בזמן המידול:
  • ללקוח יש Cookie שמזהה אותו בצורה מדויקת - בעוד חלק לא זניח מהמשתמשים, מתקינים "חוסם פרסומות" שמוחק Cookies, והמידע לא שלם.
  • ה GPS מדווח במדויק את נקודת ההתחלה והסיום של הנסיעה - בעוד בפועל בשם טעויות / רמאויות קטנות של נהגים, המידע לעתים שגוי או אפילו חסר.


תקשורת לקויה / חסרה

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

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


מודל חד-כיווני

"אלו הן הדרישות של הביזנס" - הוא משפט שגור, שמהווה smell לבעיה הזו.

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

הרבה פעמים, יש ליקויים או חוסרי-יעילות. בתהליכים בהם הביזנס עובד. כאשר אנחנו ממדלים את הליקויים האלו והופכים אותם לתוכנה:

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


"מודל אחד לשלוט בכולם"

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

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


כמובן ששני מודלים שונים עשויים לגרום לבלבול וטעויות. חשוב להגדיר bounded context - גבולות ברורים וחד משמעיים ואלו חלקים במערכת ובביזנס משתמשים במודל א' ואלו במודל ב'. כמו כן חשוב תרגום טוב מספיק בין המודלים - בנקודות החיבור של המערכת ב contexts השונים. יש המציעים בהשנות מקרים כאלו ליצור context map - מיפוי של כל ה contexts, הגבולות, והתרגומים בין המודלים ה"חופפים". "Good fences make good neighbours" - הם אומרים. 


מודל תוכנה השונה מדי מהמודל הקונספטואלי


מודל קונספטואלי הוא מחשבות / רעיונות / סדר - המוצגים בתרשימים, מסמכים ולעתים קצת קוד (יש כאלו שיאמרו - "כתבו interfaces").

מודל הקוד הוא המחלקות בפועל של התוכנה, החתימה של הפונקציות, והסכמה של בסיס הנתונים או ה documents הנשמרים ב Mongo או ב S3.

אפשר ליצור אותם שונים זה מזה, אפילו במידה ניכרת.

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

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

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



סיכום


אם הייתם שואלים אותי איך לעשות Design טוב יותר, או איך להיות אנשי תוכנה טובים יותר - אני בטוח שתחום המידול צריך להיות תחנה חשובה בדרך.

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

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

לא נכנסתי לטכניקות קונקרטיות / מפורטות יותר של מידול - כי אין הרבה כאלו. כלומר יש את Event Storming ויש כאלו שיחשיבו את CRC Cards כטכניקה של מידול (דיי דומה, למען האמת) - אבל סה"כ אין הרבה טכניקה מדוייקת שאני יודע לקשר לנושא.

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

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


שיהיה בהצלחה!



7 תגובות:

  1. אנונימי14/3/21 09:36

    פוסט מעולה, תודה!
    שים לב לשגיאת כתיב בכותרת-
    אז **איף** אפשר "לדפוק" מודל קונספטואלי?

    השבמחק
    תשובות
    1. תודה!

      אכן שגיאה מביכה. תוקנה. תודה שוב!

      מחק
  2. נ.ב. שמתי לב לשגיאת כתיב במילה ambiguous. מכיוון שזה צרוב בתמונה - נדרשת קצת יותר עבודה לתקן.

    השבמחק
  3. פוסט מצויין, תודה רבה!
    תקלדה נוספת בפסקה השלישית מהסוף - "...דיי דומה, למעל האמת..."

    השבמחק
    תשובות
    1. תודה ניר על הפרגון, תודה על תפיסת שגיאת הכתיב.
      תיקנתי.

      מחק
  4. כרגיל פוסט מעולה. תודה!

    בעיני משפטי המפתח הם:
    "תנו לי להרגיע: היה לכם מודל קונספטואלי בכל ה Designs שעשיתם. פשוט לא ידעתם את זה."
    "אנו מגדירים אותו כאשר אנחנו מזהים בעיית תקשורת משמעותית."
    "לפעמים עוזר לבקש פשוט מאוד לכתוב קוד"

    המודל הקונספטואלי קיים בראש של המפתח, והקוד הוא הדאמפ של המודל למדיום שהוא קריא על ידי אחרים.

    השבמחק