47 ספריות ג’אווהסקריפט שכל מפתח *חייב* להכיר (חלק ב’)

בפוסט הקודם סקרנו כ 21 מתוך 47 ספריות שכל מפתח ווב “חייב” להכיר (כלומר: לדעת על קיומן), בפוסט זה נמשיך את הרשימה.

בדיקות-יחידה ואוטומציה

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

Jasmine כוללת תחביר אלגנטי שמושפע מ RSpec (כלומר BDD), כך הקוד שדומה יותר לטקסט בשפה האנגלית, נוסח:

expect(items.length).toBeGreaterThan(6);

Jasmine היא דיי מקיפה וכוללת יכולות לבדיקת קוד אסינכרוני (פקודות waitFor ו runs) ו Mock Objects (ליתר דיוק: Spies או fakes).

QUnitהיא ספריית הבית של jQuery. היא פשוטה יותר ומבוססת על תחביר פחות אלגנטי של xUnit נוסח:

ok(items.length > 6); // ok = "assertTrue"
או
strictEqual(0, items.length); // strict to reflect ===

הייחוד של QUnit הוא ביכולת שנקראת Fixtures – היכולת “לשתול” ב DOM קטע של HTML עליו יתבצע הבדיקה – ולהעיף אותו מיד אחריה. ניתן לעשות זאת גם ב Jasmine – במחיר של מספר שורות קוד.
שינויי DOM בעת הבדיקה לא הטכניקה המומלצת לבדיקות-יחידה – אבל לעתים היא נדרשת. במיוחד אם אתם ספרייה שבעיקר עובדת על גבי ה DOM – כמו jQuery.

מכיוון שאין ל QUnit יכולות של Mock Objects, מצמדים אותה לרוב עם ספרייה בשם Sinon– ספרייה עשירה, אלגנטית וטובה ליצירת Mock Objects בג’אווהסקריפט מכל הסוגים (Spy, stub, mock או fake).

בגלל האופי הדינמי של שפת ג’אווהסריפט – קל מאוד לייצר בה Mock Objects. מספר פעמים יצא לי לצרף את Sinon ל Jasmine – בכדי “לכתוב קוד אלגנטי יותר”, אך בכל הפעמים גיליתי ש sinon לא מצדיקה את עצמה כש Jasmine בסביבה: Jasmine עם קצת אלתור מספקת יכולת מקבילה ל Sinon – כך שלא הייתה הצדקה להשתמש בספרייה נוספת. הסבר: אני מקפיד להיפטר מספריות שאני משתמש בפונקציה אחת או שתיים שלהן – שאני יכול לכתוב בעצמי ב 5 דקות. (ע”פ עקרון ה segregation of interfaces + כדי לא ליצור דילמה חוזרת באיזה כלי להשתמש לכל בדיקה).

Mocha(מוקה) היא ספרייה שמשתמשים בה יותר ב Node.js, אבל היא מתאימה גם לדפדפן. אפשר לבחור להשתמש בה בתחביר BDD (כמעט כמו התחביר של Jasmine, אך טיפה פחות אלגנטי) או xUnit (נקרא משום מה “TDD”) – שניהם נתמכים. למוקה מצד שני, יש תחביר יפה לבדיקות אסינכרוניות (ולכן כנראה אוהבים אותה ב Node). עבור Mock objects מצמדים לה את sinon.

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

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

ספריות חדשות בברנג’ה הן Karma, Intern ו Casper.

Internמנסה לספק פתרון בדיקות-יחידה מקיף, מקצה-לקצה, שאין כדוגמתו עד היום (כלומר: יש להרכיב כיום מספר ספריות שונות על מנת לקבל אותו). דברים כגון: הקמה, כתיבת בדיקות, הרצת בדיקות, CI, Coverage וכו’.
עצתי אליה: שתשקיע באינטגרציה ל IDEs – כרגע זה לא נראה על המפה שלה. היא נשמעת מבטיחה מאוד – אבל היא עדיין הספרייה עם הכי פחות משתמשים (בינתיים).

Karma(לשעבר Testacular (נשמע כמו “אשכים”?), מבית Angular.js מבית גוגל) היא פורט של jsTestDriver (הכתוב ב java) ל Node.js (כלומר היא כתובה בג’אווהסקריפט ומריצה ג’אווהסקריפט).

עבדתי עם Karma מעט ומאוד אהבתי. היא כוללת את כל היכולות של jsTestDriver וקצת יותר, היא נראית יציבה יותר מ jsTestDriver (שהשרת שלה לא חי זמן רב ללא restart), היא עובדת טוב יותר עם AMD/require.js, ונראה שחלק גדול מהקהילה של jsTestDriver עובר אליה. היא יודעת להאזין למערכת הקבצים לשינויים ולהריץ את הבדיקות לבד ברקע – מוד עבודה נהדר ל TDD! יש לה את כל הנתונים להצליח בגדול.

היתרונות של jsTestDriver כרגע: אינטגרציה ל WebStorm ו Eclipse וקהילת משתמשים קיימת.

Casperהוא עוד כוכב עולה: הוא מיועד לכתיבת בדיקות אינטגרציה שהן יותר מבדיקות-יחידה אבל עדיין לא בדיקות UI (כלומר Selenium).
Casper מבוסס על Phantom.js (כלומר headless webkit – דפדפן ללא Shell) ויכול לבדוק את קוד הג’אווהסקריפט עם DOM ו CSS. היתרון על Selenium: הוא מהיר הרבה יותר. החיסרון: זה לא דפדפן אמיתי. התנהגויות ייחודיות לדפדפנים ספציפיים לא ישתקפו בו.

אם אתם רציניים לגבי אוטומציה – זהו כלי שבהחלט כדאי לבדוק!

הערה: עם ההצגה של WebDriver, יכול Selenium להריץ גם את Phantom.js ולהנות מהמהירות של דפדפן ללא Shell / שלא מצייר באמת על המסך. יש פה באמת פתח לתחרות אם כי נראה ש Casper דווקא הולך וצובר מומנטום למרות עובדה זו.

Template Engines

Template Engines הן הספריות שחוסכות מאתנו ללכלך את קוד הג’אווהסקריפט שלנו עם concatenations של מקטעי HTML.

מוד העבודה הוא לרוב כזה:

  • כתוב template ל HTML sinppet רצוי והשאר “placeholders” לחלקים הדינמיים.
  • אכסון את ה template כ string, כמקטע בלתי-נראה ב HTML או טען אותו ב ajax מהשרת.
  • “קמפל” (בעזרת ה Template Engine) “אוטומט” של ה template. תוצאת הקומפילציה היא פונקציה שמקבלת נתונים מתאימים ומייצרת על בסיס ה template מחרוזת HTML מתאימה. הערה: פעולת הקומפילציה היא אטית
  • הפעל את הפונקציה שנוצרה כדי להזריק נתונים ולקבל HTML snippet מעודכן – פעולה זו היא מהירה.

יש ה-מ-ו-ן ספריות של Template Engines: אני מכיר כ 15.
במבט ראשון, קשה מאוד להבין מה ההבדל. אפילו קריאה מהירה של ה tutorials – לא מגלה הבדלים משמעותיים בין הספריות.

אז מה בעצם ההבדלים? מדוע צריך כ”כ הרבה ספריות?

  • יש ספריות מהירות יותר ומהירות פחות בהזרקת הנתונים (חלקן יודעות “להזריק ל DOM” רק את מה שהשתנה)
  • יש ספריות מהירות יותר בשלב הקומפילציה.
  • (יש ספריות שלא מאפשרות קומפילציה – אבל מעט).
  • יש ספריות בתחביר ERB / JSP קרי ויש כאלו בתחביר {{ val }} – ענין של סגנון.
  • יש כאלו עם מעט לוגיקה של templating (לולאות, תנאים), יש כאלה עם הרבה לוגיקה (פונקציות, משתנים, …) ויש כאלו שבתור עקרון לא מאפשרות לוגיקה (כי לוגיקה אמורה להיות ב Model ולא ב View).
  • יש ספריות גדולות (כ 2k) או גדולות (כ 30K ויותר).
  • חלקן מתאימות יותר לצד הלקוח (דפדפן) וחלקן מתאימות יותר לצד השרת (node).
  • נראה אבל שהגרום המשמעותי לכך שיש כ”כ הרבה ספריות הוא שלרובן יש פטרון חשוב, מישהו שמקדם אותן ושומר על קיומן. מיד אחשוף מעט מהפוליטיקה המורכבת הזו.
בהחלט רשימה חלקית

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

שתי הספריות הבולטות ביותר הן כנראה mustache.js  ו handlebars.

Mustache.js(שבולטת בתחביר ה {{ x }}). הסוגריים המסולסלים נראים כ”שפם” שסובבו ב90 מעלות – ומכאן שמה. היא פשוטה ובעלת קהילה גדולה. הפטרון שלה הוא פרויקט mustache שיצר מימושים של התחביר לשפות תכנות שונות, javaScript היא רק אחת מהן. Mustache מקפידה לא לאפשר לוגיקה עסקית ב template. המימוש של mustache.js אינו “מקפל” templates ולכן איננה כ”כ יעילה. Handlebars ו Hogan הן ספריות המממשות את תחביר mustache בצורה יעילה.

Handlebars (מקור השם) היא הרחבה של Mustache המספקת יכולות משופרות, בעיקר רינדור הדרגתי ב DOM רק של מה שהשתנה – מה שגורם לה להיות אחרת הספריות המהירות בהזרקת נתונים. היא נכתבה ע”י יהודה כץ, וכך פטרון מרכזי של Handlebars היא ספריית Ember.js (שראינו בחלק א’ של הפוסט).

