מה הפואנטה של MVVM ?

19 בינואר 2011

9 תגובות

למה אני צריך את זה בכלל?!

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

התיעוד של פריזם מספקת דוגמא מאוד טובה לבעייתיות שאליה אני מתכוון… – רוב רובו של התיעוד בנוי כך – בשביל לממש A יש לבצע B, בשביל לממש C יש לבצע D.. בהרבה מאוד מקומות שמתמשים בפריזם נופלים ללא מעט טעויות בגלל שאת השאלה הבסיסית, למה, שוכחים טיפה לשאול. (וזה חבל היות וסה"כ פריזם היא לא פריימוורק רע.. פשוט משתמשים בו מאוד רע ברוב המקרים)

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

מה MVVM נותן לי?

MVVM דומה מאוד לMVC, רק שהוא טוב ממנו בכל פרמטר (MVVM זה לא רק MVC לWPF, זה שדרוג מאוד משמעותי של MVC). MVVM נותן לי כל מה שMVC נותן לי, רק יותר טוב.

טוב, אז מה MVC נותן לי? (או: תשמעו שאלה מטופשת)

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

עקרונית, בMVC אנו נפריד את הקוד שלי לשלוש שכבות נפרדות – Model, View, Controller.

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

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

אז… לכאורה לממש MVC זה כבר בילט אין בWPF!

הXAML זה הView.

הCodeBehind זה הקונטרולר,

והDAL יהיה המודל!

השאלה לא כל כך טריוויאלית כמו שהיא נראית, למרות שהיא בפירוש שגויה.

אז כמובן שזו טעות. זה בפירוש לא MVC. אבל.. למה?

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

MVC מספק לי שלושה דברים חשובים

1. יכולת תחזוקה קלה ויעילה של הקוד. קוד של לוגיקה לא מעורב בקוד של UI ולכן הרבה יותר קל לכתוב פרוייקט מורכב, והרבה יותר קל לתחזק אותו/ לדבג אותו.

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

3. יכולת נוחה יותר של עבודה עם שכבת הUI, היות וVisual Studio יצליח יותר בקלות להציג לנו את הView בDesign Time – היות ואין שם באמת קוד – רק XAML. (ספציפית לWPF/SL, למרות שזה נכון גם בwinforms).

שלושת היכולות החשובות הללו – תחזוקה קלה, הרצת טסטים, תמיכה טובה יותר לDesigner של Visual Studio – הן למעשה מושגים מאוד חשובים בעולם ארכיטקטורת הUI –

Maintainability, Testability, Blendability

1. Maintainability – יכולת תחזוקה קלה.

2. Testability – היכולת להריץ מבחנים אוטומאטיים (UT)

3. Blendability – היכולת לעבוד עם Cider, הdesigner של Visual Studio, או עם Expression Blend (ומכאן מגיע השם).

הסיבה שCode Behind הוא לא מימוש באמת טוב של MVC זה בעיקר בגלל סעיפים 1 ו2. CodeBehind לא נותן הפרדה טובה, ולכן יש קושי רב בבניית אפליקציות שקל לתחזק, ושקל להריץ עליהם מבחנים אוטומאטיים. זה נובע מכך שההפרדה בין הXAML לCodeBehind היא לא באמת הפרדה. הם שניהם חלק מאותה המחלקה, מה שאומר ש:

1. הצימוד ביניהם (הCoupling ביניהם) מאוד גבוה. אי אפשר להפריד ביניהם, ולמעשה אין לי כאן הפרדה טובה בין קוד של UI לקוד של הלוגיקה של האפליקציה.

2. נובע מ(1) – אין לי אפשרות להרים מופע של הCode Behind ללא ה XAML, ולפיכך אין לי שום יכולת להריץ עליו UnitTesting בנפרד (Unit Testing => המטרה היא לבחון כל רכיב בפני עצמו בלבד, לפני כל מבחן אחר), ובנוסף להריץ UT על XAML די בלתי אפשרי… (יש אפשרות לבצע UI Testing אבל זהו נושא אחר..)

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

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

MVVM הולך בגישה שונה והרבה יותר חזקה.

אם נחזור לדוגמא של XAML וCodeBehind, ההפרדה שם כבר יחסית די טובה.. הבעיה היא שהCodeBehind ניגש ישירות לXAML על מנת לשלוט בו, ובנוסף הXAML מכיל לא מעט קישורים לCodeBehind (כדוגמא, רישום של Events). שני החלקים מאוד תלויים אחד בשני, מה שלמעשה הורס את כל ההפרדה. יחד עם זאת, יש לנו כאן כבר חצי פיתרון – כל מה שאנחנו צריכים זה להפריד את שני החלקים. אם נחליט שאסור לגשת לXAML מהCodeBehind, ואסור לXAML להכיל קישור ישיר לCodeBehind, למעשה נקבל הפרדה מאוד טובה, ואפילו יותר טובה מMVC!

יש רק בעיה אחת… אם אסור להם לגשת ישירות אחד לשני.. אז איך הם אמורים לתקשר?

כאן נכנסים שני פיצ'רים מאוד חזקים של WPF/SL – Binding ו Commands.

Binding – יעביר מידע בין הCodeBehind לXAML.

Commands – יאפשרו הרמת אירועים מהXAML לCodeBehind, רק שאלו Weak Events (עוד על זה בהמשך). Commands מאוד דומים לEvents, רק שהם מהווים קישור יותר קל, היות וEvent שמוגדר בXAML – אם אין לו Event Handler ב CodeBehind יגרור זריקה של שגיאה, בעוד Commands לא יזרקו שגיאה.

למעשה, CodeBehind וXAML שלא מדברים ישירות בכלל אחד עם השני מהווים הפרדה מאוד מאוד טובה. כל כך טובה, שאפשר לשים את הCodeBehind במחלקה אחרת (נקרא לה ViewModel לצורך העניין).

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

הפואנטה של MVVM

1. Blendability – ברמות שMVC יכול רק לחלום עליו. אנו נראה בהמשך שזו תכונה חשובה מאין כמוה, המאפשרת כתיבה הרבה יותר מהירה וקלה מאי פעם.

2. Maintainability – תחזוקת הקוד יותר קלה בMVVM היות ובViewModel אין גישה ישירה לView, ולפיכך MVVM שומר על עקרון ה SRP (Single Responsibility Principle – אחריות אחת בלבד לכל רכיב) יותר טוב בהרבה. הContoller בMVC ניגש גם לModel וגם לView, ולפיכך מפר עיקרון זה.

3. Testability – בניגוד לMVC, שמצריך שימוש בInterface על מנת להפריד בין הקונטרולר ובין הView, ובכך לאפשר בדיקה של הController בפני עצמו (וזה סיפור די מסורבל ומציק סה"כ – להגדיר interface לכל view…) MVVM הרבה יותר אלגנטי.

הViewModel לא מכיל שום קישור לView, ולכן מוכן אוטומאטית לUnitTesting. אלגנטיות במיטבה 🙂

מתי נשתמש בMVVM?

Blendability, Maintainability, Testability – שלושתן יכולות מאוד חזקות ומאוד חשובות שמתאפשרות ע"י ההפרדה של השכבות בMVVM, וככל שהפרוייקט יותר גדול ככה הכוח שלהן יותר משמעותי.

אבל.

מימוש של MVVM לפעמים יכול להיות לא כל כך פשוט, כפי שנראה בהמשך. ישנן כמה בעיות שצצות כתוצאה מההפרדה החזקה בין הViewModel ל View. לפחות בתחילת הדרך, המעבר לכתיבה בMVVM לא כל כך פשוט.. אז מתי כדאי להתאמץ ולכתוב בMVVM?

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

אז מה הלאה?

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

הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *

9 תגובות

  1. Jasper20 בינואר 2011 ב 10:12

    מה זה "פיצ'רים" ??

    "כאן נכנסים שני פיצ'רים מאוד חזקים של WPF/SL – Binding ו Commands"

    הגב
  2. Rotem Bloom20 בינואר 2011 ב 14:32

    אחלה של סידרת מאמרים שנושא מאוד חשוב.
    תודה על השיתוף

    הגב
  3. שחר אלדד23 בינואר 2011 ב 9:02

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

    תודה 🙂

    הגב
  4. zvi11 באוגוסט 2011 ב 1:44

    שאלה – אם ככה אלעד למה בכלל ציך את הקוד בהיינד? למה זה משמש? האם יש לו שימוש בארכיטקטורת MVVM

    הגב
  5. eladkatz16 באוגוסט 2011 ב 22:43

    zvi:

    You don't need the code behind. MSs original thought (2001) was that code behind gives us a strong-enough separation between logic and ui. turns out it doesn't.

    I'm not saying that you should never ever use codebehind, but that codebehind tends to become bad code and therefor u should try to avoid it.

    הגב
  6. חן27 בדצמבר 2011 ב 7:47

    מאמר מעולה !
    ממתין למאמרים נוספים בנושא

    תודה,
    חן

    הגב
  7. חגית21 ביוני 2012 ב 19:45

    מאמר מעולה!! מסביר הכל ובפשטות!!
    תודה 🙂

    הגב
  8. חזי12 באפריל 2013 ב 1:27

    בדיוק המידע שחיפשתי. תודה רבה!

    הגב
  9. assaf19 בפברואר 2014 ב 14:34

    סיכום מעולה, רמה גבוהה, שפה פשוטה
    יישר כוח!

    הגב