2012-07-31

ארכיטקטורה: Quality Attributes (חלק ב' - כיצד משתמשים)

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

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

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

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

Security (נקרא במקור Integrity) - עד כמה מוגבלת / מאובטחת צריכה להיות הגישה לנתונים / שירותים של המערכת.

Efficiency - עד כמה יעילה המערכת בניצול משאבי החומרה העומדים לרשותה, או בניצול שירותים אחרים (כגון SOA) - והחומרה העומדת לרשותם.

Portability - היכולת של המערכת לרוץ בסביבות ריצה שונות, קרי מערכות הפעלה, סביבות ענן, תצורות רשת וכו'.

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

Interoperability - היכולת להחליף נתונים בקלות עם מערכת אחרת. באופן אישי לא מצאתי מאפיין זה שימושי. Interoperability נראה לי יותר כמו פיצ'ר נקודתי מאשר יכולת רוחבית. אני משאיר אזכור לצורך שלמות הרשימה המקורית.

Maintainability - עלות תפעול (Administration / Operations) נמוכה של המערכת. מה שנקרא TCO (Total Cost of Ownership). מאפיין זה יכול להצביע על הוספת "פ'יצרים של ניהול המערכת". עוד נושא שנכנס לקטגוריה זו היא קלות ההתקנה של המערכת, לעתים מתייחסים אליה כמאפיין איכות עצמאי: Installability.
דוגמה: כלי monitoring שיסייעו לנטר בעיות במערכת. השקעה ב Upgrade קל וכו'.

Developability (נקרא במקור Flexibility) - היכולת לפתח את המערכת בקלות, לבצע בה שינויים או לתקן באגים. מה שנקרא TCD ((Total Cost of Development מאפיין איכות זה עוזר לאפיין את הדילמה שבין איכות שמוסיפה סיבוכיות למערכת (Portability או Efficiency, למשל) למול היכולת לפתח מהר וביתר קלות.

Extensibility - היכולת להרחיב ולהוסיף יכולות חדשות למערכת, בעזרת Plug-in, API וכו'. כמובן שיכולת ההרחבה היא ליכולות / אזורים ספציפיים במערכת.

Supportability - היכולת לתמוך במוצר בקלות, אם מדובר בגוף המייצר את התוכנה או גוף שלישי. כלי Monitoring, לוגים קריאים, יכולת לבצע Dumps של זיכרון או נתונים, דו"ח על תצורת המערכת וכו'.

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

Testability - היכולת לבצע בדיקות למערכת. באופן אישי, מאפיין זה נראה לי כמו אמצעי להשגת Reliability או Developablity - ולא מטרה בפני עצמה.

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

Availability - מאפיין זה תקף בעיקר לשרתים (או שירותים) והוא מורכב מזמינות (אחוז הזמן שהשרת / שירות זמין ללקוחותיו) או תדירות הכישלונות (מה שנקרא MTBF). שרת יכול להיות זמין 99% מהזמן אך לכשול לשנייה אחת - כל יום, מה שיגרום לתקלות כואבות. (MTBF (Mean Time Between Failures עוזר להשלים את התמונה שנתון הזמינות לבדו לא מספק היטב.

רשימת "מאפייני איכות" ממקורות שונים.  מקור: http://www.clarrus.com/documents/Software%20Quality%20Attributes.pdf

כמה הערות על הרשימה:
שימו לב שבהכללה גסה Reusability, Developability ו Testability הם איכויות פנימיות (משפיעות על הפיתוח) בעוד היתר הן איכויות חיצוניות (משפיעות על הלקוח).

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


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

מכיוון שכל מאפייני האיכות הם "דברים טובים" האתגר הוא להבחין מה יותר חשוב ממה.

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


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


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



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

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

במשך שנים, נושא חם בשוק ה IT היה בעיית ה Lock-In: בחרת ספק מסוים, לו יש API מסוימים. השתמשת בהם והיית מרוצה, אך ביום בו הספק מעלה מחירים / מחפף בשירות / קמים מתחרים עדיפים - "אין לכם שום דרך לבצע שינוי".
האמירה של "אין שום דרך" היא אמירה לא מדויקת - אך מכיוון שהסיפור (אלמנטים טרגיים של בגידה?) הוא סיפור מוצלח - הוא הושרש והשאיר חותמו על אנשים רבים.

אחד ה "Best Practices" שנבעו מכך הוא לכתוב קוד "בלתי תלוי בספק (vendor)" בכלל, ו"בלתי תלוי בספק בסיס-הנתונים" בפרט. עבדתם עם מערכת אורקל ומחר אתם רוצים לעבור ל MS-SQL? אין בעיה - מחליפים רק את ה "connection string" - והכל עובד.

ראיתי כמה מערכות שנעשה בהן שיקול שכזה[ב]. האנשים המעורבים הרגישו שהם עושים "הנדסת תוכנה טובה יותר" והחליטו "להקפיד ולכתוב קוד שלא תלוי בבסיס הנתונים". בפועל:
  • באף אחת מהמערכות הללו לא החליפו בסיס נתונים, עד היום (עד כמה שידוע לי).
  • הצוות הקפיד להשתמש ב ANSI SQL - וכך התעלם מרוב היכולות של בסיס הנתונים. אי-השימוש ביכולות הקשה בצורה משמעותית על הפיתוח ועל שיפורי ביצועים.
  • בכמה פעמים, המוצר נזנח / נכתב מחדש - אך בסיס הנתונים נותר. כלומר: בסיס הנתונים היה חלק יציב יותר מהקוד שהשתמש בו.
בפועל, ההחלטה המעשית הייתה לבחור במאפיין האיכות "no DB vendor lock-in", על פני "Developability" ועל פני "Scalability".
רק להבהיר: אני מדבר על מקרה בו אתם מוכרים Appliance או Hosting. כאשר הלקוח צריך לטפל בבסיס נתונים בעצמו, ברור למדי שלחברות רבות יש העדפה ברורה איזה בסיס נתונים הם רוצים להתקין: אולי יש להן DBA מוכשר שמכיר אותו, אולי הן כבר ביצעו השקעה מסוימת בטכנולוגיה (כלי ניהול, אבטחה וכו') ספציפית לספק בסיס-נתונים זה.
מתן האופציה להתקין כל DB, עבור לקוחות רבים - יכולה להחשב כאיכות של Maintainability - כי אז הם יוכלו להתקין את בסיס הנתונים שהם מעדיפים.

הבחירה של פלטפורמות ג'אווה וNET. לבצע הפשטה שכזו (בעזרת ODBC ו JDBC) באה לתמוך במי שרוצה להשיג Maintainability.
אם כל מה שאני שומר בבסיס הנתונים היא טבלה או 2 של נתונים פשוטים - אין לי רווח רב משימוש בבסיס נתונים ספציפי.


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


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


דרך מומלצת 
על מנת להשתמש במאפייני איכות בצורה יעילה כדאי לבחור כמה תסריטים עיקריים במוצר ולהדגיש אותם:
"בתחום ה X אנו מעדיפים d על c ומעדיפים b על a".

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

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


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

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

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

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


נ.ב. - חלק מהספרות הפורמלית בנושא מתאר את "מאפייני האיכות" קצת אחרת - אני התייחסתי אליהן בצורה שהייתה שימושית עבורי והוכיחה את עצמה. חפשו בגוגל "Quality Attributes" ותוכלו למצוא חומר רב.




---


[א] הגפרור שאנו מכירים.


[ב] אני מכחיש בתוקף!, אך בפועל ייתכן שפעם אני הוא זה שיזם את המהלך.


[ג] Effective, לא efficient.



5 תגובות:

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

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

    השבמחק
    תשובות
    1. ויטלי2/8/12 21:26

      היי ליאור,

      לא כל הכך הבנתי למה אתה מייחס קוד שהוא db-agnostic ל- Maintainability?
      אם כבר מדובר ב- Interoperability או Portability.

      בכל מקרה, במקרה כזה אני חושב שעולה הצורך להגדיר מאפיין איכות נוסף: Supportability-Matrix, שזה סוג של ערבוב בין Interoperability לבין Portabiliy: היכולת של מוצר לרוץ במערכות הפעלה שונות ולעבוד מול DB'ים שונים.

      אם מי מקוראי הבלוג תוהה מה יכולה להיות סיבה ממש טובה להיות db-agnostic, אז זו תמיכה של מוצר ב- DB'ים מרובים.
      למשל, המוצר שאני מפתח תומך לא רק ב- Windows/Linux אלא יכול לעבוד גם מול Oracle ו- Sql Sever (על גרסאותיהם!).

      כקוריוז, לא מזמן גיליתי שאנחנו לא יכולים להשתמש ב- Table partitioning כי ב- Oracle מדובר מ- enterprise feature ואיננו יכולים להניח שללקוחות שלנו יש אותו (ולא יכולים לחייבם).

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

      בקיצור, הייתי שם מעליו זרקור וצובע אותו בצהוב זוהר אם יכולתי :-)

      מחק
  2. היי ויטלי,

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

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


    לגבי Testability: אני מסכים שזה ערך חשוב מאוד בהנדסת תוכנה. כנ"ל גם Modularity ו High-Cohesion/Low-Coupling ועוד. מדוע על Testability להיות "מאפיין איכות" ולא על האחרים?


    אם הגדרה של Testability הייתה מסייעת לי לקדם (או לקבל הסכמה על) בדיקות-יחידה, או TDD - כמובן שהייתי מגדיר אותה כ"מאפיין איכות". הייתי מוכן להגדיר אותה כאחד מ"ארבעת המינים" אם זה היה עוזר ;-)
    האתגר, לפי דעתי, הוא לשכנע אנשים ש Testability חשוב ממשהו אחר "טוב". לעזור לאנשים לכתוב קוד Testable בפועל, במיוחד במערכות Legacy...
    אם אתה מוצא שזה עוזר לך - ספר לי. אשמח לשמוע.


    ליאור

    השבמחק
  3. אנונימי2/8/12 23:45

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

    השבמחק