Jade היא לא ספרייה קטנה (כ 40kb) וכל כן כנראה היא פופולרית יותר בצד השרת (קרי node). הפטרון שלה הוא express.js – ספרייה מאוד דומיננטית ב node (סוג של low level Servlet ב node). jade הוא ה default שלה לייצור HTML markup.

Hogan.js היא ספרייה קטנה ומהירה מאוד שטובה ל templates פשוטים. היא תומכת בתחביר של mustache, ללא כל תוספות. הפטרון שלה הוא חברת טוויטר.

dust.js נחשבת ספרייה מבטיחה. הפטרון שלה הוא חברת LinkedIn.

doT.js היא עוד ספרייה פצפונית (פחות מ 3k) שטוענת להיות מאוד מהירה ותומכת בכתיבת לוגיקה. אין לי מושג מי הפטרון שלה… אבל בטח יש מישהו!

jsRender – היא “הדור הבא של jQuery Templates”. אני מניח ש jQuery Templates הייתה פופולרית בזכות המותג “jQuery”, אבל עובדה שזה לא הספיק לה. היא נסגרה. אינני יודע להשוות את jsRender לאחרות, אבל נדמה לי שהפופולריות שלה בנסיגה. הפטרון: רוחה של jQuery Templates.

איך משווים בין כל הספריות? איך בוחרים?

  1. אם אתם משתמשים בספרייה שעובדת עם אחד מהמנועים – נסו להיצמד אליה ולחסוך לעצמיכם בעיות אינטגרציה.
  2. נסו את http://garann.github.io/template-chooser/ – אתר שכל ייעודו לנסות לעזור לכם לבחור Template Engine.
  3. לא עזר? הייתי מהמר על הגדולות: Hogan – למשימות מיני, Mustache למשימות קטנות או Handlebars למשימות גדולות ומורכבות.

טעינת סקריפטים דינמית, AMD ו CommonJS

פירטתי על ספריות אלו והקשרים בניהן בפוסט require.js – צלילה לעומק.

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

גרפיקה וויזואליזציה

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

מאז הפוסט נראה ש D3 (קיצור של Data Driven Documents) רק הולכת וצוברת תאוצה!
מזכירים אותה המון, ומשתמשים בה בהמון פרויקטים – משמעותית יותר משאר הספריות בקטגוריה.

לינק: סקירה נוספת לספריות ויזואליזציה.

ספריות אחרות

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

Modernizr – “הספריה” ל Feature Detection. במקום לעקוב אחרי גרסאות הדפדפנים (כבר אי אפשר [א]) והיכולות שלהם, קרי “IE8 לא תומך ב SVG, אז נבצע fallback ל gif” – אפשר לשאול בעזרת Modernizr: “דפדפן, האם אתה תומך ב SVG?” ולפעול בהתאם. דרך כתיבה זו הרבה יותר אמינה (robust) לאורך זמן.

על feature detection ו שימוש ב Modernizr ניתן לקרוא בעברית בבלוג אינטרנט-ישראל.

Underscore.js – היא ספרייה נוספת מהיוצר של Backbone שמספקת utilities רבים: עבודה עם מערכים ואובייקטים, תכנות פונקציונלי או סתם utilities שעוזרים לכתוב קוד קצר יותר. כמו ש jQuery תופסת את השם “$”, Underscore תופסת את השם “_” ומכאן שמה. לדוגמה:

_.sortBy(array, function(n) {...});

פעמים רבות רציתי להשתמש ב underscore. צירפתי אותה למספר פרויקטים – אבל היא לא שרדה שם ללא Backbone (שם היא מתאימה כמו כפפה ליד): יכולות של ECMAScript 5 (כגון foreach על מערך) והסט המצומצם של utilties של jQuery (כמו each, filter, extend) – סיפקו את הסחורה מספיק טוב כדי לייתר את Underscore.

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

על Bootstrap ו Foundation ניתן להסתכל בשני אופנים:

  1. סט מוכן של של CSS files (ומעט javaScript משלים) לשימוש מהיר באתרי אינטרנט.
  2. ספריית UI מבוססת CSS ולא ג’אווהסקריפט – ועל כן רזה ומהירה.
שתי דרכי ההתבוננות נכונות במידה, אולם אני רוצה לפרגן ולהתמקד בנקודת המבט השנייה.
אי אפשר להתעלם מכך שרוב ה”קוד” בספריות אלו כתוב ב CSS – זה אולי מטריד כמה אנשים, אולם בסופו של יום הן מספקות פונקציונליות מקבילה ל jQuery UI או כל ספריית פקדים אחרת. מלבד הפשטות והביצועים הטובים שנובעים מהשימוש ב CSS, הן מאפשרות Responsive Design מובנה – כך שה”פקדים” או “Layouts” שלהם יתאימו את עצמם לכל גודל של מסך: מסך מחשב, טאבלט או סמארטפון – ויעשו את זה יפה. זה חלק מהיתרון של שימוש ב CSS.
שתי הספריות יכולות לעבוד יפה מאוד עם ספריות שאינן כוללות פקדים כגון MVC או Meteor.
נראה שההתפתחות של CSS3 (שהוא מתקדם בהרבה מ CSS2.1) – הוא שאפשרה זן חדש זה של ספריות.
אופי העבודה עם הספריות גם הוא דיי שונה:
  • לכל ספרייה של כ 100-200 CSS classes שעליכם להצמיד ל DOM במקומות הנכונים. יש כללים שיש ללמוד אילו classes יכולים להשתלב עם אחרים. “מאות CSS Classes” נשמע כדבר מאיים, אך ישנה חוקיות פשוטה ו references טובים שיאפשרו לכם להסתדר איתם בקלות.
  • הפקדים שנוצרים הם דיי “שמרנים”. אלו לא ספריות ל UI “סקסי ויוצא דופן” – אלו ספריות ל UI פשוט, אסתטי, אך לא מתחכם. לא תקבלו את פקד ה Date המשוכלל של jQuery UI, למשל. Bootstrap ו Foundation מתאימות במיוחד ל Multiple Page Applications (בניגוד ל SPA) – אפליקציות בעלות מספר רב של מסכים, שאנו רוצים שיהיו אחידים. אלו לרוב יהיו “אתרי אינטרנט המשרתים back-end” או LOB Applications (כלומר: אפליקציות עסקיות).
  • הנתונים עבור הפקדים לא מגיעים מקריאת JavaScript – הם מגיעים מה DOM. יש classes של תיאור נתונים ו classes של “קשירת נתונים לפקד”. איך הם מגיעים ל DOM? אולי מצד השרת (RoR, Java, node או ASP.NET), אולי ע”י קוד ג’אווהסקריפט (הנעזר ב template engine?) הדוחף אותם ל DOM. כלומר: מודל זה לא מיטיב מבחינת ביצועים עם אפליקציות שמחליפות נתונים כל הזמן (כמו Dashboards|).
התוצאה היא שאפשר דיי להסתבך ב SPA כשמנסים לעבוד איתן, אבל אפשר להתחיל מהר ולהתקדם מהר כשעובדים על MPA (כקונספט, יכולה להיות MPA עם דף אחד).

האם Bootstrap ו Foundations הן “הדבר הבא”? הדעות חלוקות.
כרגע הן קונספט חדש, מעניין וחם – שכדאי להכיר.

אז מה ההבדלים בין שתי הספריות?

  • Bootstrap (מבית טווטיר) משתמשת ב LESS, בעוד Foundationמשתמשת ב SASS (כיסיתי את LESS ו SASS בפוסט זה). אם אתם מושקעים כבר באחד הכלים – הרי לכם מוטיבציה להעדיף ספרייה אחת על השנייה.
  • ל Bootstrap יש בפירוש קהילה גדולה יותר. הנה אתר עם יותר מ 300 plugins והרחבות ל bootstrap. נ.ב.: הנתונים של JSter נראים מוגזמים לחלוטין, לפיהם נראה כאילו Bootstrap היא הספרייה הפופולרית בכל הפוסט – זה לא המצב.
  • Bootstrap תומכת ב IE7-8 (אם אתם פונים למגזר העסקי – זה משמעותי).
  • Foundation נחשבת גמישה יותר לשינויי עיצוב.
  • יש עוד הרבה הבדלים קטנים בפרטים ובסגנון של כל ספרייה.

סיכום

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

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

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

[א] כשגרסאות דפדפן יוצאות בקצב של 6 שבועות (כרום, פיירפוקס) או פעם בשנה (ספארי, IE) – כבר לא סביר באמת לעקוב בקוד אחר הגרסאות.

קישור רלוונטי:
https://github.com/codylindley/frontend-tools
הרבה ספריות Frontend וכמה השוואות

רשימה של ספריות Polyfill – ספריות שמאפשרות תכונות “חדשות” בדפדפנים “ישנים”

47 ספריות ג’אווהסקריפט שכל מפתח *חייב* להכיר (חלק א’)

האמת: לא באמת “חייב” – אבל כדאי. להכיר שהן קיימות ולדעת מה מרחב הכלים הקיים לפיתוח ג’אווהסקריפט.מתכנת שמגיע לג’אווהסקריפט מעולם ה NET. או JEE עשוי להרגיש קצת אבוד: בשתי פלטפורמות אלו (בעיקר NET.) המתכנת קיבל Stack שלם של טכנולוגיות קצה-לקצה שמתאימות לפתרון מגוון רחב מאוד של בעיות.

כשיש דילמה נוסח: “כיצד כותבים אפליקציות מסוג T ?” – פשוט הולכים לתיעוד של מייקרוסופט או סאן עורקל ולומדים מהי “הטכנולוגיה המומלצת” לצורך זה: ASP.NET? Entity Framework אולי JAAS או javaFaces? הכל (לכאורה) שם.

