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.



ארכיטקטורה: Quality Attributes (חלק א' - מבוא)

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

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

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

"באמת ארכיטקטורה זה כ"כ משעמם?" - היה קול אחד שניקר בראשי.
אולי אני לא מבין שומדבר ("you know nothing Jon Snow") - היה קול ספקני שני.

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

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

אחד הכלים הללו נקרא מאפייני איכות (Quality Attributes) - ועליו נדבר בפוסט זה.


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


מה מאפייני-איכות הם לא?

הנה screenshot ממצגת שראיתי, אשר ניסתה להסביר "מהם מאפייני איכות":


המטפורה הזו היא שטותית!

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

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


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

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

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

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

אנו רואים ש"חיי סוללה ארוכים", עבור מחשב נייד, זו איכות רוחבית של המוצר. "מאפיין איכות" (Quality Attribute), בשפה שלנו.

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


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

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

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


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

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

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

מצד שני יבואו המפתחים עם שאלות:
אתה רוצה להשקיע 5 ימי פיתוח בהגנה בפני Directory Traversal[ב]? זו כמובן שאלה לא הוגנת - שרוב אנשי המוצר פשוט לא מסוגלים לענות עליה.
"כמה יהיה 'ציון האבטחה' של המערכת שלנו עם ובלי Directory Traversal?" היא שאלת הנגד המעשית של איש המוצר - שהמפתחים מצידם לא יהיו מסוגלים לספק לה תשובה.


לבחירת מאפייני האיכות במוצר שלנו יש השפעה רבה על עלות פיתוח המוצר, אך חשוב מכך - על שביעות הרצון וההתאמה ללקוח.

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

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

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

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


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


בהצלחה!


----

[א] ישנם מספר גופים שמגדירים הגדרות לגבי ארכיטקטורה והנדסת תוכנה בכלל. SEI (Software Engineering Institute) היא דוגמה לגוף שכזה. לגופים אלו לרוב יש השפעה רבה על ארגוני-ענק ועל האקדמיה, אך נראה שהשפעתם על כלל התעשייה - מעטה.

[ב] סוג של פגיעות מערכת, בהיבט האבטחה.


2012-07-30

סדרה: מבוא מואץ ל JavaScript ו jQuery - עבור מפתחי C# / Java מנוסים


את דרכי המקצועית התחלתי ב #C, ולאחר מכן עברתי את רובה ב Java. 
כאשר נדרשתי להבין גם JavaScript ו jQuery מצאתי הרבה חומר טוב למתחילים, אך מעט חומר שהיה יעיל למפתח Java ותיק. כזה שכבר יודע לתכנת, יודע לולאות, מערכים או Exceptions - אבל לא מכיר ספציפית את JavaScript.

בסדרת פוסטים זו ריכזתי מבוא מואץ ל JavaScript ו jQuery שלא אמור לשעמם מפתחים מנוסים.




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





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






מחלקות ובנאים
בג'אווהסקריפט יש אובייקטים, אך אין מחלקות. חסרות לכם המחלקות (Classes)? אתם בחברה טובה. המשיכו וקראו...






jQuery - מי, מה, מו?






להבין את JavaScript's this. המילה השמורה this בג'אווהסקריפט נשמעת דבר פשוט, אך היא מבלבלת למדי - עבור מי שהגיע מעולם ה Java (או #C או ++C או Pascal או ...)








סקירה של יכולת מתקדמת של jQuery (מה שידוע כ Deferred Object), המסייעת לכתוב קוד אסינכרוני מסודר גם כאשר כמות הקוד היא גדולה.






בהצלחה!



2012-07-25

מפרשן מול מהדר - מה ההבדל?

למי שלא עשה קורס ב"קומפילציה" (ואולי גם למי שכן), עולה מדי פעם השאלה: "מה ההבדל בין מפרשן (interpreter) למהדר (compiler)?"
- שניהם הרי גורמים לקוד של תוכנה לרוץ על מכונה כלשהי.

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

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

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

מפרשן יכול לספק debugger בהשקעה אפסית כמעט - עוד יתרון. הקלות בכתיבת מפרשן יכולה להיות מתורגמת בקלות לכתיבת שפה cross-platform - יתרון נוסף.

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

לכתוב מפרשן, זה בסה"כ דיי פשוט. קוראים שורה מקובץ (להלן ה"קוד"), מפרסרים מה כתוב שם (הכי פשוט שהפקודה היא המילה הראשונה) ואז מבצעים בשפה שלכם (#C למשל) את מה שרציתם לבצע. הדברים נהיים קצת יותר מורכבים כאשר יש משתנים, פונקציות, Scope ויותר. על המשמעות של הכנסת מצביעים אני לא יודע לספר.

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

אולי כדאי שבעצם נשאל את עצמנו מה היתרון בכתיבת מהדר? מדוע להשקיע מאמץ רב בתוכנה שתתרגם שפה לפלטפורמה יחידה, ושמציבה אתגר משמעותי בכתיבת debugger?

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


נוסטלגיה. כנראה שרוב קורסי ה"קומפילציה" בארץ נעשו על בסיס ספר זה מ 1986. מקור: amazon.com


המצב בפועל
בואו נבחן כמה שפות מוכרות: האם הן שפות-מהדר או שפות-מפרשן?

שפת אסמבלי
בואו נתחיל מאסמבלי: טעות נפוצה היא לקרוא לשפת אסמבלי (assembly) בשם "אסמבלר". אסמבלר הוא השם של המהדר שלה. האם האסמבלר "מתרגם תוכנה שנכתבה בשפה 'קריאה לאדם', כיחידה שלמה, לקוד בשפת מכונה (אפסים ואחדים) שמבוצע ישירות על המעבד"? כן. 
שפת אסמבלי היא בעצם ייצוג טקסטואלי, בעזרת מילים "בשפת אדם" כגון JMP ו MOV, לפקודות מכונה. האסמבלר פשוט עושה מין "Search and Replace" של "JMP" ל 00010010101101, למשל.

יש לי הסתייגות קלה מהגדרת שפת אסמבלי כ"קריאה לאדם". אני חושב שכדאי מאוד לעשות את ההבחנה בין "Human Readable" לבין "Human Parsable". ברוב הפעמים שמדברים על Human Readable (לדוגמה קובץ XML) רוצים לומר שזה טקסט שאדם יכול "לפענח", לאו דווקא "לקרוא".


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




שפת JavaScript
ג'אווהסקריפט הייתה במשך שנים דוגמה קלסית לשפת מפרשן. הסיבה העיקרית הייתה כנראה הרצון להריץ קוד שלה על סביבות שונות: כתוב את הקוד פעם אחת והוא ירוץ על ספארי (מק), FF (לינוקס) או IE (חלונות). אם הקוד קומפל לשפת מכונה אחת - הוא לא יתאים למכונה אחרת ולכן האפשרות היחידה היא לשלוח את קוד המקור למחשב עליו רץ הדפדפן - ושם לפרשן אותו.
בשנים האחרונות, הפכו נפוצים מהדרי JIT [ב] לשפת ג'אווהסקריפט. דוגמה בולטת היא מהדר ה JIT של V8 - מנוע  הגא'ווהסקריפט של גוגל. התוצאה: קוד המקור נשלח לדפדפן לפני ההרצה, אך הדפדפן מחליט להדר אותו ואז להריץ אותו בשפת מכונה - כך שבפועל כיום, JavaScript רצה מהודרת. הנה דוגמה ליתרון שבהידור. דמיינו את הקוד הנפוץ הבא:

var a.b.c.d.e.f.g.h.x = 100;
var a.b.c.d.e.f.g.h.y = 200;

כאשר a.b.c.d.e.f.g.h הם שמות namespaces או אובייקטים בג'אווהסקריפט. כאשר יש מפרשן, עליו לקחת את אובייקט a ואז לחפש בו property בשם b, ואז על b לחפש property בשם c וחוזר חלילה. ללא שיפורי ביצועים מיוחדים יכול להיות שמדובר בעשרות פעולות בזיכרון.
מהדר לעומת זאת קורא את 2 השורות ומבין שיש פה אופציה לייעל את הקוד. הוא יכול להפוך את הקוד ל:

var _p = a.b.c.d.e.f.g.h;
var p.x = 100;
var p.y = 200;

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






שפת Java
Java היא שפת מהדר - נכון?
כן. בג'אווה יש מהדר שהופך קוד ג'אווה לקוד bytecode, אבל קוד ה bytecode עובר פרשון (מכיוון שהוא אמור להיות cross-platform). כבר מזמן יש JIT Compilers ל bytecode, כך שבפועל ג'אווה עוברת הידור ראשון בסביבת הפיתוח והידור שני על פלטפורמת ההרצה - מה שמתגלה כנוסחה יעילה למדי!
גם כאשר מהדרים קוד ++C למעבד מסויים (למשל מעבדי אינטל 64-ביט) יש לדגמים שונים יכולות מעט שונות - יכולות שלא ניתן לנצל בקוד המהודר מכיוון שעל המהדר לפנות למכנה המשותף הנמוך. הידור דו-שלבי כגון זה של ג'אווה מסוגל לבצע אופטימיזציות ייעודיות לחומרה הקיימת - ולנצל את כל היכולות / התכונות של החומרה.

שפת CoffeeScript
לקופיסקריפט יש מהדר, אך הוא עושה דבר מוזר: הוא מתרגם קופיסקריפט לג'אווהסקריפט. בשל הבא קוד הג'אווהסקריפט  (המהודר) נשלח למכונת משתמש-הקצה ועובר הידור ב JIT Compiler - כך שיש לו הידור כפול, אך קצת שונה משל ג'אווה מכיוון ששפת הביניים (intermediate language) היא ג'אווהסקריפט - שפה גבוהה בהרבה מ bytecode והיכולת לבצע אופטימיזציה בקוד - פחותה.
בפועל, אתם מבינים, יכולה להיות שרשרת דיי מורכבת של מהדרים ומפרשנים בדרכו של קוד תוכנה להיות מורץ. הדרך לתאר את כל האפשרויות הקיימות היא מורכבת, ויתרה מכך - כנראה לא מעניינת.


(DSL (Domain Specific Languages
סוג חדש של שפות שהופיע לאחרונה[ג] הן שפות מבוססות דומיין, כלומר שפות מתאימות לפתור בעיות מסוג מאוד מסוים: ויזואליזציה של נתונים בתחום מסוים, ביצוע שאילתות על נתונים, קביעת תצורה של Firewall וכו'.
לרוב לא מדובר בשפה חדשה לגמרי, אלא שפה ש"מורכבת" על שפה קיימת. אלו יכולים להיות פונקציות או אובייקטים שמתארים עולם מונחים שמקל על פתרון הבעיה ובעצם מהווה "שפה חדשה".

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

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


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

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


עדכון: הנה נתקלתי בבסיס נתונים שמהדר SQL ל ++C ואז לשפת מכונה.

----

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

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

[ג] בעצם הוא קיים המון זמן, אבל המודעות לקיים - היא זו שהתפתחה לאחרונה + קיבלה fancy name.

2012-07-20

מקביליות עם jQuery (ובכלל)

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

ה"מקושרים" שבכם, אלו שקוראים הרבה חדשות טכנולוגיות, בוודאי שמעו כבר על כמה שינויים שהוכרזו ע"י jQuery לאחרונה:
  • היכולת לארוז רק חלקים מהספרייה (אולי בגלל התחרות מ Zepto.js).
  • הפסקת התמיכה בגרסאות לא-חדשות של Internet Explorer.
  • איחוד מנגנוני הרישום לאירועים: bind, live ו delegate למנגנון ה on (חדשות ישנות יותר).

האמת שמדובר בשינוי שהוצג ב jQuery גרסה 1.5 (עם כמה תוספות ב 1.6 ו 1.7) - ואישית, אני לא זוכר שהוא עשה חצי מהמהומה של השינויים הנ"ל. בכל זאת זהו שינוי משמעותי וחשוב.

השינוי נוגע באזור ה Ajax ומאפשר גמישות שלא הייתה קיימת קודם לכן.

בואו נדבר עליו.


שייך לסדרה מבוא מואץ ל JavaScript ו jQuery




שינוי בפקודת ה Ajax
למי שלא מכיר, jQuery עוטף את ה XMLHttpRequest (או בקיצור XHR) של הדפדפן בצורה נוחה ומאפשר לקרוא בפשטות ajax.$ על מנת לבצע קריאת ajax. יש גם גרסאות מקוצרות בשם get.$ ו post.$.

עד גרסה 1.4 הדרך לבצע קריאת ajax הייתה כזו:
$.get('http://server.com/myurl', {
  success: onSuccess, // a callback function to be triggered on success
  failure: onFailure, // a callback function to be triggered on failure
  always: onAlways // a callback function that is triggered on either failure of success. Like "finally".
});

success, failure ו always הם callbacks שנקראים כאשר הקריאה מסתיימת, הצלחה או כישלון.

מגרסה 1.5 אפשר לכתוב את הקוד בדרך הבאה:
var request = $.get('http://server.com/myurl');
...
request.done(onSuccess);
request.fail(onFailure);
request.always(onAlways);

כלומר, ניתן לבחור אלו פונקציות (callback) יקראו בעקבות התשובה לאחר שהקריאה התבצעה. אם התשובה כבר חזרה, הקריאה (done, למשל) תפעיל את פונקציית ה callback מיידית.

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

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


Making Promises
אפתח בכמה מילים גדולות: מה ש jQuery עשו, הוא לממש Design Pattern (יו... וואהו!) שידוע בשמות הבאים: Deferred Object או Promise או Future. יש אפילו הגדרה פורמלית בשם Promises/A שמגדירה כיצד תבנית זו אמורה להתנהג בג'אווהסקריפט.
לאכזבתם של לא-מעטים, jQuery לא נצמדה ל"הגדרה הפורמלית" ומימשה וריאציה קצת שונה של תבנית העיצוב, מימוש שהושפע כנראה מספריית Dojo שסיפקה יכולת דומה. אם אתם אורתודוקסים ל Promises/A, תוכלו למצוא מימושים "תקניים" בספריות כגון Q.js או Async.js שניתן להשתמש שהם. לרובנו, כל מה ש jQuery יעשו - מהווה את התקן בפועל.

על מנת להבין את המשמעות של הפעולה של ה Promise, נפרק אותה (Deconstruct) למרכיבים יותר בסיסים ונבחן אותם. הביטו על קוד ה JavaScript/jQuery הבא:
var deferred = new $.Deferred();
deferred.done(function(){ console.log('done'); }); 
deferred.fail(function(){ console.log('fail'); }); 
...
deferred.done(function(){ console.log('donedone'); }); 

האובייקט Deferred הוא לב העניין, אם כי אינו קשור ל ajax במאומה. הוא מעין handle-עתידי.
בעת קריאה ל ()deferred.resolve - יופעלו הפונקציות (ניתן לרשום מספר לא מוגבל של פונקציות, לכל אחד מהאירועים) שנרשמו ל done. במקרה זה - כתיבה של done ו donedone ללוג.
בעת קריאה ל ()deferred.reject - יופעלו הפונקציות שנרשמו ל fail. במקרה זה כתיבת fail ללוג.

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

ה Promise הוא אובייקט (יחידון = singleton) שחוזר מקריאה ל ()deferred.promise וכל מטרתו היא לאפשר גישה מוגבלת: לאפשר לרשום פונקציות ל done, fail ו always - אבל לא לבצע triggering ל reject או resolve.

Read/Write Pattern - שליטה ב"הרשאות" ע"י הפרדת הפעולות ל interfaces שונים. אפשר להחליף את user ב promise ואת userMaint ב Deferred על מנת לראות את תבנית העיצוב בהקשר לדיון שלנו.

הערה: ל reject או resolve ניתן לקרוא פעם אחת בלבד בחיי אובייקט ה Deferred. מאותו הרגע, כל פונקציית callback שתנסה להירשם - תופעל במקום.

כעת, לאחר שהבנו את ההתנהגות של Promise, בואו נראה אלו בעיות מבנה זה יכול לפתור לנו.


Concurrent Pattern: Monitor
השימוש ב Deferred יכול לסייע לנו לבנות מבנה של concurrent programming בשם בקר (monitor). בקר הוא כלי לטיפול באסינכרוניות, הגבוה ברמת ההפשטה שלו מ mutex או semaphore, אך נמוך מ "synchronized" של ג'אווה / #C. אנו עשויים למצוא אותו דיי שימושי בשפת ג'אווהסקריפט / שימושי ב ajax בהם אסינכרוניות היא נפוצה [ב].

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

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

הרבה יותר אלנגנטי, יעיל ונוח יהיה פשוט מאוד לכתוב:

var promiseA = $.get(...);
var deferredAnimation = $.Deferred(); // call  deferredAnimation.resolve() when it is done
var promiseB = deferredAnimation.promise();


$.when(promiseA, promiseB).
done(function(promiseAargs, promiseBargs) {
   ... // what happens when both are done 
});

תענוג!


מודולריות
השימוש העיקרי, והנפוץ יותר ל Promises הוא עבור callbacks פשוטים.
כפי שציינו קודם לכן, הקוד

$.get('http://server.com/myurl', {
  success: onSuccess, // a callback function to be triggered on success
  failure: onFailure, // a callback function to be triggered on failure
  always: onAlways // a callback function that is triggered on either failure of success. Like "finally".
});


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

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

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


סיכום 
Promise הוא לא Silver Bullet, אבל במקרים רבים הוא יכול להיות כלי רב-עצמה שיתיר סיבוכיות רבה מהמערכת. היכולת לנתק את השליטה (קריאות resolve ו reject של Deferred) מצד אחד ואת התגובה לסיום הפעולה (done, fail ו always של ה promise) מצד שני מאפשרות לשמור על מודולריות גבוהה של המערכת במחיר נמוך.

אם אתם מוצאים את תבנית העיצוב של Deferred ו Promise שימושית, יש עוד פונקציות שניתן לחקור:
Deferred ו Promise יכולים לתקשר בניהם גם אודות progress (שלא כיסיתי בפוסט). לפעולת when יש פעולה "אחות" בשם then. חשובה אולי מכולן היא פעולת ה pipe שמתירה לשרשר הצלחות / כישלונות של promise וכך לחסוך קוד.


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


---

[א] בגרסה 1.6 שונו שמות הפונקציות - אני משתמש בשמות החדשים. בגרסה 1.8 השמות הישנים (complete, success ו error) יוכרזו כמיושנים (deprecated) ולכן אני נמנע משימוש בהם.

[ב] בג'אווהקריפט בדפדפן יש כמובן thread יחיד ואין מקביליות חישוב. מצד שני יש הרבה פעולות IO אסינכרוניות שקוראות במקביל ויש אתגר תכנותי לשלוט בהן.


2012-07-14

מבוא מואץ לjQuery עבור מפתחי #C ו Java מנוסים

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

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

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


שייך לסדרה מבוא מואץ ל JavaScript ו jQuery


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

  • להגיע לקהל יעד רחב
  • לכסות נישות שלא מכוסות היטב - כלומר Value Proposition ייחודי.

הקדמה
על jQuery יש טונות של חומרים. רוצים לדעת מה ההבדל בין live ל bind? עשרות מקורות טובים ישמחו להסביר. עם מעט חיפוש, גוגל יפנה אתכם לתשובה בודדת ב StackOverflow שעונה בדיוק, אבל בדיוק, על המקרה שאתם מתמודדים איתו. אבל יש משהו שנראה לי ייחודי ושקשה למצוא - מבט גבוה קצת מהפרטים, מפוכח ובעברית - על מה שקורה שם.
לפני כתיבת פוסט זה חיפשתי בגוגל "jQuery Crash Course" או "jQuery introduction". יש הרבה - אבל הם מספקים hands-on בכדי להתחיל להשתמש ב jQuery. הם לא מספקים הקדמה נאותה שתכין אתכם ללמידת jQuery או בכלל תעזור לכם להבין אם זה מה שאתם מחפשים. כשאני התחלתי ללמוד jQuery (לא כ"כ מזמן) - רציתי למצוא מישהו שיספר לי "מה העוקץ ב jQuery" - אך לא מצאתי. הנה זה לפניכם.
עלייתה של jQuery
תחילתה של jQuery היא בימי הביניים (של הדפדפנים - כמובן), ימים אפלים שהאנושות מנסה לשכוח.
בעוד JavaScript הייתה סטנדרטית (נניח...), ה APIs של הדפדפן לייצוג דף הHTML, מה שנקרא (Document Object Model (DOM, היה שונה למדי בין דפדפן לדפדפן. אמנם היו פונקציות עם שמות זהים (כמו getElementsByTagName) - אבל ההתנהגויות היו שונות. לעתים הן החזירו מבנים שונים, לפעמים הם קראו לאירועים (events) בסדר שונה. ובד"כ הן עשו את זה לאט ובצורה לא יעילה, תחת ההנחה ששינויים דינמיים ב DOM הם מעטים למדי. בקיצור: כל מה שלא הייתם רוצים מ API.
הכתיבה של קוד ווב Cross-Browser הייתה סיוט, ואכן רק אנשים מעטים הסכימו לעסוק במלאכה הבזויה[א]. ספריה שתספק API אחיד, אמין ומהיר עתידה להפוך לדבר שהמפתחים יהיו תלויים בו ולא יוכלו עוד בלעדיו.
כעשור מאוחר יותר, הדפדפנים מהירים יותר ואחידים יותר במבנה ה DOM APIs שלהם.
"מדוע מפתחים עדיין 'תלויים' ב jQuery?" - אפשר לשאול. ובכן, לשימוש ב jQuery יש הרבה תיעוד ודוגמאות - הרבה יותר מאשר שימוש ישיר ב DOM. בנוסף, בעוד ה API של ה DOM התפתח בקצב איטי ונשאר דומה למדי לתכנון בן 13+ שנים, jQuery יכלה להרשות לעצמה שינויים יותר דרמטיים שמשקפים יותר טוב את צורכי התקופה.

אז מה jQuery מספקת?
אמירה מקובלת היא ש "jQuery היא רק ספריה ל Selection" - אבל זה לא מדויק. jQuery מכסה מספר נושאים:

  • ביצוע שינויים ב DOM - קריאה וכתיבה.
  • מודל פשוט ואחיד יותר של אירועים (DOM events).
  • שיפורי ביצועים עבור טיפול בהרבה אירועים.
  • אנימציות - שיכולות להיות מופעלות על כל אלמנט ב DOM כמו Image, או Div שמאגד אלמנטים רבים.
  • הפשטה של XMLHttpRequest - מה שקרוי Ajax.
  • Utilities שונים לשימוש בג'אווהסקריפט, כגון each.$ או proxy.$
כפי שניתן לראות jQuery הוא דיי רוחבית. חוץ מהאנימציות שהן קצת "אקסטרה" - ספריה זו מספקת עטיפה ל DOM שמאפשרת לנו לעבוד איתו ברמת הפשטה קצת יותר גבוהה.

אלטרנטיבות
Prototype ו MooTools הן ספריות בעלות יכולות מקבילות, פחות או יותר. jQuery נצחה אותן בזכות קהילה, תיעוד טוב יותר או אולי אמינות גבוהה יותר.
Dojo, YUI או ExtJS/Sencha הן ספריות שמספקות רמת הפשטה גבוהה בהרבה ובעצם מנתקות אתכם מה DOM. הן נותנות למפתח לעבוד ברמה קרובה הרבה יותר ל Windows Forms או AWT ובעצם מייצרות מודל חדש אלטרנטיבי ל DOM שהמפתח עובד מולו.

יש המון כוח ויופי בכך ש jQuery לא מתארת מודל חדש, אלא רק מודל משופר של ה DOM. המפתח נותר עם קשר והבנה טובה בהרבה למה שקורה בפועל בתוך הדפדפן, ו jQuery יכולה להתחבר בקלות להמון ספריות שנכתבו בחשיבה על ה DOM. מי שרוצה ליצור ספרייה מעל YUI צריך לעבוד ע"פ המודל של YUI שעשוי בהחלט לא להתאים ל Dojo או ל ExtJS.



טעימה מיכולותיה של jQuery
לא אנסה להרשים אתכם בתצוגות-תכלית מגניבות. ה Adoption של jQuery הוא כבר מעבר לזה. אנסה לתת, בקצרה, טעימה מהיכולות העיקריות והסגנון של jQuery.

DOM Manipulation
בדומה לSQL בה יש משפטי SELECT...FROM...WHERE עם פורמט ידוע, גם ב jQuery יש דרך פעולה שחוזרת על עצמה. משפטי jQuery הם בעלי המבנה הבא:

$('selection').<execute>();


בחר שורה של אלמנטים - ובצע עליהם משהו: שינוי של HTML, CSS, רישום לאירועים ועוד.
חלק גדול מהיופי של jQuery היא הדרך בה היא משתלבת בטבעיות בנוף של HTML, JavaScript ו CSS. שפת CSS עושה פעולה דומה: בוחרת אלמנטים ב DOM (כלומר ב HTML) ומחילה (כלומר apply) עליהם עיצוב.
jQuery משתמשת בתחביר של javaScript לתאר את אותה התבנית. הנה דוגמה:

$('.banner').css('background-color', 'red');

שהיא המקבילה לכתיבת ה CSS הבא:

.banner {
  background-color : red;
}

מפתח שחדש ל jQuery אך בקיא ב CSS יוכל ללא קושי להגדיר שאילתות דיי מורכבות.
jQuery לא אמורה להיות תחליף ל CSS - לצורך זה היא תהיה משמעותית פחות יעילה, אבל היא מאפשרת באותה דרך חשיבה לבצע שינויים מרחיקי לכת בעזרת שורות בודדות של קוד.
התחביר של jQuery, בדומה ל javaScript, תומך בשרשור (chaining). פעולת ה Select מחזירה רשימה (באורך 0, 1 או יותר) של אלמנטים ב DOM. כל אחת מפעולות ה execute מחזירה את אותה הרשימה של אובייקטים עליה נקראה, כך שיהיה ניתן לשרשר עליה עוד ועוד פעולות:

$('div > p').show().css('color', 'blue').removeClass('selection');


קריאה זו תבחר את אלמנטי ה p (פסקה ב HTML) שנמצאים ישירות בתוך div, תציג אותם, תחיל על הטקסט צבע כחול ותסיר class בשם selection - אם קיים.
אם ננסה לתאר בצורה יותר כללית את תבנית כתיבת הביטויים ב jQuery - אפשר לתאר אותם כך:

$('selection').<execute>().<execute>().<filter>().execute();


פעולת הפילטר היא פעולה שמצמצמת את רשימת האובייקטים. "צמצום" יכול להיות גם פעולת בחירה במקרה זה, כאשר find בוחרת את אלמנטי ה strong הבנים לאלמנטי ה div שבחרנו:

$('div').css('border', '1px solid blue').fadeTo('slow', 0.5).find('strong').css('color', 'red');
הנה דוגמת ההרצה של קוד זה. אין מניעה שיהיו יותר אלמנטים של strong מאלמנטים div-אבות כמובן, כך שהשם "צמצום" (filter) הוא שם בהחלט לא מדויק. וריאציה אחרת של צמצום נקראת "טיול" או traversal. בעזרת פקודות כגון ()parent או ()siblings אפשר "לטייל" על ה DOM מהנקודה בה אתם נמצאים.
יש מספר רב של פעולות execute, traversal ו filter אפשריות - אני בטוח שגוגל יוכל לעזור לכם למצוא מידע רב על כולן.

טיפול באירועים (events)
jQuery מספקת רמת הפשטה נוחה יותר לאירועים ב DOM. לדוגמה, עבור hover סביר שמפתח יבחר להירשם לאירועים של ה DOM בשם mouseOver ו mouseOut, אבל היכרות אינטימית תלמד שברוב הדפדפנים שימוש ב mouseEnter ו mouseLeave הוא עדיף. jQuery חוסכת לכם ללמוד פרטים כאלו ומספקת אירוע hover (שדורש 2 פונקציות: כניסה ויציאה) שידע לעשות את הדבר הנכון עבור כל דפדפן.
עוד צרה קשה היא רישום מופעים רבים של אירוע.
נאמר שיש לכם גלריה עם 100 תמונות על המסך, שבפעולת Hover אתם רוצים להדגיש את התמונה (אחת מ 100) שכרגע העכבר מצביע עליה. הדרך הנאיבית היא לרשום את אירוע ה hover והטיפול בו 100 פעם, פעם עבור כל תמונה בגלריה. מחיר הביצועים עלול להיות הרסני.
עדיף בהרבה לרשום את אירוע ה hover פעם אחת על כל הגלריה, לאתר את התמונה הרלוונטית לאירוע ואז להפעיל את קוד הטיפול באירוע בעזרת ההקשר הנכון.
שיפור הביצועים הוא משמעותי מאוד, אבל לדפדפנים שונים יש חוקים שונים כיצד לעשות זאת. jQuery מספקת הפשטה טובה לסיבוכיות זו ונותנת לכם לרשום אירועים על "קבוצה של אלמנטים" בקלות רבה.



כיצד jQuery עובדת? (בקצרה)
jQuery היא ספריית JavaScript לכל דבר. מוסיפים אותה ל HTML Header ואז ניתן להשתמש בה.
jQuery רושמת אובייקט גלובלי בשם $ (שם חוקי ב javaScript) שהוא משמש כמפתח לפעולות שונות של הספריה.
כאשר מבצעים Selection (כלומר "בחירה") - לא מקבלים רשימה של האובייקטים האמיתיים ב DOM, כי אם wrappers של jQuery שמספקים API בטוח, cross-browser, ופשוט יותר.
ל jQuery יש אלגוריתם יעיל לביצוע selection ב DOM. הוא נקרא Sizzle וניתן למצוא אותו כספריית javaScript עצמאית. ספרייה זו באמת "רק עושה selection". הנה כמה כללים איך להשתמש ב jQuery בצורה יעילה.
יש שמועות על כך ש jQuery מבצעת caching לאלמנטים ב DOM. שמעתי אותן לא פעם. לא נתקלתי מעולם בזכר להתנהגות שנראתה כמו caching עבור פעולות DOM. בעיקרון, גישה ישירה ל DOM אמורה להיות תמיד מהירה יותר משימוש ב jQuery.

Plug-ins
ניתן לכתוב plugins ל jQuery. בפועל plugin הוא פונקציה שנרשמת על ה namespace של jQuery (כלומר, סימן ה $) ויכולה להשתלב בתבנית ה Select-execute.
לדוגמה, אני יכול לכתוב פונקציה שהופכת אלמנטים להציג מימין לשמאל, ע"י שינוי כל פרטמר אפשרי לתמוך בהתנהגות זו. במקום לקבל רשימה של wrappers ולעבור עליהם בלולאה, יהיה הרבה יותר אלגנטי להשתמש בפונקציה שלי בצורה הבאה:
$('.text .localizable').toRTL();

יש כמה כללים (המנעות מהתנגשויות על הסימן $, אתחול, ...) שכדאי להקפיד עליהם בעת כתיבת jQuery Plugin - יש מדריכים רבים באינטרנט שישמחו לספר ולהדגים זאת.
סה"כ ראיתי כמה jQuery Plugins שלא הייתה להם הצדקה אמיתית להיכתב כ Plugin. אני מנחש שאם jQuery הייתה קוראת ל Plugins בשם פחות מרשים (כמו jQuery Chained Function) - היו נכתבים הרבה פחות Plugins של jQuery.

---
[א] הפוסט מופנה למפתחי Server בשפות מודרניות, שם ה APIs המקובלים טובים בהרבה.

2012-07-09

שיקולים בעיצוב אפליקציות מובייל

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

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

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

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

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

The Hotzone - האזור בו אצבע המשתמש חופשיה ועלולה להקיש (tap) בטעות. כדאי להרחיק את האזורים הלחיצים ממנה. מקור: http://answers.oreilly.com/topic/1802-designing-iphone-apps-the-rule-of-thumb/


חשבו היכן ניתן לצמצם, לא היכן ניתן לעשות יותר
נקודת פתיחה לא טובה לאפליקציית מובייל, כך נראה, היא מצב בו כבר קיים כבר מוצר Desktop.
"פרויקט התאמה" קוראים לזה, Mobile Adaptation או Mobile Enablement ומנסים, בעזרת צוות של כמה מפתחים ואיש UI חסר מזל, "לדחוס" את האלמנטים הגרפיים ממסך של "22 למסך של "4.
בעוד ב Desktop יש עכבר שהוא כלי הצבעה דיי מדויק, במובייל אזורים לחיצים צריכים להיות גדולים בהרבה - מה שמותיר מקום מועט אפילו יותר לתוכן שעל המסך.

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

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

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


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

חשבו לדוגמה על ההבדל בין אאוטלוק ל Mail ב iPhone: כמה עשרות, אולי מאות, פונקציות של אאוטלוק לא מצאו מקבילה בגרסת המובייל? בכל זאת, השימוש באפליקציה הוא נוח למדי ומתאים למרחב רחב מאוד של משתמשים. 
דוגמה נוספת: חשבו על המקלדת של המובייל מול מקלדת של Desktop, איפה כל כפתורי ה F-masheu? כיצד ביטלו את כפתור ה del (מחיקה ימנה) וניתן להסתדר רק עם מחיקה שמאלה[ב]?

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


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

הקלדה היא מאמץ מוגבר - שמור עליה

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

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

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

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

ססמאות בנייטיב אפ - במערכות ווב שדורשות הקלדת משתמש / סיסמה, דבר מקובל הוא לייצר מעטפת (למשל PhoneGap) שתשמור את הסיסמה ב Secured Storage של המכשיר. יכולת זו בלבד מצדיקה שימוש ב PhoneGap ופיתוח Hybrid App.


אל תצפה ממשתמש לנווט במסך של 4 אינץ'

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


שמור קצת מידע בצד ליום סגריר (connectivity issues)

אלו אלמנטים שקצת יותר קשורים למימוש הטכני מאשר להגדרת השימושיות per se.

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

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


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


בהצלחה!


----

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


[ב] בעברית, כמובן, הכיוונים הפוכים.

2012-07-06

פוסט היובל (50)

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

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

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

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

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

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


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





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






פוסט: מה הביג-דיל ב BigData (או NoSql). רלוונטי מתמיד. זכה ל 600+ קריאות.






פוסט: הקרב בתעשיית התוכנה: Development vs. Marketing - שזכה ללא מעט תגובות (הנה ב Newgeek).






הפוסט: חומרה: מבט מפוכח על מהפכת ה SSD - שזכה ל 400+ קריאות, בתקופה בה קהל הקוראים היה קטו יותר






הפוסט: האם ג'אווה גוססת? - שזכה ל 400+ קריאות, למרות שפורסם בחודש הראשון (אוקטובר 2011). עדיין רלוונטי, רק שהייתי מוסיף את JavaScript בראש הרשימה.







מה הייתי רוצה הלאה?

להמשיך, לגוון ולייצר שיח עשיר יותר בתגובות לבלוג (שכרגע אין לי מושג כיצד להשיג זאת).


שלכם,
ליאור


---

[א] למרות הבדיקות - היו לי כמה טעויות שנתפסו, וכנראה עוד כמה שלא.

[ב] כתבתי 13 פוסטים בחודש הראשון, דבר שנראה לי כרגע - כמעט בלתי נתפס.