תמיד היה ניתן לחפש “מחוץ לקופסה” ולמצוא הרבה ספריות קוד-פתוח מעניינות – אך הספריות שהגיעו בחבילה היו “מספיק טובות”.

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

מאיפה מוצאים את הספריות הללו? תחפשו!

כנראה שתגיעו מהר מאוד תוסיפו לארסנל שלכם את jQuery כמה פקדים ויזואליים וכלי Shim (אם אתם תומכים בדפדפנים ישנים).

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

הכירו את JSter

הטריגר לפוסט הוא אתר נחמד שנתקלתי בו בשם JSter המרכז רשימה של ספריות ג’אווהסקריפט.
האם אין המון אתרים כאלה? – יש, אבל בג’סטר היו 2 דברים שקסמו לי:

  • הוא מנסה למיין את הספריות (בתוך הקטגוריות) ע”פ הפופולריות שלהן  – ולהציג קודם את הספריות החשובות ביותר.
  • הוא מוסיף לכל ספרייה את הלוגו שלה – תוספת קטנה, אבל חשובה, לטעמי. הכרת הסמלים עוזרת להתמצא ביתר קלות ולזהות מהר יותר ספריות שאתם “נתקלים בהן פעם נוספת”. שמות הספריות רבות בג’ווהסקריפט דומה ומזכיר אחד את השני. למשל: EmbedJs, Ember.js ו emojify.js או sprite.js, spine.js, spry ו spin.js. כאלה. לכו תבדילו.
אם JSter קיים – מדוע צריך את הפוסט הזה?
  • לכלי אוטומטי יש הטיות וטעויות. למשל ג’סטר קבע ש SenchaTouch היא ספריית ה Mobile במקום ה 16 (מתוך 19), ממש לאחר ספרייה כלשהי בשם JindoMobile (??). זו שטות גמורה ודיי ברור ש Sencha היא השנייה הפופולארית אחרי jQueryMobile, אם לא הראשונה. מקור הטעות נובע כנראה מכך שעל ספריות שלא מנוהלות ב Github לג’סטר אין נתונים והוא מדרג אותן אחרונות / ע”פ הצבעות באתר בלבד.
  • רציתי להוסיף כמה הערות משלי. ישנן ספריות פופולאריות אך בירידה, ישנן ספריות חדשות אך מאוד מעניינות ויש כמה מילים שאפשר לכתוב על הספרייה שיוצר הספרייה לא כתב עליה.
כמה הערות נוספות:
  • כפי שציינתי, ניסיתי להתמקד בספריות “טווח ארוך” ולא כאלו שפותרות בעיה מיידית.
  • ניסיתי לקבץ את הספריות קצת אחרת מג’סטר בצורה שנראתה לי יותר הגיונית.
  • עדיין השתמשתי בצילומי מסך מג’סטר הכוללים נתונים שימוש מ github. ג’סטר יתעדכן עם הזמן, והפוסט הזה – לא.
  • יש כאן עניין של דעה אישית – שאחרים עלולים לא להסכים איתה. אני כבר מצפה לכמה תגובות בנוסח: “אבל איך לא ציינת את ?”
  • גם ל”כלי אנושי” יש הטיות וטעויות. ייתכן ויש ספריות שאני חושב שהן “לא פעילות” או “פאסה” – ואני פשוט לא יודע.
  • אני מציג בכל קטוגריה מספר ספריות שהן חלופות אחת לשנייה. אינני מנסה להמליץ ללמוד את כולן, חס ושלום. בעיקר נראה לי חשוב להכיר את האופציות השונות ותחומים בהן כל אופציה חזקה.
יאללה לדרך!

ספריות בסיס

jQuery היא ספריית “חובה” שבשימוש ע”י כמעט-כל מפתח ווב שאני מכיר. Zepto היא ספרייה המציגה API תואם ל jQuery – אבל עם כמה הבדלים:

  • Zepto, בהגדרה, תומכת רק בדפדפנים מודרניים. היא לא תומכת ב IE (אם כי תמיכה ב IE גרסה +10 נשקלת).
  • היא לא כוללת את כל הפונקציונליות, אלא קצת פחות. מה שקיים – תואם ל jQuery.
  • גודל הספרייה היה כשישית מ jQuery כשהספרייה הוצגה, כיום הוא כשליש.
מדוע להשתמש בספרייה שעושה את מה ש jQuery עושה, תומכת בפחות דפדפנים ובפחות פונקציות? בגלל הגודל.
קהל היעד של Zepto היה בעיקר אפליקציות / אתרים למובייל, היכן שגודל ה javaScript הוא משמעותי לביצועי האפליקציה.

דיי מהר הפכה Zeprto לאופציה פופולרית בעולם המובייל. “שליטה בעולם המובייל?!” – jQuery נלחצה, נבהלה, והגיבה בהתאם: התפצלה לגרסת “Legacy Support” (גרסאות 1.9) וגרסה רגילה (גרסאות +2) והוסיפה אופציה לוותר על פיצ’רים כדי להפחית את נפח ההורדה ולצמצם פערים מול Zepto (עדיין יש פער – אבל מפתחים רבים יוותרו עליו בכדי לזכות ב jQuery שהם מכירים). נחייה ונראה כיצד תחרות זו תמשיך ותתפתח.

Prototype ו MooTools היו שתי מתחרות של jQuery שלא עמדו בתחרות. אני לא מכיר אף אחד שמשתמש בהן כיום – אבל יש עדיין המון קוד כתוב שעובד איתן, בעיקר עם Prototype.
עוד על jQuery וחברותיה כתבתי בפוסט מבוא מואץ ל jQuery עבור מפתחי #C ו Java מנוסים.
לינק: השאווה בין הספריות (ע”פ Minified)

Frameworks בסיס

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

עוד הבדל מהותי הוא שבפיתוח עם jQuery המפתח עדיין עובד עם ה abstractions של הדפדפן, קרי Style Sheets, DOM וכו’ – jQuery מספקת API נוחים יותר לעבודה עם מודל זה. עקרון זה נכון גם, פחות או יותר, עבור Polymer.
Enyo, YUI ו Dojo מספקים abstraction שהוא הרבה יותר Object Oriented ומבוסס javaScript – תמונת עולם שמשקפת פחות טוב את מה שקורה בדפדפן – ולכן כנראה קשה יותר לסגל אותה לחידושים בדפדפן.

הבדל מהותי אחרון הוא נושא ההיקף: אפשר לומר של jQuery ו YUI (או Dojo) יש חפיפה, אולם בעוד של 80% מהיכולות של jQuery יש תחליפים ב YUI/Dojo – אולי ל 30% מהיכולות של YUI/Dojo יש תחליפים ב jQuery. רשימת היכולות שיש ל YUI ואין ל jQuery כוללת: פקדי UI (מה שמכוסה חלקית ע”י jQuery UI), הרחבות לשפת ג’אווהסקריפט שמספקות מחלקות (בניגוד לאובייקטים, מה שנקרא Class System), ניהול state על ה URL, יכולות input validation, ועוד.

Dojo ו YUI הן דיי מקבילות אחת לשנייה בסט היכולות (שכולל הרבה מאוד), אם כי פילוסופיות המימוש שונות. נראה שמעמדן הולך ונשחק עם השנים לטובת jQuery עם השלמות. כלומר: במקום לבחור ב Framework אחד שעושה את רוב העבודה – מעדיפים להרכיב סט מותאם-אישית של ספריות קטנות יותר.
שתיהן ספריות שהשפיעו רבות על הרבה עולם הג’אווהסקריפט ורבות מהספריות החדשות שאנו רואים כיום הושפעו לקחו רעיונות משתי ספריות אלה. על כן, שמור להן מקום של כבוד בפנתאון של עולם הג’אווהסקריפט – לנצח (קרי כ-5 עד 10 שנים).
Polymer היא המאפה החם החדש מהתנור של גוגל שאמור לאפשר לנו להרחיב את שפת ה HTML לתגיות משלנו תוך שימוש בתקנים עתידיים כגון HTML Custom Elements, שימוש ב HTML Imports  – בכדי לשתף תגיות אלו ו Shadow DOM על מנת לקבל הפרדה בין קוד התגיות לשאר התוכנה ולמנוע התנגשויות. יש לה גם ספריית UI עם אלמנטים מוכנים לשימוש חוזר. Polymer משתמשת בסדרה של polyfills = מימושים בג’אווהסקריפט שמדמים תקן עתידי עוד לפני שהדפדפנים תומכים בו. ברגע שדפדפנים יחלו לתמוך בתקנים אלו (אם וכאשר) – סביר שהביצועים יהיו טובים יותר ושבעיות מסוימות תפתרנה.Polymer כנראה תשתלב יפה עם Angular.js – ספרייה אחרת מבית גוגל (בהמשך הפוסט).
כתבה רלוונטית: Google Believes Web Components are the future of Web Development.

Enyo פותחה במקור עבור מערכת ההפעלה WebOS – אבל נתרמה מאז לקהילה. עקרונות רבים דומים בה ל YUI או Dojo – כך שלא קל לומר מייד במה היא מחדשת. Enyo החלה במקור כספרייה למובייל (כ”ספריית הבית” של WebOS) אבל היא מתאימה לחלוטין גם ל Desktop. נקודת חוזק בה היא היכולת לפתח אפליקציה שתרוץ גם על desktop, גם על mobile וגם על יצירי כלאיים (Phablet, מחשב נייד עם touch וכו’). ל Enyo יש גם חבילת התאמה ל PhoneGap/Cordova לפיתוח Hybrid Web Apps (פוסט רלוונטי).

עדכון: עוד Framework נפוץ למדי הוא ExtJSבשנת 2010 ExtJs חברו לספריות jQtouch (בהמשך) ו Rafael (בפוסט ההמשך) לחברה שנראה Sencha.

ExtJS היא ספרייה עשירה ומלאה בנוסח YUI ו Dojo, אם כי ברמת מודל ההפשטה שלה היא התרחקה צעד נוסף מה DOM/HTML/CSS והיא קרובה יותר למודלים של פיתוח אפליקציות Desktop כגון Spring או AWT. המומחיות של ספרייה זו היא אפליקציות עסקיות ויש לה פקדים עשירים מאוד ליצירת טבלאות וגרפים. ל ExtJS יש כנראה את סט הפקדים העשיר ביותר מבין ספריות הג’אווהסקריפט. התוצרים של ExtJS “כבדים” יותר מ YUI ו Dojo מבחינת כמות ומורכבות ה javaScript שנוצר – ולכן מתאימים יותר לאפליקציות שרצות ב LAN (בניגוד ל YUI ו Dojo שכוונו לאפליקציות אינטרנט). בגרסה האחרונה שלה (4.0) ExtJS עברה הרחבות משמעותיות הוסיפה גם תשתית MVC.

קישור: השוואה בין יכולות הספריות שהזכרנו (מלבד Polymer שעדיין לא נכנסה לטבלה)

ספריות למובייל

מובייל הוא היום הנושא החם, והוא רק הולך וצומח במהירות. סביר שהשפעתן וחשיבותן של ספריות אלו רק ילך ויגבר עם הזמן:
jQuery Mobile (בקיצור JQM) היא לא הספרייה הכי ותיקה – אבל היא מתהדרת במותג “jQuery” שכנראה מאוד עוזר. היא גם דיי טובה. היא ו Sencha Touch מתמודדות זה זמן רב על הבכורה.JQM מתבססת על jQuery והיא פחות או יותר המקבילה למובייל של jQuery UI . היא מספקת מנגנון לחלוקת אפליקציית המובייל לדפים ואת ניהול המעברים בין הדפים – ועושה זו בצורה דיי יעילה.
בנוסף היא עוזרת לטפל ב touch (תכונה חשובה מאוד במובייל) ויש לה סט גדול של פקדים המותאמים למובייל. היא כוללת Theme Roller שמסייע לשנות את צבעי האפליקציה בקלות (אם כי הוא קצת מוגבל) ואפשר למצוא לה עורכי WYSIWYG – לתחילת עבודה מהירה.

הבדל גדול בין JQM ל Sencha הוא ש JQM היא חינמית בעוד Sencha תגבה כסף מארגונים (יש כמה הקלות עבור סטארטאפים ופרויקטי קוד פתוח). Sencha Touch, כמו YUI או Dojo מספקת תמונת עולם (הפשטה) שאיננה מבוססת על HTML, DOM ו CSS – יש שאוהבים זאת ויש כאלו שלא (אני מאלו שלא).

בניגוד ל JQM ו SenchaTouch בחרו בפקדים וחווית UI “ניטרלית” למערכת ההפעלה, KendoUI (יש לבטא: “Can Do UI”) מייצר UI שנראה כמו מערכת ההפעלה שהיא רצה עליו: iOS, Android וכו’. אפשר לטעות במבט ראשון באפליקציה ולחשוב שהיא Native Application של מערכת ההפעלה, אולם “גליצי’ם” קטנים פה ושם – יסגירו אותה לאורך הזמן.
אני רואה אותה מוזכרת הרבה במאמרים ובפוסטים – אם כי אני לא מכיר אף אחד שבאמת עובד איתה.
jQTouch (שהשתנה לאחרונה את שמה ל jQT – נראה שג’סטר פספס את זה איכשהו) היא ספרייה דיי ותיקה (מאז 2009?) שלא כ”כ המריאה עד אשר התאחדה עם ExtJs לחברת Sencha. היא:

  • חינמית (כרגע)
  • תלויה ב jQuery – וחולקת איתה את פילוסופיית השמירה על ה abstraction של הדפדפן.
  • מיועדת כרגע רק ל webKit (צעד טקטי, לפי דעתי), בעוד JQM מיועדת לכמעט כל מכשיר מובייל ששמעתם עליו.
  • כמו KendoUI – מספקת UI שמחקה את מערכת ההפעלה עליה היא רצה.

אני מבין את Sencha שרוצה Plan B במידה ויתגלה שהאסטרטגיה של Sencha Touch נכשלת. האם הייתי מהמר באפליקציות שלי על ספרייה שכזו?…

ספריות Client Side MVC

ספריות אלו הפכו כמעט לחלק בלתי-נפרד מפיתוח של כל מערכת בגודל בינוני ומעלה בג’אווהסקריפט (צד-לקוח). במיוחד ב Single Page Applications (בקיצור: SPA).

כתבתי על הקונספט וקצת על הספריות בפוסט הצצה מהירה על Backbone.js

עלי לציין שבעת כתיבת הפוסט ההוא הייתי תחת הרושם ש Backbone, Ember ו Knockout הן שלושת הגדולות ויש עוד “כמה בינוניות” בניהן Angular.js. מאז, למדתי מכמה מקורות ש Angular היא דווקא מאוד פופולרית, כנראה שנייה לאחר Backbone ובעלת אופק חיובי. התחלתי להכיר אותה ולהבין גם מדוע.

Backbone היא עדיין הספריה הפופולרית ביותר – אם כי במגמת ירידה קלה. מתכנתים רוצים יותר ממה שהיא מספקת. אופציה מעניינת אחת הוא plugin פופולרי ל Backbone בשם MarionetteJS שחוסך הרבה “הקלדות חוזרות” שקיימות ה Backbone.
עדיין נראה לי שתוך שנה-שנתיים האחרות יתפסו את הבכורה ו Backbone תהפוך קצת יותר לספריית נישה לאלו שאוהבים הרבה שליטה על הקוד שלהם.

עדיין – זו הספרייה הטובה ביותר להתחיל ללמוד ממנה מהו Client-Side MVC. הייתי עדיין פותח בה בכדי ללמוד את העולם הזה, לפני שהייתי מבצע בחירה אחרת ומשקיע את הזמן הרב הנדרש בלימוד Ember, Angular או Knockout.

ספריות צד-שרת

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

  • גישה לקבצים
  • פעולות Networking
  • ריבוי threads (לפחות נרצה אחד לכל Core של מעבד)
  • הפשטה וכלים לביצוע משימות נפוצות של פיתוח צד-שרת, כגון Express שהיא המקבילה (ה low level) של Servlets על Node.

האם היא תחליף את ג’אווה כפלטפורמה – עדיין מוקדם לומר.

Meteor היא מעין יציר כלאיים: מטרתה לאפשר פיתוח מהיר מאוד של אפליקציות. “לאיפה הולך זמן רב?” החבר’ה של Meteor שאלו – “אהה, כן. לאינטגרציה בין שרת ולקוח”. Meteor רצה מצד אחד על Node לכתיבת השרת ומצד שני בצד הלקוח על הדפדפן ועושה את האינטגרציה – קלה מתמיד. היא דיי חדשה – אך יש מסביבה לא מעט באזז.

כותבי אפליקציות עסקיות: זוהי ספרייה שמכוונת להיות Enterprise class ולא עוד “צעצוע”.

בחלק הבא

בפוסט ההמשך נראה עוד ספריות חשובות: בדיקות, Template Engines, ויזואליזציה, ניהול תלויות ועוד – וכך נשלים את המספר ל 47. זאת התכנית, לפחות.

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

Backbone.js – ספגטי או רביולי?

״קוד ספגטי״ הוא תיאור של קוד סבוך, מלא תלויות – ועל כן קשה לתחזוקה. בכל פעם שעושים שינוי באזור אחד בקוד, קיים סיכוי גבוה ״לשבור״ אזורים אחרים בקוד. ״קוד רביולי״ הוא המושג ההפוך המתאר קוד מודולרי וקל לתחזוקה: רביולי הם נפרדים אחד מהשני ויש להם הכמסה טובה – רביולי אחד לא יכול לגעת ב״מילוי״ של השני.
ג׳אווהסקריפט מעלה את נושא ״קוד הספגטי״ מחדש למרכז הבמה: מתכנתים רבים נכנסים עכשיו לעולם הג׳אווהסקריפט, עולם עם מעט הגנות והרבה אפשרויות ליצור “קוד ספגטי”. ג’אווהסקריפט לא תוכננה בכדי לתמוך במערכות גדולות, והאופי “מונחה-האירועים” מעודד פיזור אחריויות ויצירת תלויות רבות. מי שחושב ששפה איננה אחראית לאיכות הקוד – שייזכר בפקודת ה GOTO בשפת בייסיק.
ספריות JavaScript MVC באו לנסות ולעזור למתכנתי ג’אווהסקריפט לעשות סדר – אך האם הן מספיקות?
בפוסט זה אני רוצה לעזוב את מסלול הTutorial שהתחלנו בו לגבי Backbone.js (בקיצור: BB): מסלול שמציג את יכולות הספרייה בצורה אופטימיסטית בה הכל מסתדר יפה. אתם בוודאי מכירים את המצב הבא: אתם לומדים טכנולוגיה, עושים כמה tutorials ומרגישים שהכל ברור ואז אתם מנסים את הטכנולוגיה בעבודה היומיומית שלכם ו…”הופ” – נתקעים אחרי שעות בודדות רק כדי לגלות איזו בעיה עקרונית, מוכרת, שהרבה פורומים דנים בה – אך יש לה מעט פתרונות יפים. מכירים?!
ספריות JavaScript MVC הן לא שונות, ועל כן אני רוצה להציג גם את הצדדים הללו.

שייך לסדרה: MVC בצד הלקוח, ובכלל.

קוד “ספגטי”?

בחרתי להתמקד בדוגמה “קטנונית” לכאורה. הדוגמה מבוססת על מודל ה Person וה View בשם PersonView מהפוסטים הקודמים. בחלק זה הוספתי לה את היכולת לעשות expand/collapse לפרטים של האדם (במקרה שלנו: האימייל) + אייקון יפה שמציג את המצב, “פתוח” או “סגור”.

הנה הקוד:

הקוד אמור להיות ברובו מוכר.

1- העשרתי מעט את ה template. הוספתי תמונה המתארת את מצב הפריט ברשימה (סגור/פתוח) והוספתי class בשם hidden שבעזרתו אני מסתיר חלקים ב markup. תיאור ה class יהיה משהו כמו:
.hidden {
  display : none
}

טכניקה זו מאפשרת לי להסתיר / להציג את ה markup ע”י הוספה / הסרה של CSS class – פעולה קלה בjQuery.

2 – שימוש במנגנון האירועים של BB. הפורמט הוא key: value, כאשר:
Key = מחרוזת: “.
Value = מחרוזת עם שם הפונקציה באובייקט ה View שתופעל כתגובה לאירוע.

BB בעצם מפעילה כאן את jQuery: היא רושמת את הפונקציה שהוגדרה ב value, לשם האירוע (למשל “click” או “keypress”), על האלמנט(ים) שחוזרים מהשאילתה.

את השאילתה היא מבצעת על אלמנט ה el, ואם לא הוגדרה שאילתה – היא מפעילה jQuery.delegate על el, כך שהאירוע יופעל עבור כל אלמנט-בן של el.

בנוסף, BB גם עושה עבורנו Function Context Binding (לטיפול ב this) – כך שאין צורך לבצע bind/bindAll לפונקציית הטיפול באירוע.

את האובייקט הנכון של ה View היא מזהה בעזרת ה cid שעל ה el – מה שחוסך לנו הרבה עבודה.

3 – זו הפונקציה שתקרא לאחר שהמשתמש לחץ על ה person-frame שלנו. היא מזהה את המצב הנוכחי ומבצעת את השינויים הדרושים ב DOM. קריאת toggleClass של jQuery מסירה / מוסיפה CSS class בדיוק עבור שימושים כאלו.

הנה ההרצה של הקוד:

1 – אנו מוודאים שה default הוא הנכון.

2 – אנו מדמים לחיצה של משתמש על ה person frame ומוודאים שהמצב השתנה.
טיפ קטן: אני משתמש ב (‘trigger(‘click, הקצת פחות קריאה, ולא ב ()click הקצת פחות אמינה. כמה דפדפנים מונעים שימוש ב click ישירות.

3 – אני בודק גם את המצב ההופכי, עבור שלמות הבדיקה.

הקוד נראה בסה”כ קריא, ולא כ”כ מסובך. מדוע אם כן אני קורא לו “קוד ספגטי”?

  1. אנו שומרים state של האפליקציה (isExpanded) על ה DOM.
    נכון, זו טכניקה מקובלת בג’אווהסקריפט – אבל זה “ספגטי”: כל פעם שאנו רוצים לעשות שינויים ויזואליים אנו צריכים “לבחון” את ה DOM ולהסיק מה המצב שלו. כשהקוד גדל ונהיה מסובך – זה יכול להיות פשוט סיוט של קוד.
  2. אנו מציבים לעצמנו מגבלה שה View לא יתרנדר מחדש. אם מרנדרים אותו – אנו מאבדים את ה state שלנו.
  3. ה markup שלנו נובע בעצם מ 2 מקורות שונים: מה template וממנהלי האירועים. כדי להבין מה / כיצד נוצר – יש לבחון את שניהם, מה שיגרום לנו לשאול את עצמנו: “מאיפה ‘זה’ הגיע…?”

אפילו בקוד הבדיקות, “נגררתי” (עלק) לבדוק את מצב ב DOM: האם יש css class מסוים או לא. מבנה ה DOM הפך לציבורי.

מודל רזה או שמן?

ב JavaScript MVC יש בגדול 2 אפשרויות כיצד לחלק את האחריויות בין ה View וה Model:
  • “מודל רזה” (נקרא גם anemic model) – המודל הוא בעיקרו DataStructure / DTO שמחזיק בצד הלקוח עותק קונסיסטנטי של מצב האובייקט בצד-השרת / בבסיס-הנתונים. כל הלוגיקה ה”עסקית” מתרחשת ב View.
  • “מודל שמן” (נקרא גם rich model) – המודל הוא המקום בו מתרחשת הלוגיקה העסקית, בעוד ה View הוא רק שיקוף של UI למצב המודל.
BB, באופן רשמי, לא נוקטת עמדה לגבי הגישה המועדפת. “אפשר גם וגם”.אם אתם משתמשים ב”מודל רזה”, BB מספקת מנגנון בשם Backbone.sync שעוזר לשמור / לטעון את המודל משרת בעל RESTful APIs: אם תגדירו על מודל / אוסף (collection) את ה url של השרת / REST servuce ותקראו לפעולת ()fetch, ספריית BB תקרא לאותו ה URL ב get (קונבנציות REST) ותטען מחדש את המודלים מהשרת. פעולת create על האוסף תיצור בשרת (ולאחר תשובת HTTP 201 – גם באוסף שלכם) את המודל. כנ”ל יש גם update ו delete וכו’.

אם אתם משתמשים ב”מודל שמן” – אזי BB מספקת פחות תשתיות מוכנות. אין בעיה להוסיף פונקציות על המודל שמחשבות ערכים, כגון ()isVIP שמכילה את הלוגיקה האם Person מסוים הוא אדם “חשוב מאוד”.

הקושי נובע מהמצב בו אתם רוצים לשמור על המודל client-side state או ui state – כלומר properties שישמשו אתכם בצד הלקוח אך לא תרצו לשמור בשרת.
כיצד תוכלו לומר ל BB אילו תכונות של המודל נשמרות בשרת ואילו לא? BB לא מספקת יכולת מובנה לדילמה זו.
ההורשה ב BB, כלומר extend._ איננה הורשה אמיתית, היא בעצם ממזגת עותק של אובייקט האבא (כלומר Prototype Design Pattern) עם אובייקט חדש שאתם מגדירים.
BB גם לא תומכת בארגון מודלים בהיררכיה – רק ברשימות (כמו טבלאות ב DB רלציוני). כלומר: איננו יכולים להשתמש בהיררכיה על מנת להפריד בין ה״מודל לשמירה בשרת” ל״ערכי המודל של צד-הלקוח״.

  1. לפלטר את ה ui state בצד השרת? אאוץ.
  2. אפשר להשתמש בplug-in ל BB שמאפשר ניהול היררכי של מודל (במקום הורשה), משהו כמו BB deep model. קצת מסורבל.
  3. אפשר לוותר על שימוש ב Backbone.sync ולפלטר לבד את ה ui state.
בואו נבחר בדרך מס’ 3.בלי קשר לבעיה זו – אינני אוהב את הדרך בה עובד מנגנון הסנכרון לשרת של BB :

  • הוא בעיקר עושה דלגציה ל ajax.$ ומוסיף עליה מעט מאוד. אני מרגיש שבנקודה זו BB לא השקיעה בי מספיק.
  • נקודת הגישה לשרת נעשית דרך המודל ולא ישירות – דבר שלא מרגיש לי נכון. טיפול בשגיאות והתנהגויות חריגות הוא מסורבל, הקשר ההדוק הזה מקשה על היכולת לבצע בדיקות-יחידה, ואי אפשר להשתמש ב Backbone.sync עבור צורות תקשורת אחרות (למשל Push/WebSockets).

“מודל שמן” ב Backbone.js

הנה המודל שלנו ב”גרסה השמנה” (Rich Model):

  • הוספתי למודל תכונה בשם isCollapsed שהיא חלק מה UI State שלו – שלא אמור להישמר בבסיס הנתונים.
  • יצרתי מתודה בשם getJSONToPersist שתחזיר לי את ה JSON של מה שצריך להישמר בשרת. ניתן ליצור superclass חדש של BB.Model על מנת למחזר קוד זה.
  • את השינוי במצב (גלוי/חבוי) שייכתי לפונקציה במודל בשם toggle. כרגע היא מזערית, אך זה הרגל טוב לכתוב גם פונקציות לוגיות מזעריות – במקום הנכון. הן נוטות להתרחב.
  • הוספתי עוד דוגמה לפונקציה “לוגית” קצת יותר עשירה בשם isVIP. היא איננה בשימוש בדוגמה זו (ולכן מסומנת באפור).

הנה ה View:

אפשר לראות שיש 2 templates עבור כל מצב: Collapsed או Expanded – גישה זו טובה כאשר יש 2-3 מצבים. אם יש יותר – אז כדאי להחזיק template בסיסי ולבצע ב ()render שינויים ב markup.

המחזור של תגובה-לאירוע שונה משמעותית מזה של הדוגמה הקודמת:
אם קודם המחזור היה: רינדור View ל DOM, לחיצה של משתמש, אירוע -> שינוי ה DOM,
עכשיו המחזור הוא: רינדור View ל DOM, לחיצה של משתמש, אירוע -> שינוי המודל -> אירוע שינוי המודל -> רינדור ה View ל DOM.

השינוי מתרחש במודל – וה View משקף אותו. ב View אין חוכמה לוגית / עסקית – הוא מטפל ב UI נטו.
שימו לב שעל מנת לשנות את המחזור, הוספתי binding לאירוע ה change של המודל בבנאי – כלי נוח ש BB מספק לי.
קוד ה render הוא לא קצר הרבה יותר מהדוגמה הקודמת – אך הוא פשוט יותר ו”שביר” פחות. הוא בוחן את המודל (קוד js פרטי ולא DOM – שיכול להיות מושפע מהרבה מקורות) ורק על פיו הוא מחליט מה לצייר.
אין לי צורך “לבצע delta” (במקרה זה: הסרה של ה CSS Class בשם hidden) כי בכל מחזור אני מתחיל על בסיס ה template מחדש – דבר שמפשט את הקוד משמעותית.

שיקולי ביצועים

אחד הדברים שהכי בולטים בקוד ה”רביולי”, מלבד שהוא קצת ארוך יותר, הוא שהוא עושה יותר עבודה.
במקום לשנות ב DOM משהו קטן – רינדרנו חתיכת markup מחדש והחלפנו את כולה. “שיטת המוסכים המורשים” – אני קורא לה: “שריטה בדלת? – נחליף דלת”, “רשרוש במנוע? – לא מתעסקים. נחליף את המנוע”.

זה עשוי להראות דיי מרתיע – אך לרוב אין פה בעיית ביצועים אמיתית: רוב הפעמים ההחלפה תהיה של “מודל בודד” שלא יכלול הרבה markup – ולכן החלפתו לא תהיה יקרה.

אם שמתם לב, הוצאתי את “קימפול” של ה templates (פקודת template._) מחוץ ל instance הבודד של ה view – זה דבר משמעותי הרבה יותר מבחינת ביצועים!

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

  • אתם יכולים לעשות binding לשינוי של שדה ספציפי במודל, בפורמט ‘<change:<field name’ על מנת להיות מסוגלים להגיב לשינויים נקודתיים מאוד.
  • אתם יכולים לבקש מ BB להשתמש ב el קיים ב markup ולא לייצר אותו, כך שתוכלו להשתמש בספריית templating סלקטיבית (לדוגמה pure.js או handlebars) – אשר עושה שינויים ב markup מבלי לרנדר אותו כל פעם מחדש.
  • אתם יכולים לא להשתמש בספריית templating ולבצע רינדור סלקטיבי בעצמכם. עשו סדרה של שינויים ב DOM – אך שאבו את המידע מהמודל ולא מה DOM.

אני בטוח שיש עוד כמה דרכים אפשריות…

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

סיכום

כל חובב בישול יאמר לכם שרביולי הוא טוב מספגטי. ספגטי הוא דיי … פושט.
בתור מישהו שעוסק הרבה ב״הנדסת תוכנה״, אני מתפתה להצטרף למקהלה ולהעדיף אוטומטית את “מודל הרביולי” – אך לא כך.

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

הבעיה: כאשר מתרגלים לסגנון אחד – קשה לעבור לשני.
לאחדים (כמוני) שהתרגלו לכתוב רק “קוד רביולי” – קשה מנטלית לכתוב “קוד ספגטי” גם כשהדבר נכון. זה גורם להרגשה רעה.
לאחרים, שהתרגלו לכתוב “קוד ספגטי” – קשה מנטלית לכתוב “קוד רביולי” – זה מרגיש מיותר ומעייף.

אני מניח שאם הגעתם להתעסק ב Backbone / JavaScript MVC – כנראה שעלה צורך ל”קוד רביולי”.
אני, הייתי הולך עם זה עוד צעד קדימה – ועובד עם “מודלים שמנים, Views רזים”.

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

 

Backbone.js (ספריית MVC) – אוספים

בפוסט הקודם, הצצה ל Backbone.js (בקיצור BB, ובלי לדבר על פוליטיקה) ראינו את שני הטיפוסים המרכזיים ביותר של ספריית BB. בפוסט זה ארצה להרחיב מעט את היריעה לטיפוס מרכזי נוסף שנקרא Collection שמסייע לארגן את המודלים במערכת.
להזכיר: מודל (model) מייצג אובייקט המתאר “יישות בעולם בו עוסקת המערכת”, קרי Domain Object. לעתים קרובות נרצה להציג / לטפל בסדרה של מודלים. BB מאפשר ותומך בצורך זה בעזרת Collection שהוא אוסף של מודלים, המספק יכולות מתקדמות יותר מרשימה פשוטה.שייך לסדרה: MVC בצד הלקוח, ובכלל.

דוגמה בסיסית

בואו נפתח בדוגמה פשוטה:

אתם יכולים לזהות מודל מינימלי בשם Person ואת האוסף (Collection) בשם People – אוסף של Person.

1 – ההגדרה של model בבנאי של האוסף אינה נדרשת בשלב זה. היא משמשת רק כאשר משתמשים ביכולות ה REST המובנות ב Backbone.Model ו Backbone.Collection על מנת לסנכרן שינויים לשרת. איננו עוסקים ביכולת זו עדיין, אך אני מעדיף להגדיר את המודל לצורך הקריאות. הקונבנציה המקובלת ב BB היא לקרוא לאוסף בשם הרבים (s בסוף) של המודל, למשל Invoice ו Invoices.

2 – אנו יוצרים מודל (בצורה נאיבית, אציג דרכים יעילות יותר בהמשך) של מג’יק ג’ונסון ומוסיפים אותו לאוסף.

3 – לכל מודל (בעצם לכל אובייקט של BB) שנוצר ניתן מזהה גלובלי ייחודי, בפורמט “c”. במקרה זה אני יודע שאובייקט של מג’יק ג’ונסון הוא השלישי שנוצר במערכת ועל כן אני יכול לאמת את ה cid שלו. זו הנחה שלא הייתי רוצה להסתמך עליה בקוד אמיתי.
cid הוא קיצור של Client Identifier, שנועד לסייע לזהות מופע של מודל בצורה ייחודית. ב BB מניחים שצד-השרת, בעקבות השימוש בבסיס נתונים כלשהו, יהיה לכל אובייקט זיהוי ייחודי. בטווח הזמן בו האובייקט נוצר בצד-הלקוח ועדיין לא נשמר בבסיס הנתונים וקיבל Id ייחודי מבסיס הנתונים, ה cid אמור להיות כלי העזר על מנת לזהות ייחודית את המודלים.

4 – הוספנו עוד מודל אחד לאוסף.

5 – אוסף של BB, באופן מובנה, יכול להשתמש utilities של underscore.js – שהם דיי שימושיים. הנה דוגמה של פונקציה בשם plunk שעוברת על כל אחד מהמודלים באוסף, ומכניסה לתוך מערך התשובה ערך של שדה שהוגדר, במקרה זה – כל שמות המשפחה. כמה נוח.
כן, underscore.js “מתעסק לנו” באובייקטים בסיסיים של השפה כמו “Object” או “Array”‘, במקרה זה הוא הוסיף את plunk ומתודות אחרות למערך. נכון, זה משהו שממליצים לא לעשות. לא לעשות באפליקציה – אך זה “מותר” לספרייה. תתרגלו.

Collection ו Views

הנה דוגמה מורכבת מעט יותר המציגה חיבור של Collection ל View:
View אחד עבור כל Person, ועוד View עוטף של האוסף People.

התוצאה, עבור אוסף מינימלי של 2 אנשים, תראה משהו כזה:

הכותרת “שני אנשים” שייכת לPeopleView, והשאר נוצר ע”י שני מופעים של PersonView. בלי שום Styling כמובן – בכדי לצמצם את גודל הדוגמה.

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

ב1 – אנו יוצרים אוסף בשם people ומזינים אותו בערכים. המשמעות של reset היא “החלף את כל הערכים הנוכחיים ברשימת הערכים הבאה” והיא האופן בו נרצה להזין ערכים כאשר אנו טוענים מצד-השרת רשימה מלאה של ערכים. אנו מזינים את people במערך של אובייקטים שכל אחד מתאר את המודל של הרשימה – Person.

ב2 – אנו יוצרים את ה PeopleView, ה View שיודע להציג את הרשימה וליצור את ה HTML הנ”ל. נראה את הקוד שלו מייד.

ב3 – כך מבצעים בדיקת-יחידה יציבה (לא-שבירה) עבור תוצאת HTML. טעות נפוצה היא להשוות את כל תוצאת ה HTML כ String לערך שהיה נכון בסוף רגע הפיתוח ובחנו שהוא תקין. הבעיה: כל שינוי ב markup – אפילו ריווח או תוספת תג לא משמעותית (למשל label) תשבור את הבדיקה – גם כאשר התוצאה עדיין תקינה. הדרך הנכונה לבדוק היא לאתר “עוגנים חשובים” ב HTML ולבדוק רק אותם. האומנות היא למצוא את רמת הפירוט האופטימלית.
אנו מאמתים את טקסט הכותרת
אנו מאמתים את מס’ האלמנטים מסוג h2
אנו מאמתים שהטקסט של הראשון הוא “ג’ונסון, מגיק” – כלומר את הפורמט. eq היא המקבילה של jQuery ל index.
אנו מאמתים שאחרי (“~” ב css selector) הכותרת h2 הראשונה ישנו אלמנט p שמכיל את כתובת האימייל של זיגי. איננו רוצים “להפיל” את הבדיקה אם מחליפים את התחילית “email” באייקון קטן, למשל. אנו מתמקדים בנתונים ההכרחיים.

ב4 – אנו מבצעים reset לנתונים – עם רשימה באורך 3, רק כדי לוודא שהכותרת הראשית (h1) אכן תלויה באורך הרשימה.

הנה הקוד עצמו:

ההתחלה אמורה להיות מוכרת. פרקטיקה טובה היא להוסיף ערכי defaults למודל עבור כל שדה שאנו הולכים להשתמש בו ב View – אחרת אנו עשויים להיתקל ב Runtime Errors ללא fallback (למשל כשיש מודל עם age בלבד).

1 – לא התאפקתי והשתמשתי הפעם ב template engine – שהיא הדרך המומלצת ב BB כדי לייצר את ה markup עצמו. השתמשתי בצורה בסיסית ביותר בספרייה המובנה בתוך underscore.js (אתם יכולים לזהות ע”פ תחביר ה ERB/JSP), אבל אין שום מניעה לעבוד עם ספרייה אחרת כמו handlebars.js, mustache.js או dust.js.
אתם יכולים לשים לב שב template.people יש קו על התגית . הסיבה: התגית היא deprecated ב HTML5. הדרך ה”נכונה” ע”פ HTML5 לייצר קו תחתון הוא לעטוף ב span עם class שלי ואז להחיל עליו קו-תחתון בעזרת CSS. לצורך דוגמה זו אתעלם מזוטות שכאלה.

עוד נקודה מעניינת היא השימוש ב class (נקודה) ולא id (סולמית) על מנת לזהות את החלק שבו “יוזרקו” חתיכות ה markup של ה Person הבודד. על Id ב HTML להיות ייחודי בכל הדף ואיני יודע בוודאות אם ה PeopleView יוצג יותר מפעם אחת על הדף או לא. סיכוי אחר: אולי מישהו אחר ישתמש בid בשם people-list במקום אחר. על מנת להישאר סטנדרטיים יש להימנע משימוש ב id אלא אם אפשר לוודא שהוא אכן ייחודי – מה שלרוב קשה לדעת. הפתרון: שימוש ב  css class לזיהוי.

בכל מקרה, אחפש את ה css class בצורה יחסית – כך שלא אשפיע על אזורים אחרים ב markup, גם אם הם השתמשו באותו css class בדיוק.

גישה פופולרית היום היא להקליד את ה templates עצמם בתוך ה HTML עצמו עטופים בתג ועם id ידוע מראש ואז להשתמש ב jQuery על מנת לטעון את ה template בזמן ריצה. ה template כמובן אינו משפיע על ה HTML – הוא רק “יושב שם מבלי להפריע”. מדוע לעשות זאת?

  • כדי ליהנות בעת כתיבת ה template מה HTML Editor עם Syntax Highlighting ובדיקת שגיאות.
  • הצמדות לכלל שאומר: makrup נמצא בקובץ ה HTML – לוגיקה ב javaScript. כל ספריות ה template engine שציינתי למעלה הן “logic-less” ואינן מאפשרות כתיבת javaScript בתוך ה template, אלא רק לוגיקה רק בשפה הפנימית שלהן. היה נכון יותר לקרוא להן “javaScript-less”, בעצם.

מדוע, אם כן, אני מעדיף בכל זאת לשמור את ה templates בתוך ה javaScript code?

  1. אני משתמש בIDE בשם WebStorm שמספק לי את היתרונות של HTML Editor בתוך קובצי הג’אווהסקריפט. החיסרון היחיד: חוסר החופש לייצר שורה חדשה ללא +.
  2. כתיבת ה templates בתוך ה javaScript מאפשרים לי להריץ את בדיקות-היחידה ללא קובצי HTML – מה שמאפשר להם לרוץ הרבה יותר מהר. התוצאה: אני מריץ בדיקות בצורה תכופה הרבה יותר – כי כולן רצות בשתי שניות בתוך ה IDE.

2 – ביצירה של ה PersonView אני מייצר את ה”אוטומט” של ה template. על מנת להשיג יעילות מרבית, ה template engine נוהגים לפרק את ה string של ה template לצורה מהירה יותר לשימוש. לרוב מקובל לקרוא למשתנה שמחזיק את התבנית פשוט “template”, השתמשתי ב myTemplate על מנת לנסות ולהקל על ההבנה במקרה זה.

3 – כאן מבצועת ההפעלה של ה”אוטומט” של ה template engine על נתונים מתאימים, במקרה זה – המודל המדובר. ה”אוטומט” myTemplate הוא בעצם פונקציה שמרנדרת html markup ברגע שמזינים לה נתונים. אנו טוענים את התוצאה לתוך this.el שהוא, כאמור, העטיפה ב DOM ל View שלנו.

בואו נעבור עכשיו ל PeopleView המייצג את התמונה הכוללת:
4 – לאחר שרינדרתי את החלק של People ב HTML, הרי היא ה”מסגרת” (במקרה שלנו – רק כותרת), אני רוצה להזין את הנתונים של המודלים הבודדים. אני קורא ל $.this על מנת לבצע חיפוש בתוך ה markup של this.el בלבד, אחר המקום בו “אזריק” את ה Views של המודלים הבודדים. זוהי גרסה מקוצרת (ומומלצת) לכתיבת “(this.el).find(‘.people-list’)$” (אני מניח שאתם מכירים jQuery).

5 – each של collection מאפשרת לי להריץ פונקציה עבור כל מודל באוסף – משהו כמו foreach.

6 – או יוצרים מופע של PersonView עם המודל ה person הנוכחי. אולי זה מרגיש קצת “כבד” לייצר View כל פעם ולא לייצר אחד ולעשות בו שימוש חוזר – אך זה בסדר.

7 – אנו משתמשים ב view על מנת לרנדר את ה markup ומוסיפים את ה “glueing markup”, שבמקרה זה הוא רק תגית br. אנו רוצים לשמור את ה template של Person “נקייה” כך שנוכל להשתמש בה גם ללא ה PeopleView.

סיכום

בפוסט זה צללנו לדוגמה ריאלית קצת-יותר (מהפוסט הקודם) של קוד ב backbone – על מנת להבין כיצד קוד ב BB “מרגיש”. אני מקווה שהצלחתי להעביר את התחושה, אם כי היא עדיין מינימלית למדי. כפי שראינו, BB לא עושה “קסמים” (כמו Ember או Angular) – אנו עדיין כותבים את כל הקוד, אך BB נותן לנו מסגרת, guidance ו utilities על מנת להגיע לשם.
על הדרך השלמנו את הפער אודות השימוש ב template engine, שהוא היבט מרכזי בספריות “javaScript MVC”, והדגמתי כיצד לבצע בדיקות-יחידה ל View וראינו Views מקוננים. כל זה דחוס בפוסט לא כל-כך ארוך. אני מקווה ששמרתי על איזון נכון של “לא משמעמם” ו “ניתן להבנה”.

הערות יתקבלו בשמחה!

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

הצצה מהירה על Backbone.js (ספריית MVC)

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

האם השפה רלוונטית במיוחד לבעיות חדשות בתעשייה, שלא היו נפוצות בעבר? – גם לא ממש.

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

שייך לסדרה: MVC בצד הלקוח, ובכלל.

סמל, שאם תכתבו ב Backbone.js – תיתקלו בו עוד הרבה…

רקע

לא ניתן להתעלם מתרומתה הרבה של ספריית jQuery ודומותיה[ב] בעיצוב מקומה החדש של שפת ג׳אווהסקריפט. במעגל השני של ההשפעה (לפחות בצד-הלקוח) נמצאות ספריות שעוזרות בכתיבת אפליקציות צד-לקוח גדולות. ספריות אלו נקראות ״MVC Frameworks” או ״ספריות ארכיטקטוניות״. השם MVC עשוי לבלבל את מי שכבר מכיר ועבד עם ספריות MVC צד-שרת כגון Struts או ASP.NET MVC.

בעוד ספריות “MVC קלאסיות” מטפלות באפליקציות רבות דפים והניווט בניהם, ספריות ה “JavaScript MVC” לרוב מטפלות באפליקציות דף-יחיד (כגון GMail) בהן יש מסך עקרי אחד שחלקים בו מתחלפים / משתנים – אך אין ניווט משמעותי. בכלל, עצם הפעולה בצד-הלקוח, ב Ajax, בו אין refresh לדף בעת פעולה – משנה את כללי המשחק: מציב בעיות חדשות ופתרונות אחרים. עוד הבדל בולט הוא שברוב ספריות ה “JavaScript MVC” אין Controller. השם MVC בא לבטא את הרזולוציה ואת הבעיה שהן באות לפתור: ארגון קוד באפליקציית UI גדולה ומורכבת.

קיימות כיום מספר רב של ספריות “JavaScript MVC” וצפוי בהן עוד תהליך של קונסולידציה. שלושת הגדולות הן:

  • Backbone.js כנראה הנפוצה והבוגרת מכולן. מספקת מסגרת כללית בלבד ומשאירה חופש / חללים למפתח להחליט ולמלא בעצמו.
  • Knockout.js ששמה במרכז את ה Data Binding ומאפשרת לכתוב בקלות אפליקציות “מונחות-נתונים” (מערכות מידע וכיוצ”ב) נפוצה במיוחד בעולם ה NET.
  • Ember.js (לשעבר Amber.js), ספרייה מקיפה שכוללת גם Class System[ג] ושואבת רעיונות רבים מ Rails ״כתוב מעט קוד, אך עשה זאת בדרך שלנו” צעירה יחסית – אך זוכה למומנטום משמעותי. נפוצה במיוחד בקרב מתכנתי רובי.

ספריות משמעותיות אחרות הן Spine.js, JavaScriptMVC, Batman.js ו AngularJS (מבית גוגל). האתר המצוין todoMVC מציע השוואה מעמיקה בין האפשרויות בכך שמימש אפליקציית דוגמה בכל אחת מספריות הנ”ל (ועוד כמה ספריות נוספות).

רגע של התפלספות

כפי שציינתי, ספריות “JavaScript MVC” הן לא בדיוק MVC קלאסי. בעצם, גם ל”MVC קלאסי״ יש כמה פרשנויות שונות (לדוגמה, האם ה Controller מתמקד בעיקר בטיפול ב input או אחריות על ניהול הflow והתלויות?[ד]).

המדקדקים מגדירים את Knockout.js כ MVVM) Model, View, View-Model) – תבנית עיצוב שמייקרוסופט מקדמת בעולם הNET. זה דיי נכון.
את Backbone.js ו Ember.js נוהגים להגדיר כ Model, View, Presenter) MVP). האמת, ספריות כמו ASP.NET או GWT מתאימות יותר להגדרה זו. הגדרה כגון Model, View-Controller, Router (בקיצור MVCR) תהיה יותר מדויקת.

ההגדרה המועדפת עלי כרגע היא !Model, View, Whatever (בקיצור MVW או *MV).
התחלתי את הפוסט הזה בניסיון לעקוב אחר ההיסטוריה של תבנית העיצוב MVC, הוריאציות והשינויים שהיא עברה במשך השנים, בעיקר MVP ו MVVM, והניסיון להסביר כיצד ספריות ה “JavaScript MVC” מתאימות לתבניות אלו.

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

בסופו של דבר – MVC הוא ניסיון לארגן אפליקציית UI מורכבת בצורה שתהיה קלה לתחזוקה ושינויים. כל דור של UI (Web, Fat Client, Fully Client Side, Command Line) – והאתגרים שלו.
כפי שמרטין פאולר ציין פעם: “אנשים נוטים להסתבך עם MVC. החלק הכי חשוב הוא לבצע הפרדה אמיתית בין Business Logic ל UI. כל השאר – משני”. אני מסכים ב 100%.

לכל ספרייה יש את הדרך שלה לארגן את הקוד – ואולי יותר מעשי ומעניין פשוט להתבונן בישומים קונקרטיים.
בפוסט זה אתן הצצה בסיסית ביותר ל MVW בג׳אווהסקריפט בדמות Backbone.js – הספרייה הנפוצה והמינימליסטית שיכולה להיות בסיס לימודי מצוין להבנת MVC בג׳אווהסקריפט.

אז מה יש ב Backbone.js?

אקצר מעתה ואקרא ל Backbone.js פשוט BB.
  • BB היא קטנה למדי. 700 שורות קוד בערך. 1400 שורות עם הערות.
  • BB משתמשת ב underscore.js (ספרייה טובה ל javaScript Utils מאותו היוצר) ו jQuery. אם אתם עובדים עם BB – יהיה לכם מאוד נוח להשתמש גם כן בספריות אלו, וקצת פחות נוח (אך אפשרי לחלוטין) להשתמש בספריות אחרות. BB מעודדת שימוש בספריית Templating – ואתם יכולים לבחור את זו של underscore (תחביר JSP-like, שלי אישית, עושה צמרמורת) או כל אחת אחרת.
  • ל BB יש תיעוד טוב (reference) ו Tutorials סבירים. יש קהילה גדולה ופעילה.
  • בגלל ש BB פשוטה – מייחסים אותה כמתאימה למערכות פשוטות יחסית – אך בפועל יש גם מערכות גדולות מאוד ומורכבות שנכתבו בעזרתה.
  • מאוד קל לעבוד עם BB מול שרת שמספק REST APIs – במיוחד אם תבנית-הנתונים היא JSON.
  • ל BB יש ארכיטקטורת Plug-Ins וניתן למצוא Plug-Ins רבים שמרחיבים את יכולות-הבסיס שלה.
  • BB מספקת מסגרת לא-מחייבת. אם אתם רוצים לפעול קצת אחרת, יש לכם את החופש לעשות זאת. כאשר מדובר במבנה של האפליקציה שלי – אני אוהב את זה.
  • כמו ספריות “JS MVC” אחרות, BB מספקת:
    1. מערכת-מחלקות (Class System) עבור Model ו Views (וגם Routers ו Collections – שהם רכיבים מרכזיים אחרים בBB)
    2. ניהול של המודלים (ה instances), כולל הקשרים בניהם.
    3. כלים לאימות ערכים (Validation Logic) במודל.

הנה דוגמה למודל מינימלי שניתן לייצר ב BB:

הערה: משפטי ה expect…toBe הן בדיקות-יחידה המציגות את התנהגות הקוד. כל הבדיקות עוברות בהצלחה.

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

ב1 – אנו יוצרים מודל של אדם בשם אוזי כהן.
ב2 – בכדי להדגיש את השוני בינו ובין אמן אחר בשם ״ליאונרד״ ובעל שם משפחה זהה, אוזי משנה את שם המשפחה שלו.
ב3 – אנו מקבלים את המודל המלא בפורמט JSON.

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

השתמשתי במודל הכי פשוט שאפשר – כי ברצוני להתמקד ב View.

PersonView היא המחלקה שאחראית לצייר מודל של Person. יכולים להיות, כמובן, כמה Views שונים לאותו המודל. את ה markup שה View יוצר, ארצה לשלב היכנשהו ב DOM. בדוגמה זו – זה יהיה container$, שמשתמש ב span בכדי לא לבלבל עם ה div ש Backbone יוצר באופן אוטומטי לכל מופע של המודל.

el הוא בעצם אלמנט ה DOM שיצר לי BB כחלק מה View. הוא עושה זאת על מנת לאפשר ל markup בפנים להשתנות, בלי שאצטרך לחבר את ה markup שוב ל container. הבחירה ב div היא כמובן רק default, ואם אני זקוק ל list element (תג

  • ) – אפשר לקבוע זאת.ב1- אני בודק מה יש בתוך ה container – ניתן לראות את ה markup שנוצר בתוך הפונקציה render. זו דוגמה דיי מכוערת – לרוב נשתמש בספריית templating על מנת שהקוד שיוצר את ה html snippet יהיה אלגנטי. לא רציתי להעמיס על דוגמה זו ולכן הקוד ה”פרימיטיבי”.

    ב2- אנחנו בוחנים את ה markup כולל ה container. רק לוודא שהתמונה הכללית ברורה.

    ב3- אנחנו מבצעים שינוי למודל ורואים שה markup ב container השתנה באופן פלאי. “פלאי” – כמובן שלא. אנחנו כותבים את הקוד שעושה זאת – backbone רק מכווין אותנו למבנה מסוים ועוזר לנו.

    בואו נבחן את הפונקציה initialize שהיא לצורך העניין הבנאי (constructor) של מחלקת ה PersonView שלנו, וכוללת 2 משפטים מוזרים:
    ב5- אנחנו מבצעים פעולת JavaScripts’s bind לכל המתודות במחלקה שאנו הולכים ל”ייצא” כ callbacks לאובייקטים אחרים. במקרה זה – יש רק את ״render״, אך יכולתי באותה מידה לשרשר גם שמות של מתודות נוספות. למה צריך לעשות JavaScript bind? – כדי ש this ימשיך להצביע לאובייקט שלנו. מבולבלים? קראו את הפוסט להבין את JavaScript this.
    הסימן “_” (קו תחתון) הוא הקיצור לגשת לספרייה underscore.js, ממש כמו שניגשים עם $ ל jQuery. אלו המקומות ש underscore מסייעת מאוד לכתוב קוד ב BB. אתם לא חייבים – אבל כדאי.

    ב6- אנחנו “מחייטים” את ה View שלנו לבצע פעולת render כל פעם שהמודל משתנה (change’ event’). מאוד דומה לאירועים ב jQuery.
    הבהרה קלה: אם אתם מכירים את תבנית העיצוב MVC אתם יכולים להבחין שה View ב Backbone מבצע פעולות (“חיוט”) של Controller. זה נכון: אפשר לומר שה View ב BB הוא בעצם View-Controller: הוא עושה הרבה פעולות שבמקור יוחסו ל Controller.
    אם אתם מכירים את תבנית העיצוב MVP נראה שה View הוא בעצם יותר Presenter. הוא אחראי ל Presentation Logic. זה נכון: בעצם מה שנקרא “View” ב BB הוא דומה ל MVP’s Presenter בעוד ספריית ה Templating (בעצם ה Template עצמו) – דומה מאוד ל MVP’s View.

    סיכום

    הצצנו ל Backbone וטעמנו כיצד נראה קוד שמשתמש ב Backbone.js. טעימה קטנה.
    דיברנו גם על החשיבות של ספריות “JavaScript MVC” – כאשר קוד הג’אווסקריפט שלכם מתחיל לגדול ולהסתבך. וגם על החשיבות לא לחפור בתבנית-העיצוב MVC וההיסטוריה שלה יותר מדי 🙂

    ייתכן ואמשיך לכתוב קצת על Backbone על מנת להתעמק בו קצת יותר, בניסיון לבחון JavaScript MVC “מהשטח”.

    בהצלחה!

    ——

    [א] נקראת Harmony, ג׳אווהסקריפט 2.0 או ECMAScript 6.0. כוללות, ככל הנראה, מחלקות, מודולים (חבילות של מחלקות עם ניהול תלויות), תיקונים לכמה כשלים של שפת ג׳אווהסקריפט ועוד. ממש מהפיכה!

    [ב] Prototype ו MooTools היו גם הן מועמדות ראויות, אך קהל המפתחים בחר לבסוף בjQuery. ניתן לקרוא על העיקרון מאחורי jQuery בפוסט מבוא מואץ ל jQuery.

    [ג] כלים / Framework להגדרת מחלקות וכל מה שקשור בהן. בג’אווהסקריפט, כפי מתואר בפוסט מחלקות בג’אווהסקריפט. בשפת ג’אווהסקריפט לא קיימות מחלקות – ועל המתכנת לייצר אותן לבד. בעוד ספריות “JavaScript MVC” רבות מספקות סביבה אחידה / מוגנת ליצירת מחלקות עבור האלמנטים הבסיסיים בספריה (כמו Model או View).- ספריית Ember מספקת כלים שתוכלו להשתמש בהם עבור כל המחלקות בפרויקט שלכם.

    [ד] המקור של MVC הוא בשפת Smalltalk בשנות ה-70. כשהגיעו ה Fat Clients (ב ++C), ולאחר מכן הווב – נוצרו פרשנויות ווריאציות שונות ל MVC על מנת להתמודד עם האתגרים החדשים שהציבו טכנולוגיות אלו.