2014-12-29

ריילס, רובי on ריילס

ריילס, או בשמה המלא Ruby On Rails (קיצור מקובל: ROR) היא מסגרת פיתוח (Framework) פופולרית לבניית אפליקציות ווב.
ספציפית: אפליקציות עם ממשק וובי מצד אחד, ובסיס נתונים (בד"כ רלציוני, אבל לא רק) - בצד השני. 

מדוע ריילס?
ריילס הגיעה כתגובה ל JEE (בימיו הפחות יפים - תחילת דרכו) וכאלטרנטיבה פשוטה ומהירה לכתיבת אפליקציות ווב. באותם הימים, מרכז הכובד של JEE היה ה Enterprise JavaBeans (בקיצור EJB) שהיו כבדים ומסובכים. למשל, ה Guideline היה לכתוב לכל רכיב שמייצג נתונים 4 Interfaces נפרדים (רגיל, Home, Remote, ו LocalHome - אם אני זוכר נכון). ל EJB היו ה-מ-ו-ן קובצי קונפיגורציה XML לא-ידידותיים, ולמרות הכל - זה היה טרנד חם ורבים עברו לעבוד בו.

JEE הביא יתרונות רבים (סביבת multi-platform סטנדרטית, המתאימה ל Enterprise), אך במחיר גבוה. הוא כנראה היה טוב יותר מ Microsoft DNA או CORBA (כנראה...), אבל היו אנשים שחשבו שאפשר להשיג את הערך בעלות נמוכה יותר.
אחד מהם הוא Rod Johnson שיצר את Spring Framework, ה Framework שהפך הכל להרבה יותר פשוט (בעיקר הציג אלטרנטיבה פשוטה ל EJBs) - ומה שאח"כ הפך להיות הסטנדרט של JEE, בצורת EJB גרסה 3.0 (שהעתיקה הכל, כמעט, מ Spring + Hibernate).
חלוץ אחר הוא David Heinemeier Hansson (ידוע גם בקיצור DHH), בחור דני צעיר יחסית (יליד 79) שעבד בחברה בשם 37singals (היום נקראת basecamp) שפיתחה לעצמה Framework יעיל מאוד לפיתוח מערכות ווב בשפת רובי. ה Framework הזה יצא כ Open Source ונקרא Ruby on Rails. נראה שריילס, אגב, השפיעה באזורים מסוימים גם על Spring בגרסאותיה המאוחרות (אני לא מדבר רק על Spring Boot) - ומשם היא השפיעה גם על JEE. בכלל, ריילס הוא Framework רק השפעה, שניתן למצוא השפעות שלו במקומות רבים בעולם התוכנה.

מקור השם Rails הוא כזה: "במקום להתקדם באיטיות, כל אחד במסלול שלו, הצטרפו אלי: אני קובע את הדרך - אבל תוכלו לנוע במהירות". ריילס הוא יישום של אוסף של best practices (ש DHH האמין שהן מוצלחות, לא אוסף גנרי) - שמתאימים זה לזה, ומסביבם נכתב Framework שהופך את השימוש בהם למאוד קל ומאוד מהיר. ריילס הוא לא סיפור על פלורליזם - זהו סיפור על דעה מוצקה כיצד נכון לפתח אפליקציות ווב. אם אתם רוצים להיות יעילים בריילס, עליכם לקבל עליכם את "The Rails Way", או לפחות את רובה. אם תקבלו - תגלו את אחד ה Framework הפרודקטייבים הקיימים לפיתוח אפליקציות ווב. ריילס פרחה ביוחד בסביבות של סאטראט-אפים, שהדבר שהכי חשוב להם הוא לספק Value מהיר לשוק שאותו הם עוד לומדים.

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







התכונות העיקריות של ריילס


ההחלטה התכנונית המרכזית של ריילס, אם כן, היא "פריון (productivity) על פני גמישות".
שני עקרונות מרכזיים שנוהגים להזכיר שוב ושוב, בהקשר של ריילס, הם:
  • Convention over Configuration - במקום לומר היכן נמצא משהו (קובץ, משתנה, וכו') ומה שמו - בואו נגדיר כלל מוסכם (convention) היכן הוא אמור להימצא / איך הוא ייקרא - ונחסוך לנו את כל התקשורת הזו. הרעיון של CoC הוא לא חדש, ניתן למצוא אותו במייבן, למשל, שקצת קדמה לריילס. בכל זאת, ריילס היא זו שעשתה PR משמעותי מאוד לעקרון התכנוני הזה (ובמיוחד כ contra ל JEE) - והשפיעה בכך רבות על התעשייה.
  • Don't Repeat Yourself (בקיצור DRY) - גם זה רעיון שכבר מקובל עשרות שנים, אבל ריילס חרטה אותו על דגלה. לא לכתוב בקוד שום דבר פעמיים.

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

ריילס צמחה על גבי שפת רובי, קצת רחוק מהקהילה הטבעית של ג'אווה (ה Enterprises), ולכן ההשפעה שלה הייתה קצת יותר רחוקה. אל דאגה! JEE ננגחה שוב ושוב על היתירות של הקוד שהיא יצרה (בתרגיל הנדסי כ"כ מרשים): גם ע"י NET. (מי שזוכר את קרבות ה PetShop) וגם ע"י Spring - בניצוחו של רוד ג'ונסון (Rod Johnson), שגילה מעט מאוד עדינות כלפי החבר'ה של JEE. היום מצבה של JEE טוב בהרבה מאשר היה באותם הימים, אבל עדיין - פיתוח בריילס נחשב מהיר בהרבה.


עוד אלמנטים מרכזיים בריילס שכדאי לציין הם:


הרחבה לשפת רובי:

רובי, כתכונה של השפה מאפשרת (ומעודדת) שימוש ב metaprogramming בכדי להרחיב את השפה עצמה וליצור DSLs חדשים. יכולות אלו, הן אולי הסיבה המרכזית שריילס הצליחה להיות יותר אפקטיבית [א] מספריות ווב אחריות (ASP.NET MVC, Lavarel או !Play) - שהיו משוחררות גם הן מ"כבלי ארכיטקטורת ה Enterprise של JEE". פקודות שימושיות בכתיבה של אפליקציות ריילס (למשל הגדרות שונות על המודל) הן בעצם הרחבות של ריילס לשפת רובי. מתכנת ריילס ללא רקע משמעותי ברובי עשוי לא להיות מסוגל להבחין אלו תכונות בהן הוא משתמש שייכות לשפת רובי - ואלו שייכות לריילס (ואולי גם לא ממש אכפת לו).


אינטגרציה:

ריילס כוללת stack של טכנולוגיות שמחוברות טוב מאוד זו לזו, ומספקות חווית פיתוח אחידה end-to-end. החל מבסיס הנתונים (Active Records - כלי ה ORM של ריילס), ועד צד הלקוח (SASS, Haml, ו CoffeeScript [ה]) - הכל מרגיש מתאים, ודומה למדי. החוויה דומה, אולי, לזו של פיתוח בפלטפורמת NET. של מייקרוסופט - לה שליטה רחבה על כל ה Stack הטכנולוגי.

עד גרסה 2, ריילס הייתה gem [ב] אחד, שלא גמיש להחלפות. החל מגרסה 2 חלק מהרכיבים (Active Records, למשל) הופיעו כרכיבים הניתנים להחלפה, אם כי ההחלפה בפועל הייתה מאתגרת למדי. ובמשך הזמן ממש התפתחו plug-in APIs המאפשרים לעשות החלפות אלו בצורה פשוטה יותר ויותר.
שלא תבינו לא נכון: אם אתם הולכים לכתוב אפליקציה ראשונה בריילס, ורוצים כבר בשלב זה להחליף רכיבים כראות עיניכם - זה לא ממש כדאי. החלפת רכיבים היא עדיין פרקטיקה מתקדמת שמומלצת רק למי שמבין היטב את דרכי העבודה של ריילס. באפליקציות הראשונות - כדאי להיצמד לסטדרטי ולמקובל.

הגישה שרואה בריילס "אוסף של רכיבים" (מה שטכנית באמת נכון) - מהם ניתן להרכיב תצורה מותאמת-אישית, נקראת (גם) Hexagonal Rails (ע"ש Hexagonal Architecture, שדוגלת בהפרדת ה domain model משאר הרכיבים, ורואה בהם סוג של plugins שמתחברים מסביב אליו) - והיא פחות נפוצה, ואולי אף שנויה במחלוקת: האם ההשקעה, הלא פשוטה, "לאלף את ריילס" מתירה בסופו של דבר תוצר שמצדיק את ההשקעה הזו?





בדיקתיות:

תכונה אחרונה של ריילס שארצה לציין היא "בדיקתיות". יוצרי ריילס (ממש כמו יוצרי AngularJS, למשל) היו מודעים היטב לצורך בבדיקות - והם בנו תשתית שמאפשרת לבדוק את הקוד שרץ עליה בקלות יחסית. בדיקות יחידה ואינטגרציה הן חלק מובנה מריילס, ו flows הבדיקה מאופשרים היטב בכל הרמות , אם כי קצת יותר לכיוון ה integration tests וקצת פחות לכיוון ה isolated unit tests. כמות ספריות הבדיקה הזמינה לשפת רובי היא מרשימה (RSpec, MiniTest, Test::Unit, Cucumber, Factory_girl), ולכמה מהספריות הללו יש הרחבות מיוחדות לריילס (למשל Rspec_rails או Factory_girl_rails). בדיקות הוא לא רעיון זר בקהילת הרובי או ה RoR...

מעניין לציין שדווקא DHH הוא זה בשנה האחרונה העלה כמה דברי ביקורת על כתיבת בדיקות. בגלל ש DHH קידם מאוד את תרבות כתיבת הבדיקות (וגם בגלל שהוא הגורו הבלתי-מערוער בעולם של ריילס?) - דבריו זכו לתהודה רבה. הוא כתיב פוסט בשם Test-induced design damage, ואח"כ העביר סשן בשם "?Is TDD Dead". בסוף הפוסט תוכלו למצוא לינק לסדרת הסשנים המעניינת בה הפגישו אותו עם יוצר ה TDD (קנט בק) ומרטין פאוולר (ששימש כמגשר?). סדרה של 3 שעות - אך בהחלט מעניינת.

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



ריילס בחזית הטכנולוגיה

בעולם של Single Page Applications, בעולם בו חווית משתמש שהפכה מקובלת, שדורשת שקוד משמעותי ירוץ בדפדפן, ובעולם של noSQL - ריילס כבר זוהרת פחות. אפשר לעשות את כל הדברים האלו עם ריילס, אבל היא כבר לא יעילה כמו שהייתה בעבר, ומפתחי ריילס צריכים לפעמים להיות יבשושים ולכתוב קוד משעמם / קצת פחות יעיל.

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

אכן נראה שחלק ממפתחי הריילס (כלומר: רובי + ריילס) עוזבים את ריילס ומחפשים Frameworks חדשים לעבוד איתם. הטיעון ששמעתי כבר כמה פעמים הוא "אני לא רואה הגיון לעשות MVC גם בשרת וגם בצד הלקוח" (ברור שלא! מוזר לשמוע בכלל ניסו כזה דבר). באופן טבעי, חלקם מחפשים את המוכר, ולא מפתיע למוצא frameworks שמנסים לספק את הצורך הזה. קשה לי שלא לציין את Sails - של node.js ו grails של שפת גרובי (groovy). האחרון הוא לא חדש - אבל קשה להתעלם מהצליל המוכר שהוא בחר לעצמו :)



הרכיבים העיקריים בריילס


ריילס בבסיסה היא ספריית MVC שמושפעת ישירות מה MVC (המקורי) של שפת smalltalk:

המודל - שומר את ה state של המערכת (בעזרת בסיס הנתונים, אם כי לפעמים רק בזכרון), אוכף "חוקים עסקיים" על נכונות ה data (למשל: סטודנט חייב להיות רשום לתוכנית לימודים כלשהי). הוא לא בהכרח המאמת היחידי של הנתונים, אלא ה gatekeeper לפני שהמידע נשמר / משותף עם חלקים אחרים במערכת. בניגוד ל MVC של Smalltalk הוא גם כולל חלק מהלוגיקה - ראו בהמשך את ההסבר על Active Records.
המודל, בגדול - הוא זמין לכלל האפליקציה, אין בו partitioning (או bounded context).

ה View - הוא הקוד שמייצר דפי HTML למשתמש, על בסיס מידע במודל. ריילס היא תשתית לכתיבת MVC בצד-השרת (כלומר: השרת מייצר HTML, ומוסיף JavaScript לאינטרקטיביות). בדומה למודל ה MVC הקלאסי ה View לא מקבל input מהמשתמש, ולא מנהל איתו שום סוג של אינטרקציה (לפחות לא בצד-השרת).

ה controller - אחראי לקבלת קלט מהמשתמש, טיפול בו, ותפעול (ניתן לומר: orchestration) של המערכת עד שהמשתמש מקבל בחזרה את התשובה שלו. דרך העבודה שלו היא לעדכן את המודל, ואז להזניק את ה View המתאים (הוא לא מעביר מידע ל view ישירות).

בריילס יש גם routers - שהם ממפים URLs, ומצבים - ל Views. לדוגמה: אם משתמש שהוא admin ניגש לדף מסוים - הוא יקבל View אחר ממשתמש רגיל. ה router עושה מה שבמערכות אחרות עושה סוג של "super controller". הוא דקלרטיבי, בעזרת סט של ״פקודות״ מיוחדות לעניין (מה שהופך אותו לפשוט יותר לכתיבה ותחזוקה) - וסה"כ הוא מהווה הרחבה מבורכת על מודל ה MVC ה"קלאסי".



רכיבים עיקריים של ריילס הם:

Active Records (בקיצור: AR)

כלי ה lightweight ORM של רובי, המנהל בפועל את הגישה לבסיס הנתונים של המודל. רובי מספקת גם כלים להגדרת טבלאות ברובי דקלרטיבי (ולא SQL, על הווריאנטים תלויי בסיס הנתונים הספציפי שלו) וכלים מובנים לביצוע migrations בין גרסאות שונות לסכמת בסיס הנתונים (מה שמקובל בג׳אווה לעשות עם flyway).

השם "Active Records" הוא בעצם של שם של דפוס-עיצוב (מופיע בספר PoEAA) אותו המודול מממש.

דפוס העיצוב "Active Record" מגדיר מחלקה בשפה (במקרה שלנו: רובי) שמתארת נתונים של שורה (להלן Record) בבסיס הנתונים, אבל מוסיפה עליהם גם את התנהגות ה domain הרלוונטית לאותם נתונים (להלן Active). למשל: validation, חישובים, derived fields, וכו'. הבהרה: יש מחלקה אחת לכל טבלה, ומייצרים מופעים שלה ע"פ הרשומות להם נזקקים באותו הרגע.

דפוס עיצוב זה מרשה לערבב בין מיפוי הנתונים בין בסיס הנתונים לזיכרון, עם לוגיקה עסקית - כל עוד הלוגיקה העסקית היא רק ברמה של הרשומה הבודדת (ולא "שייכת" ל scope רחב יותר). ערבוב זה, נמצא בוויכוח תמידי על הלגיטימיות שלו, מכיוון שהוא סותר כלל מקובל בארכיטקטורה הנפוצה ביותר למערכות מבוססות-נתונים (הרי היא Layered Architecture) - הפרדה בין Persistence ל Business Logic, או בצורת דפוס העיצוב "Data Mapper" אותה מממשים רוב כלי ה ORM המוכרים - הפרדה מוחלטת בין לוגיקה עסקית למיפוי הנתונים בין בסיס הנתונים לזיכרון [ו].

בריילס, יידרש מאמץ מיוחד בכדי לא-לעבוד עם Active Records, אז כדאי שתתנו לדפוס זה הזדמנות - גם אם כל חייכם "גדלתם" על Data Mappers ;-).

Active Records מאפשר לנו לכתוב אובייקט "פשוט" ברובי, לרשת מ ActiveRecord::Base ולקבל את פעולות ה CRUD הבסיסיות ע"י סיפוק הגדרות בסיסיות של מה שאנו רוצים (declarative programming).
לא! זה לא "בחינם", אין ארוחות-חינם בהנדסת תוכנה. אנו מוותרים על גמישות וקצת על ביצועים - בכדי לקבל את הנוחות הזו.

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

את שאר הרכיבים אזכיר בקצרה, לא כי הם פחות חשובים, אלא בגלל שנדרש ידע נוסף בריילס על מנת להבין אותם.
  • Action Pack - זהו הרכיב שמתפעל את ה MVC בריילס. כל פעולת משתמש בריילס נקראת "Action". הוא מורכב מ -3 תתי-מודולים:
    • Action Dispatch - אחראי ל routing.
    • Action Controller - מספק את מחלקת ה ActionController::Base ממנה יורשים כל ה controllers במערכת. 
    • Action View - אחראי לרינדור ה Views, בעזרת מנגנון ה ERB (קיצור של Embedded Ruby) - מנגנון שדומה מאוד ל JSP בג'אווה או ל PHP: סוג של template (בד"כ HTML, יכול להיות אחר) שבו מושתל קוד רובי המתאר את ההתנהגות הדינאמית.
  • Active Model - המשמש כ Facade של AR מול ה Action Pack.
  • Active Resource - המספק יכולות צריכה של שירותי REST חיצוניים. סוג של שירות אינטגרציה בין מערכות.
  • Active support - סט של utilities כלליים (שימושיים) שמגיע עם ריילס. המקבילה של Apache Commons - של מג'אווה.
  • Action Mailer - אשר תופס בתיעוד, משום מה, נתח מכובד. הוא בסה״כ שולח מיילים.
  • Active Job - לניהול Queues של jobs. הוא בעצם שכבת הפשטה למימושים קיימים (כגון Resque) ולא מימוש בפני עצמו. הוא חדש בריילס 4.2 .
  • Railties ("קשרי מסילה") - זהו ה gluing logic של כל רכיבי ה Active / Action למיניהם. ה Strategy של תפעול אפליקציות הריילס.
  • Rails - רכיב קטן למדי, שאחראי על אתחול המערכת - והכנסת המודולים האחרים לפעולה.

כל עבודת ה low-level ברמת ה HTTP הוא לא חלק מריילס. חלק זה יטופל ברמת ה Application Server - עליו נדבר בהמשך.


מבנה אפליקציית ריילס


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

$ rails new <app name> [optional: -d < sqlite3 | mysql | postgresql >]

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

מבנה אפליקציית ריילס חדשה

התיקיות המעניינות ביותר באפליקציית הריילס הן תיקיות ה app, config, ו lib. אם יש בדיקות טובות - הוסיפו לכך (במקום גבוה) את תיקיית ה tests (לפעמים תראו אותה בשם spec).

תיקיית ה bin כוללת את הסקריפטים לפעולות הבסיסיות של האפליקציה. אלו בעצם wrapper scripts (נקראים ברובי גם binstubs) שרק מכינים את סביבת הריצה ואז קוראים ל executable הנכון. לפני ריילס גרסה 4 קראו לתיקיה זו בשם "scripts".

קובץ ה Gemfile (מתחיל באות גדולה) הוא קובץ של כלי רובי בשם bundler, כלי שעוזר להגדיר, ואז להתקין - תלויות (gems [ב]) על סביבות חדשות בהן תרוץ האפליקציה.
ברגע שמריצים את הפקודה "bundle install", אז bundler יקרא את קובץ ה Gemfile, יבדוק מהן הספריות הנדרשות וגרסאותיהן, ויתקין את מה שלא נמצא - בגרסאות המתאימות. אם אתם מכירים את קובץ ה package.json של node.js - זה ממש אותו הדבר.

קובץ ה Gemfile שנוצר בעקבות הפקודה "rails new" כולל כבר רשימה של ספריות שימושיות: דרייבר לבסיס הנתונים שהגדרתם, כמה ספריות צד-לקוח, ספרייה ל generation של תיעוד, ספריה לעבודה עם JSON, וכו'.

Gemfile.lock הוא קובץ בו bundler מנהל לעצמו את הגרסאות שמותקנות בפועל. זהו קובץ שתרצו להכניס ל git repository שלכם - אך לא לשנות ידנית (אין קשר לקבצי lock של MS Office, שמטפלים ב concurrency).


קובץ ה rakefile הוא של כלי ה build של רובי שנקרא rake. ה build ברובי כולל בעיקר בדיקות, פענוח הסכמה, Linting, וטיפול בקצבי HTML ו CSS (למשל: minification).

קובץ ה rakefile של ריילס יהיה לרוב מינימלי, והדבר המרכזי שהוא יעשה הוא לטעון ולהריץ רשימה של rake tasks (שאתם תכתבו). קבצי ה task יושבים בתיקיה lib/tasks.

בריילס, עובדים לא מעט עם command line עבור scaffolding [ג]: ניהול בסיס הנתונים, ביצוע buid, הרצת האפליקציה, ועוד.

לפעמים הפקודות הללו לא עובדות כראוי, ו"טריק" מקובל הוא לקרוא ל  <bundle exec rake <rake params - מה שהופך את כל ה gems שמצוינים ב Gemfile לזמינים, אפילו אם הם לא ב path של מערכת ההפעלה.


התיקייה lib, ע"פ הגדרה אחת, כוללת קוד שהוא לא מודל, controller, router, או View.
התיקייה lib, ע"פ הגדרה נוספת, כוללת קוד שניתן לעשות שימוש חוזר בו בין הרכיבים השונים (view, model, controller).
מלבד כמה תתי ספריות נדרשות (למשל tasks) - יש לכם חופש כיצד לארגן אותה.

בגרסאות ישנות של ריילס, כל הקבצים שישבו ב lib נטענו כזמינים לכל הרכיבים במערכת. כלל זה שונה והיום עליכם להדיר במפורש באיזה lib רכיב ה app שלכם רצה להשתמש - בכדי להשתמש בו. ( או פשוט להוסיף ל config/application.rb את הפקודה config.autoload_paths += %W(#{Rails.root}/lib שתעשה מה שריילס עשתה בגרסאות ישנות).

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


שני קבצים חשובים שנטענים בעליה של ריילס הם config/environement.rb ו config/application.rb.
בנוסף תמצאו בתיקיה config/environemnts קובץ קונפיגורציה לכל סוג סביבה: development, production ו test - זה הבסיס למערכת ה staging של ריילס.
כשמפעילים את אפליקציית הריילס, ניתן לציין את הסביבה כפרמטר, למשל:

$ rails server - e development

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

זהו.

ייתכן ותתקלו בקבצים ריקים בשם ״keep.״. מטרתם היא למנוע מכלים מסוימים להתעלם מהתיקיות שנוצרו ע"י "rails new" - וניתן (ומומלץ) למחוק אותם כאשר התיקיה מתמלאה בתוכן. חבל לראות פרויקט ריילס בן כמה שנים - שעדיין שמר את הקבצים הללו.



החידושים שהגיעו עם ריילס 4, ששוחררה באמצע 2013. גרסה מג'ורית של ריילס משוחררת אחת לשלוש שנים, בערך. מקור.



ה Application Server


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

ריילס מגיע כברירת מחדל עם שרת "רזה" בשם WEBrick. זהו שרת פשוט למדי - שמשמש בעיקר לצורכי פיתוח (ולא ל production). ב Production מקובל להשתמש ב Puma, Raptor או ב Unicorn.

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

סה"כ ה API ש Rack מציע הוא מאוד בסיסי: הוא עובד ברמת הפשטה מאוד נמוכה - ה HTTP Request-Response Lifecycle (בדומה ל CGI - אם אתם ותיקים מספיק בכדי לדעת מה זה).

מצד מימושי השרת, המימושים הנפוצים ביותר הם Rack (כמובן), Unicorn, או Mongrel.
ספסיפקציית ה Rack משתמש לא רק את RoR, אלא גם Frameworks אחרים כגון Sinatra, Ramaze ו Merb (שמוזג לתוך RoR בגרסה 3.0).

כמה מלים על Rack כ reference implementation:
מקור השם Rack הוא הכוננית בחדר השרתים שעליה מתקינים את השרתים / ציוד הרשת. יוצריו בחרו בשם זה בגלל מנגנון ה plugins שלו, שמאפשר למודולים צד שלישי (הנקראים middleware, דומים ל Servlet Filters בג'אווה) להרחיב אותו בקלות. הנה רשימה של מודולים זמינים.
מעניין להזכיר את Rack::MockRequest שמייצר mocks לאובייקטי request ו response (נחמד שזה מגיע מ"הספק"), ו Rack::Lint שעושה Linting על קוד המשתמש ב API של Rack ומוצא כמה common pitfalls.

קובץ הקונפיגורציה של Rack, הנקרא config.ru מכיל את ההגדרה של ה middlewares שאנו משתמשים בהם, ו metals.
Rails Metal Apps (בקיצור: metal, מלשון "bare-metal" - אני מניח) הן חתיכות קוד באפליקציית הריילס שלנו, שירוצו ישירות מעל ה API של Rack, ללא תוספות.

מדוע לעשות זאת? בגלל ביצועים, למשל: כדי לספק REST API שקוראים לו בקצב מהיר.

ה stack של ריילס שמריץ את ה controllers (ה Action Controller Stack) מציב תקורה משמעותית לכל request שמטופל. אם אנו רוצים לספק תשובה פשוטה, ולעשות זאת מהר - כדאי לעקוף אותו.

הערה: ברור שאם אנו זקוקים לביצועים ממש גבוהים - גם metal עדיין מציב מגבלה על מה שאפשר להשיג מהחומרה. שפת רובי היא לא concurrent (השתפרה, אבל עדיין לא ממש) ואין לה parallelism. כדי להגיע ל throughput או tps גבוה במיוחד - כדאי לשקול עבודה נקודתית עם node.js (עבור קוד "רעב" ל I/O) או עבודה ב Go (עבור קוד "רעב" ל CPU) [ד].

אחרונה חביבה, היא ספרייה בשם spring שעובדת עם rake (שהיא כבר חלק מובנה מריילס 4.1 ומעלה) שעושה preloading לשינויים באפליקציית הריילס מבלי לעשות restart לשרת (אלא על בסיס של fork של ה process - לא עובד ב Windows או ב JRuby). יכולת דומה קיימת באופן מובנה בשרת ה Unicorn.







ה Conventions של ריילס


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

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

שמות של טבלאות בבסיס הנתונים יהיו ב snake_case - כמו משתנים. טבלאות תמיד יקראו ע"פ צורת הרבים של האובייקט (plural): למשל People או Invoices ולא Person או Invoice.
למה? כדי שהקוד יהיה קרוב יותר לשפה הטבעית: "Select a Product from products". אני מניח שהבדל זה יכול גם להקל להבחין מהר בין מחלקה לטבלה בבסיס הנתונים.

שמות של קבצים (model, view, controller, וכו') יהיו גם הם ב snake_case - כפי שמקובל ברובי גם מחוץ לריילס.

נניח שאנו רוצים ליצור מודל בשם LineItem (שם מחלקה ברובי הוא CamelCase). כדי שהכל יעבוד, ללא קונפיגורציה נוספת, על שם הקובץ המכיל את המחלקה להיות line_item.rb (והיא תהיה בתיקייה app/models), ועל שם הטבלה בבסיס הנתונים להיות line_items.

"אני מבין איך עושים זאת עבור line_items, אבל איך *לעזאזל* ריילס תקשר עבורי בין people ל person?". שאלה טובה. הציצו ב utility של ActiveSupport שעושה זאת: inflections.rb. הוא מכיר יוצאי-דופן מוכרים כמו person-people או octopus-octupi, ואתם גם יכולים ללמד אותו כללים חדשים, למשל: selfie-selfieez.

ל controllers יש כללים נוספים:

אם יש לנו Controller ששם המחלקה שלו הוא InvoiceController, אז עליו להיות בקובץ בשם invoice_controller.rb שנמצא בתיקייה app/controllers. עד כאן - זה כמו המודלים.

בנוסף, ריילס תצפה שיהיה קובץ נוסף בשם invoice_helper.rb בתיקייה app/helpers שיכיל מחלקה בשם InvoiceHelper.

ריילס גם תצפה שה view templates של ה controller הזה יהיו בתיקיה בשם apps/views/invoice. כהתנהגות ברירת מחדל, ריילס תשתמש ב output של ה templates הללו ותכיל אותם בתוך layout template (לא דיברנו עדיין ממש על הפרטים של ה view...) בשם invoice.html.erb (או invoice.xml.erb - אם מישהו משתמש עדיין ב XML/XHTML) שנמצא בתיקייה app/views/layout.

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

אם יש לנו כמה controllers הקשורים זה לזה (למשל Admin screens), אנו יכולים להגדיר אותם בהיררכיה בתוך התיקיה app/controllers. אם הדפדפן ביקש URL בשל admin/user אז ריילס תחפש את ה controller בקובץ בשם user_controller.rb בתיקיה app/controllers/admin (כלומר: תת-התיקיה admin מקבצת את כל ה controllers בקבוצה).

בכדי למנוע התנגשות בין שני controllers בעלי אותו השם (נאמר user_conroller.rb בתיקיה app/controller/report), שם המחלקה יהיה namespaced ע"י מודול בשם של תת-התיקיה. במקרה שלנו: Admin::UserController.

רוצים לסדר את מבנה התיקיות בצורה שנוחה לכם? אולי ברור לכם עכשיו כמה קונפיגורציות תאלצו לנהל!





---

קישורים נוספים:

The Rails Doctrine - הרעיונות התכנוניים / פילוסופיים מאחורי ריילס.

מה ההבדל בין RDoc ל Markdown

?Is TDD Dead

A Conversation with Badri Janakiraman about Hexagonal Rails

פוסט על הארכיטקטורה של ריילס




---


[א] זו לא אמת חד-משמעית, אך כך מקובל להאמין.

[ב] Gems, הן ספריות קוד של רובי אותן ניתן להתקין בקלות (<gem install <gem name $) מ repository משותף-לכל. דומה ל npm packages של node.s, ל eggs של פייטון, או Pears (אגסים) של PHP.

[ג] פירוש המילה: פיגומים. הוספת templates קטנים (controller חדש, מודל חדש) תוך כדי עבודה ע"י הפעלה ב command line של "... rails generate", או בקיצור: "... rails g". זו המקבילה הרזה ל Create New <...> Wizard ב Eclipse, למשל. פקודת rails generate דומה מאוד ל Yo - למי שמכיר, ובעצם הייתה עבורה מקור ההשראה.

[ד] יש כמובן את Scala, Elixier, Rust, ועוד. הצגתי את הבחירות הנפוצות של אנשי רובי.

[ה] טכנולוגיות אלו הן לא "של ריילס", אבל ריילס עושה בהן שימוש מקיף, ואלי גם השפיעה עליהן במידה:
  • SASS - שפת מטא ל CSS
  • Haml - תחביר מקוצר ל HTML 
  • CoffeeScript - שפת מטא לכתיבת ג'אווהסקריפט, בתחביר שדומה לשפת רובי.
כתבתי על שפות המטא של ג'אווהסקיפט ו CCS בעבר.

[ו] Data Mapper, כמו Hibernate - מבודד את ה Domain מבסיס הנתונים, בכדי להפוך את ה Domain Logic לבלתי תלוי, קל לבדיקה (Unit Testing), ולאפשר שינויים בבסיס הנתונים במנותק מה Domain וליהפך. אמנם במקרים רבים הצוות משתמש ב Data Mapper כי זה "Best Practice" למרות שהכוונה הברורה היא שבסיס הנתונים יהיו מיפוי מדויק של המודל - או ליהפך (הכוונה: תמיד אובייקט = טבלה, בלי שום רמת הפשטה). כמובן שרמת ההפשטה האפשרית בפועל מעל בסיס הנתונים היא מסוימת - ולא "אינסופית". כדאי להזכיר ש Data Mappers נולדו בסביבת ה Enterprise, בה לעתים רבות לאפליקציה לא הייתה בלעדיות על ה Database schema.

2014-12-22

פוסט חנוכה: הגיגי-שפה

מה יותר "חד": Bleeding Edge או Cutting Edge?
מה ההבדל בין Accurate ו Precise (יש הבדל משמעותי) או בין Edge case ו Corner case?

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



סופגנייה מול Donuts - מה בעצם ההבדל?


ראשית, נתחמם עם כמה מוכרים יותר (סביר שחלקם יהיו כבר מוכרים לכם):

ניסוי ותהייה או ניסוי וטעייה?

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


עיקר ותפל או עיקר וטפל?

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

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


(שימו לב שעל כמה מההבדלים להלן - כתבתי בפוסטים לאורך השנים)


Parameter או Argument

האם אלו מילים נרדפות - או שיש הבדל?
ובכן... parameter הוא המשתנה שנמצא בחתימת הפונקציה (כיצד הפונקציה מכירה את המשתנה), ו Argument הוא הערך שנשלח לפונקציה בעת ההפעלה - כפי שהקוד שמפעיל את הפונקציה מכיר אותו. בקיצור: יש הבדל ברור.


Accurate vs. Precise

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


בגדול: Accuracy הוא הכיוון הנכון, Precision הוא הדיוק בפרטים.



מקור הביטוי Pros and Cons

מה זה "Pro" ומה זה "Con"? האם אלו מלים? האם ניתן להשתמש בהן בצורת יחיד? מה משמעותן?
ובכן, המקור הוא ביטוי בלטינית בשם "pro and contra" שמשמעו: "בעד ונגד", ובפועל משמש בימנו כ"יתרונות וחסרונות". contra קוצר ל con, ומכיוון שיש יותר מייתרון / חסרון יחיד - משתמשים בהם בצורת רבים: pros and cons.


Transparent vs. Opaque

לפעמים רואים מלים אלו כנרדפות ומתארות שקיפות ("זה שקוף לך!"), אבל בפועל אלו הפכים:
Transparent - משמע שקוף.
Opaque - משמע אטום.

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


General vs. Generic

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

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


Corner Case vs. Edge Case

האם יש באמת הבדל? האם אני צריך להסיק מסקנות אישית - כשאני מריץ בגוגל כאלו שאילתות?!

ובכן - יש הבדל מוגדר היטב:

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

Corner Case (איני יודע אם יש מינוח עברי מקובל) - הוא תופעה פתולוגית, שמתרחשת רק כאשר רצף של מקרים, לא נפוצים מתרחש. באופן ויזאולי ניתן לחשוב עליו כהרכבה של כמה edge cases שמתרחשים בו-זמנית (ואכן פינה היא נקודת חיבור של כמה קצוות). זה בעצם מה שנתקלים בו כאשר משחררים תוכנה מורכבת ללקוחות מורכבים.



מה יותר חד: "bleeding edge" או "cutting edge"?

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

באופן מעט מפתיע - דווקא יש הגדרה ברורה:

Cutting Edge (ביטוי נרדף: "Leading Edge") מציין את הפיתוח הכי מתוחכם ומתקדם בתחום. אין לו הקשר לסיכון או לחוסר בשלות.

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

ההבדל הוא בעצם בין "הטוב ביותר" ל"חדש ביותר" (מקור).


מהיכן מגיע המונח "באג"?

(לצעירים שביננו שעדיין לא שמעו זאת כבר חמש פעמים)

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

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

הנה צילום המחברת של גרייס (שנלקח מתוך הביוגרפיה שלה):




UK מול "בריטניה הגדולה"

נכון, זה לא ממש לא קשור לתחום התוכנה, אבל נתקלתי בהבחנה הזו כחלק מהעבודה - תוך כדי קריאה של איזה תקן.
מה שמשך את תשומת לבי היא הערה בתקן שאמרה בערך כך: "אמנם אנו משתמשים בקיצור GB - אבל הכוונה היא ל United Kingdom ולא ל Great Britian, זו טעות היסטורית שלא ניתן לשנות".

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

מקור



כמה הגיות שאנו נוהגים להגות לא נכון (תזכורת):

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

Digital נשמע כמו דיג'יטל, ולא דיגיטל.

Medium נשמע כמו מידיום (midi) ולא מדיום (med). מדיום הוא מדיום-תקשורת.

Char הוא קיצור של Character, ולכן הגיוני יותר להגות אותו כ"קר" ולא כ"צ'ר" (למרות ששמעתי גם אמריקאים אומרים "צ'ר").

בשני האחרונים כדאי לנסות לחקות את ההגייה של הנשיא פרס (פולני):

Data הוא דייטה (dey) ולא דטה (da).

Micro (כמו במיקרו-שירותים) הוא מייקרו (mai) ולא מיקרו (mi)


סיכום


אני מקווה שניהנתם.
אתם יותר ממוזמנים להגיב ולהוסיף את ההגיגים שלכם.

וחג שמח!




2014-12-15

דפוסי ארכיטקטורה: מיקרו-שירותים (Micro-Services Architecture)


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

מיקרו-שירותים הוא "הטרנד החם" בנושא הארכיטקטורה בשנים האחרונות, ונראה שהוא כבר עכשיו הדיח את ארכיטקטורת השכבות ממקומה והפך ל "ארכיטקטורת ברירת המחדל למערכות ווב" (או מה שאוהבים לקרוא לו היום Twelve-Factor App)

יש בזה הגיון רב: בסאפ יצא לי לראות מערכות בהן Layered Architecture התאימה בצורה נהדרת לאתגרים והדרישות. מדובר במערכות עסקיות, גדולות ומורכבות בהן ה UI הוא שיקוף של הסכמה בבסיס הנתונים.
במערכות מודרניות יותר, בהן ה UI הוא עשיר יותר ובעצם בסיס הנתונים הוא שיקוף של חווית השימוש שתוכננה, חלק מההנחות של ארכיטקטורת השכבות (למשל: "ה UI משתנה ללא שינויים ב Business Logic ו/או ה Persistence") - פשוט לא משקפות את המציאות.

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

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






הסבירו לי נא, בדקה, מה "הקטע" של מיקרו-שירותים?


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

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

בפועל, רוב היכולות של מערכות הווב המודרניות מרכיבות גם UI, גם לוגיקה, וגם Persistence - כך שכל deploy דורש את כל שכבות המערכת.

מיקרו-שירותים הוא תהליך פירוק המערכת (מודולריזציה) לרכיבים (נקראים "שירותים"). ה"חיתוך" הוא לא אופקי (כמו במודל השכבות - ע"פ רמת הפשטה), אלא אנכי (ע"פ הפונקציה). כמו כן מחלקים את המערכת ליותר חלקים. תכונות השירותים הן:
  • ניתן לעשות לכל שירות deploy באופן בלתי-תלוי באחרים.
    לאמזון יש עשרות אלפי מיקרו-שירותים, והיא עושה deploy כל 10 שניות (בממוצע). איך ייתכן? היא פשוט עושה deploy כל פעם לחתיכה קטנה אחרת של קוד.
    בדרך כלל מיקרו-שירותים מורצים כתהליכים נפרדים של מערכת ההפעלה, המתקשרים זה עם זה על גבי HTTP / REST.
  • ניתן לפתח כל שירות באופן בלתי תלוי: CI, בדיקות, וסביבת העבודה היא בלתי-תלויה. אולי גם שפת התכנות.
    תכונה זו היא מרכזית מאוד, ומטרתה לשפר את ה scalability של הפיתוח: כמה מפתחים בצורה יעילה במקביל על הקוד. ההנחה כאן שהיא שיותר קל לפתח הרבה רכיבים קטנים - מאשר רכיב אחד גדול.
  • לכל שירות יש Persistence בלתי-תלוי.
    תנאי זה בא לשרת את שני העקרונות הקודמים - והוא לא מטרה בפני עצמה. Persistence היא תלות בין רכיבים במערכת, אם כי פחות מורגשת. אם שני שירותים ישתמשו באותן טבלאות בבסיס הנתונים - יהיה לכם הרבה יותר קשה להגיע ל deployment בלתי תלוי. גם אי-התלות בסביבת הפיתוח תשתפר מתנאי זה.
  • מיקרו-שירותים הם קטנים.
    "כמה קטנים?" - זהו דיון חם עליו אפשר לכתוב פוסט בפני עצמו. הנה כמה מדדים מקובלים (ולא-מתואמים) לגודל המומלץ למיקרו-שירותים. למרות שהם שונים - כולם מרמזים על "קטן למדי":
    • מספיק קטן כך שאדם אחד יכול להכיר היטב את כל הקוד של השירות ("כזה שיכנס כולו לראש שלי" - הגדיר ג'יימס לואיס, חלוץ בתחום ה MSA)
    • מספיק קטן שצוות אחד (שניתן להאכיל בעזרת 2 פיצות אמריקאיות גדולות) - יכול לפתח ולתחזק אותו.
    • כמה מאות שורות של קוד. 
    • מספיק קטן שלא יהיה קשה לארגון "לזרוק" אותו - ולכתוב אותו מחדש.
      מספרים שדף הבית של אמזון מפעיל כ 100-150 שירותים שונים (תלוי במקרה המדויק) בכדי לשרת כניסה של משתמש.
  • שירות עושה "דבר אחד בלבד" - Single Responsibility Principle.
    כמובן שגם "מתפעל את הלוגיסטיקה של וולמארט" הוא דבר אחד בלבד - ולא דבר קטן בכלל!
    זהו כמובן כלל קונספטואלי, שלא ניתן לאמוד אותו "מתמטית" - ושיהיה עליכם ליצור קונצנזוס ארגוני לגביו. כלל זה בא לשרת ולסייע לכם לקיים את כל התנאים הנ"ל.


היתרונות העיקריים של ארכיטקטורת המיקרו-שירותים הם:
  • ארכיטקטורה שתומכת ב Continuous Deployment. שניה! האם CD הוא מטרה או אמצעי? ובכן... גם וגם. CD משרת מטרות עסקיות (feedback מהיר ולמידה מהירה) והוא מנבא מוצלח של ההצלחה העסקית של הארגון (מקור).
  • Scalability של הפיתוח, הרבה מפתחים יכולים לעשות הרבה שינויים במקביל - ולפחד פחות.
    הנחה סמויה - יש לכם לא רק את הארכיטקטורה של מיקרו-שירותים, אלא גם מערך מקיף של בדיקות אוטומטיות שהכרחיות לקיום של CD סביר.
  • High Availability - קריסה של שירות אחד (או חמישה) - לא משביתים את המערכת שלכם, אם הם לא קריטיים ל flows המרכזיים של המערכת. שירות קרס בצורה בלתי צפויה? יש memory leak? מכיוון שכל שירות רץ כתהליך נפרד של מערכת ההפעלה - הוא עשוי לא להשפיע על השירותים האחרים. קריסה של קוד ב Layered Architecture / Monolith - סביר יותר שתגרום להשבתה.
  • אפשור / קידום שכתוב הדרגתי של המערכת.
    אם למשל, החלטתם לעבור מרובי לסקאלה (עוד מופע של "Ruby doesn't scale") או מ Framework אחד ל Framework שני - המשמעות בארכיטקטורה Layered היא דרמטית: עצירה ארוכה בכדי לאפשר שינוי שכזה.
    מצד שני, זה הרבה יותר פשוט בארכיטקטורת מיקרו-שירותים: ניתן להתחיל להעביר שירותים ל Stack החדש בזה אחר זה - וחלק מהם לא להעביר לעולם. רק שימו לב שאתם לא נגררים לתפעול של stacks רבים רק כי "אפשר", או מחוסר תשומת לב - זו טעות קלאסית.
    תכונה זו של הארכיטקטורה היא שימושית במיוחד כאשר אתם חיים בעולם שבו המערכת שלכם נמצאת ב Refactoring תמידי (כי העסק דינאמי ומבנה השירות הישן כבר לא עושה את העבודה אחרי שנה-שנתיים...). 
  • Scalability של ה production - מכיוון שאתם יכולים "לשכפל" ו/או לבצע אופטימיזציות על שירות X מבלי להתמודד עם שכפול או השפעות הביצועים של שירות Y שמתקשה להשתכפל. בעיות Scalability מטופלות בשיטה "פרה, פרה".
    נושא זה הוא גם, בד בבד, חולשה של מיקרו-שירותים, נסביר מיד.


באופן טבעי, יש לארכיטקטורת מיקרו-השירותים גם כמה חולשות:
  • קושי ב monitoring ושחזור בעיות ב production. כאשר יש לכם עשרות (שלא לדבר על מאות) שירותים שונים - קשה יותר לשחזר בעיות ולנתח. למשל: לאסוף ולסנכרן לוגים של שירותים שונים, במיוחד אם כמה שירותים התעדכנו לגרסאות שונות מאז. צפו השקעה בניהול והפצה של ה session id בין כל הקריאות. מיקרו שירותים "מפרקים את התמונה" להרבה תמונות קטנות, וכדי להבין מה קורה במערכת - יש להשקיע ב "להרכיב את התמונה בחזרה".
  • Scalability של ה production, ויעילות בכלל - מכיוון ששירותים שיכלו עד עכשיו לתקשר בזיכרון, מתקשרים כעת על גבי HTTP  - לכל קריאה נוסף overhead מסוים. מכיוון שיש הרבה מיקרו-שירותים, שיגרמו להרבה קריאות וה overhead הזה ילך ויגבר.
    פעמים רבות, ה overhead הזה מחייב מעבר ל I/O אסינכרוני - מה שמסבך את הקוד.
  • Refracting יכול להיות מורכב - אם הוא חוצה-שירותים.
  • Operational Complexity - בעוד monitoring הוא האתגר הראשון, הוא לא האחרון. תפעול של שירות בודד אולי הוא קל יותר, אך לתפעל מערכת של מאות שירותים (גרסאות, היכן רצים, כיצד לשדרג) - היא משימה לא קלה לכל הדעות. אומרים שאימוץ של מיקרו-שירותים מעביר מורכבות מהפיתוח ל Operations. סביר להניח שאימוץ ארכיטקטורה של מיקרו-שירותים תאלץ את גוף ה Operations שלכם "לעלות מדרגה" מבחינת היכולות שלו. אם הוא לא יצליח - זה הולך להיות כואב מאוד...

באופן מעט מפתיע, המונח Microservice Envy נוסף כמשהו שכדאי להיזהר ממנו, בדו"ח של Technology Radar Jan2015 של חברת Thoghtworks. למה מפתיע? כי Micro-Services הוא משהו שמדברים עליו קצת יותר משנה, אז הגענו מהר למדי למצב בו מתריעים משימוש יתר / שימוש ללא הבנה מספיקה. הנה הציטוט המדוייק:

We remain convinced that microservices can offer significant advantages to organizations, in terms of improving team autonomy and faster frequency of change. The additional complexity that comes from distributed systems requires an additional level of maturity and investment. We are concerned that some teams are rushing in to adopting microservices without understanding the changes to development, test, and operations that are required to do them well. Our general advice remains simple. Avoid microservice envy and start with one or two services before rushing headlong into developing more, to allow your teams time to adjust and understand the right level of granularity.





אז מה ההבדל בין מיקרו-שרותים ל SOA?


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

הקושי הבולט שאני נתקל בו בניסיון לענות על השאלה הזו, היא שבעוד שאנו מסכימים (כנראה) מהם מיקרו-שירותים - מי בכלל מסכים בעולם על ההגדרה של SOA?!

הדרך היחידה בה אני יכול לענות על השאלה הזו, היא להניח כל פעם על פרשנות שונה של "SOA" - ואז לנסות ולענות.


אם SOA עבורכם הם SOAP ותקני ה *-WS
אז התשובה היא פשוטה: אתם יכולים להשתמש ב *-WS גם במיקרו שירותים, אבל סביר שתקורת הפיתוח ותקורת הביצועים - יהרגו אתכם.
אחת מהנחות היסוד של *-WS היא "coarse grained services" - וזה היהפך המוחלט בהנחת היסוד של מיקרו-שירותים שהם קטנים. חוץ מזה - אין ספק שיש גם הרבה עקרונות משותפים.


אם SOA עבורכם היא ניהול ("mix and match") של שירותים בדמות ESB או CMDB
ESB (קיצור של Enterprise Service Bus) הוא הרעיון בו ניתן יהיה לעשות שינויים במערכת לא בקוד, אלא בקונפיגורציה - וכנראה ע"י power business users. יהיו הרבה שירותים שעושים פעולות טכניות (חישוב עלות טיסה, רישום הזמנה, וכו') - אך כל flow בעל משמעות יורכב בעצם ב ESB ע"י חיווט של השירותים הנתונים בקונפיגורציות שונות.

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

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

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


אם SOA עבורכם הוא מידול של המערכת לשירותים stateless ופונקציונליים
כלומר: אתם מאמינים שניתן לחלק את המערכת לפונקציות ("רכיב לכל משימה") - ולא דווקא ע"פ חלוקה OO. את השירותים עצמם - ניתן כמובן לפתח ב OO. כמו כן - אי-תלות מובנה בין השירותים.

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

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




האנטומיה של מיקרו-שירות



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


עד עכשיו סיפקתי סקירה high level של הנושא - אך יש עוד פרטים רבים שהייתי רוצה לגעת בהם.
למשל: כיצד מתחילים? כיצד "מפרקים" מערכת למיקרו-שירותים (להזכיר: MSA = Micro-Services Architecture)?

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

על השירות להיות self-contained: להכיל את ה deployment script העצמאי משלו, את הפרוייקט ב IDE משלו, את הבדיקות שלו, את התלויות שלו (ספריות צד-שלישי, בגרסאותיהן השונות) - וכו'.
מבחן טוב לעצמאות הזו היא מפתח חדש שמקנפג סביבה רק עבור השירות הזה, פותח רק אותו ב IDE - ומצליח לעשות שינויים ולהעביר אותם ל production מבלי להסתבך. השאיפה היא ליצור מערכת גדולה - מתוך הרבה רכיבים קטנים ופשוטים, ושפיתוח של כל רכיב קטן שכזה - יהיה פשוט כמו כתיבה של רכיב פשוט עצמאי (נאמר: תרגיל בקורס באוניברסיטה).

השלכה משמעותית של רעיון זה, הוא שאת השירות צריכה לכתוב קבוצת אנשים שיכולה לבצע את כל המטלות הנדרשות מהם (UI, Operations, DB, ולוגיקה עסקית). ע"פ Conway's law, אם בארגון שלכם יש "צוותי UI", "צוותי DB", ו"צוותי server" (ולא "צוותים פונקציונליים") - אזי סביר שהיישום של השירותים אצלכם יהיה: שירותי UI, שירותי DB, ושירותי Server - שזה נחשב מידול לא טוב של מיקרו-שירותים. ייתכן ויהיה עליכם לשנות את המבנה הארגוני בכדי להגיע ל MSA מוצלח.

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

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


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


   האם על כל שירות להיות מנוהל ב Git Repository עצמאי?
זה עניין של טעם. למשל: גוגל מנהלים 90% מהשירותים שלהם ב repository יחיד. Git repository לכל שירות - גם הוא סביר בעיני.


   מה עושים עם ספריות שכל השירותים צריכים? למשל Logging או אבטחה?
מה שאתם עושים עם כל ספריית Open Source שאתם משתמשים בה הרבה - הוסיפו אותה כ dependency לכל השירותים שזקוקים לה. זה אמנם לא שירות - אבל לא כל הקוד חייב להתמפות לשירותים, יכולים להיות גם "סתם רכיבים לשימוש חוזר". הרגישו נוח לייצר וריאציה שלכם על דפוס הארכיטקטורה.
אפשר לדמיין מיקרו-שירות שעובר ל production כתא חי: יש את פנים התא שהוא ייחודי, ועוד קצת infrastructure שיש לשלוח עם כל תא ל production בכדי לקיים אותו. וכן - יהיו הרבה instances של השירותים הללו חיים (מה שמקשה על ניטור ו root cause analysis).

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


   מה??? יהיו לי במערכת גרסאות שונות של 3rd Parties? יהיה עלי להתמודד גם עם באגים של SpringFW 3.0.1 וגם עם אלו של SpringFW 4.1.2?
ובכן - היכולת להשתמש בגרסאות שונות של ספריות הוא דווקא יתרון גדול של MSA. כשיש מערכת גדולה ועותק יחיד של הספריה - אנחנו נאלצים לרוב "להיתקע" עם גרסה ישנה לאורך זמן, או לצאת ל"מסע צלב" בכדי לשדרג אותה. הפחד מ"ריבוי באגים" הוא לא תמיד כ"כ ריאלי. בכל מקרה - ברור שיש תקורה בשימוש במספר רב של גרסאות של אותה הספרייה - הייתי ממליץ לנהל "רשימת גרסאות מאושרת" שניתן יהיה לבחור רק ממנה במוצר. לאזן בין גמישות לשליטה.

יש מצבים בהם יש בעיה טכנית להשתמש בגרסאות שונות של אותה הספרייה (למשל: כאשר השירותים הם לא תהליכים שונים של מערכת ההפעלה אלא למשל wars ב JEE application server, או שימוש ב jQuery כאשר UI של שירותים שונים מוצג זה לצד זה על אותו דף של דפדפן. מה עושים? מתפשרים, או מחליפים טכנולוגיה - כמו תמיד.


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

הייתי מסכם זאת כך: RDBMS (בסיסי נתונים רלציוניים) הם בעלי התאמה גבוהה לארכיטקטורת Layers, אך בעלי התאמה פחות טובה - ל MSA. אם אתם עובדים עם MSA (או רק CD) - הבעיות יהיו קטנות יותר אם תעבדו עם בסיסי נתונים שהם schema-less כמו K/V DB או Document DB.
האמת שהיכולות המתקדמות של RDBMS עודדו הפרות משמעותיות של עקרונות ארכיטקטוניים חשובים (הכמסה, שבירת ה Layering שהוגדר, וכו'). איך קיבלנו זאת כל השנים? - זה פשוט עבד.


   איך מנהלים Transactions אם הנתונים שלנו מבוזרים לטבלאות שונות?
פשוט לא עושים. לא מגיעים ל Internet Scale כשעובדים עם ACID. נוקטים מדיניות של Eventually Consistent.


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


   כיצד שירותים מתקשרים זה עם זה? כיצד הם יודעים על קיומו אחד של השני?
בדרך כלל לכל שירות יש URL וניתן להשתמש ב DNS ו Load Balancer בכדי לנהל כמה עותקים - ולמצוא עותק זמין. הכי נפוץ הוא להשתמש בתקשורת REST, הרי - למה להמציא את הגלגל מחדש. אפשר גם על גבי TCP/UDP, אולי RPC או Thrift - הכל ע"פ הצרכים שלכם. בד"כ יהיו לכם גרסאות שונות של ה APIs של השירות, וכמה גרסאות של API שיחיו במקביל - עד שתוכלו באמת להשבית אותם.

דפוס נפוץ בארגון APIs של מיקרו-שירותים הוא ה API Gateway (מסמך: כיצד נטפליקס עושים זאת): שירות נוסף שכל תפקידו לקבל בקשה מה Client (ב URL אחד וב HTTP request אחד) - ולקרוא לכמה שירותים, להרכיב את התוצאות, ולהחזיר הכל באותה הקריאה. שירות זה הוא סוג של Facade שיסתיר מ clients חלק מהשינויים במבנה השירותים (פיצול, שינויי API, וכו')

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

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

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


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


   האם אין תשתית כזאת, שתפתור לי את כל הבעיות שנובעות מ MSA - ותשאיר אותי עם כל התהילה, והיכולת להתמקד בכתיבת הקוד העסקי?
יש כל-מיני ניסיונות. יש את סנסה ל node.js, את rodent לרובי, או DropWizard של Yammer לעולם ה JVM. משום מה כולם עוסקים בפיתוח של המיקרו-שירותים (החלק הקל) ולא בתפעול שלהם (החלק היותר מורכב).
בכל מקרה... אם אתם קוראים את הבלוג - אתם אמורים לדעת מה דעתי האישית בנושא.


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






Bounded Contexts


רעיון שחוזר על עצמו שוב ושוב בהקשר ל MSA הוא רעיון ה Bounded Context, רעיון של מתודולוגיית ה Domain-Driven Design (בקיצור: DDD) של אריק אוונס. הרעיון מזהה שה Domain Model שלנו (תיאור האובייקטים בעולם והקשרים ביניהם. לא בתוכנה - ב"ביזנס") הוא לא אבסולוטי - אלא תלוי הקשר.

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

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

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

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

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

יש לכך כמה פתרונות: אפשר לנהל Shared Context שמכיל את ההזמנה ומשותף לשני העולמות, ניתן לעשות "המרה" של אובייקט מ BC אחד ל BC שני, אפשר שה BC יראה רק view - אבל בבסיס הנתונים (שכבה נמוכה יותר) יהיה מודל שהוא aggregation של כל התכונות מכל המודלים, וכו' וכו'.

הקשר בין BC ל MSA הוא פשוט: אותן בעיות שהתמודדו איתן במשך שנים ב DDD, ובפרט בעקבות רעיון ה BC - צצות עכשיו בעולם ה MSA. בשני העולמות מאמינים שחלוקת המודל למודלים מקומיים וקטנים / פשוטים יותר - היא הדרך הנכונה להצליח.






בדיקות


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

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

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

השימוש ב MSA פותח כל מיני שאלות על Testing שלא היינו צריכים להתמודד איתן קודם לכן. 
טובי קלמסון ניסה לסכם את כל אפשרויות הבדיקה במצגת דיי מקיפה. קשה לי לתמצת את מה שהוא אמר - כי הוא חוזר על הרבה רעיונות מוכרים ומנסה להתאים אותם לסביבה של MSA:
  • נסו להריץ כמה שיותר בדיקות בזיכרון / עם mocks - שירוצו מהר.
  • כתבו יותר בדיקות יחידה ואינטגרציה ופחות בדיקות End-to-End שקשה לתחזק ("פירמידת הבדיקות").
  • בדקו לוגיקה בעזרת בדיקות יחידה, וקוד יותר "משעמם" עם בדיקות אינטגרציה או בדיקות-רכיב (בעיה: יש פרשנויות שונות לכמעט כל סוג בדיקה שנציין).
גישה אחרת (אציין: מקובלת) היא להשקיע פחות בבדיקות אינטגרציה - ויותר בניטור המערכת והיכולת לבצע root cause analysis מהיר. במקום prevention (בדיקות) - להתמקד בטיפול הבעיה ברגע שהיא צצה. יש הגיון כלכלי ברור לגישה זו, אם כי לוקח זמן להגיע לרמה "מספיק טובה" של ניטור והתאוששות בכדי שנסמוך על המערכת הזו להחליף את תפקידם של בדיקות האינטגרציה.

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



סיכום 


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

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

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

החלטנו לעבור למיקרו שירותים - אבל הייתה הסתייגות רבה מניהול תהליכים נפרדים המתקשרים ב REST, בעיקר בגלל שזה קוד רב "ומשעמם" שיש להוסיף למערכת. המערכת כיום (כמו רוב מערכות ה Layered Architecture) מלאה בקשרים רוחביים בתוך ה Layers שקשה מאוד לנתק. באמת התרנו לעצמנו לקרוא מכל מקום ב Layer לכל פונקציה אחרת ב Layer - מה שגרם לריבוי תלויות. כמובן שגם ברמת ה DTO בעיות רבות נפתרו בעזרת "joins" - מה שקשר את הפונקציות השונות של המערכת גם בשכבה זו. ניתוח תלויות ראשוני נראה קצת מבהיל במחשבה שכל תלות הופכת לקריאת HTTP.

לכן...החלטנו לוותר על התכונה של "isolation by process" של MSA - ויצרנו וריאציה קצת חדשה: כל שירות מקבל פרויקט נפרד (pom.xml במייבן משלו) עם build משלו, בדיקות משלו, וכו' - והוא נארז לתוך קובץ jar. (המערכת כתובה בשפת ג'אווה + UI בשפת ג'אווהסקריפט). את כל השירותים אנו אח"כ אורזים לתוך קובץ war. גדול - ואז עושים deploy.

כיצד אם כן עושים deploy לשירות בודד?
שומרים תמיד את קובץ ה war. האחרון שעבר deploy, מעדכנים רק את קבצי ה jar. של השירות הרלוונטי (הוא עצמו + תלויות ישירות) - ועושים deploy מחדש.

איך מוודאים isolation בין השירותים?
הגדרנו שבכל שירות יהיה package מיוחד בג'אווה בשם facade המתאר את הממשק החיצוני של השירות - ורק לו שירותים אחרים יכולים לקרוא. אנו מתכוונים לאכוף התנהגות זו בעזרת JDepend שירוץ בעת ה build ויפיל אותו בעת חריגות.
בעת build של כל שירות - ה jar. שנוצר מתעדכן ב maven repository של הארגון, ושירותים אחרים שתלויים בו פשוט מגדירים תלות ל jar הזה ומקבלים גרסה עדכנית בעת ה build שלהם.

ל facade יכולים לקרוא שירותים אחרים או שכבה שנמצאת בתוך השירות (בשם webaccess) - במידה והשירות גם זמין על גבי HTTP.

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

עד כמה וריאציה זו של MSA מוצלחת? ייקח זמן לדעת. בוודאי נעשה עליה עוד שינויים והתאמות.

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



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





-----

לינקים מעניינים

תיאור של חברת SoundCloud על האתגרים במעבר מאפליקציה אחת גדולה ("Monolith") לארכיטקטורה של מיקרו שירותים. מומלץ!
חלק א': http://goo.gl/1ciqbS, חלק ב': http://goo.gl/31Gmy7, חלק ג': http://goo.gl/0aeq3u.

פוסט ידוע, ומצוטט רבות, של ג'יימס לואיס ומרטין פאוולר על מיקרו-שירותים: http://martinfowler.com/articles/microservices.html.
גם שווה קריאה. הם עוסקים בכמה היבטים בהם לא נגעתי בפוסט.

הקלטה של סשן מ Buraco 2012 של Fred George על מיקור-שירותים מיקרו-שירותים: https://www.youtube.com/watch?v=2rKEveL55TY

יש גם מצגת של ג'יימס לואיס בנושא (איך לא?): http://www.infoq.com/presentations/Micro-Services

מצגת מעניינת: http://www.slideshare.net/fuglylogic/microservices-26369481

פרק בפודקאסט "Software Engineering Radio" שעוסק במיקרו-שירותים: http://www.se-radio.net/2014/10/episode-213-james-lewis-on-microservices/




2014-12-12

סדרה: רובי (Ruby) למפתחי ג'אווה ותיקים

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

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

אני מרגיש פספוס קטן שרק עכשיו, אחרי כ 12 שנים בתעשיה, אני נחשף לראשונה באמת להבנה מהם רובי וריילס. פתאום אני מזהה נקודות השפעה שונות שלהן שראיתי שהכרתי כבר שנים - אך לא זיהיתי את מקור ההשפעה. נכון: ריילס נמצאת בדעיכה, מתוך כך שהמשקל של ה UI עובר לצד הלקוח, וכדי לכתוב REST APIs ברובי מספיק כנראה לקחת את Sinatra ו Active Records (כך אומרים). לא צריך את כל "המשקל" של ריילס. ההחלשות של ריילס משפיעה גם על רובי, ופתאום יותר מגניב מ"לעשות רובי" זה "לעשות node.js" [א].

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


---





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







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







RVM - כלי לניהול סביבות (וגרסאות רובי)
כאשר אתם מתחילים לכתוב רובי קצת יותר ברצינות - זהו כלי שכדאי להכיר.


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




ריילס, רובי on ריילס
שפת רובי איננה שפת רובי ללא ה framework הכ"כ-מפורסם שלה לפיתוח אפליקציות ווב: Ruby on Rails. בפוסט זה נספק סקירת high level על ריילס.






-----

[א] אפילו מאטצ' (שם החיבה של Matsumoto Yukihiro - ממציא רובי) עובד (במקביל) על שפה חדשה - Streem.



-----

לינקים מעניינים

Ruby Weekly - דרך טובה להתעדכן על החדש ברובי / ריילס.



2014-12-11

כנס הארכיטקטורה הראשון של IASA ו ILTAM

עדכון (11 בדצמבר, 2014)

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


------


שבוע שעבר, בימים שני ושלישי התקיים "כנס הארכיטקטים הראשון" של IASA ואילתם.

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

ל IASA יש גם קבוצה ב LinkedIn  (דורשת הצטרפות) - בה חברים רבים מהארכיטקטים שאני מכיר. אם אתם ארכיטקטים - אני ממליץ לשקול להצטרף (אני חושב שלא יאשרו לכם להצטרף אם לא כתוב בקורות החיים שלכם שאתם ממש ארכיטקטים באופן רשמי).

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

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

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


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

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

מקור

אני אספר בקצרה על שני sessions שהיו לי מעניינים במיוחד:

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

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

רוב התוצאות שאציג להלהן הן מסקר בו נשאלו מאה ומשהו ארכיטקטים על העבודה שלהם: מה הם עושים מול מה שהם חושבים שהם צריכים לעשות. כל התוצאות הן בסקאלה של 1 עד 5 (כלומר: 3.5 ממוצע) - כאשר המספר המדויק לא ברשותי - אני מספק רק "קריאה" שלי מגרף מסוג Bar Chart. למשל:
  • ארכיטקטים הם חלק מצוות הפיתוח (בערך 3.6) בעוד הם חושבים שהם צריכים להיות פחות חלק ממנו (בערך 3.4).
  • ארכיטקטים מובילים את תהליך פיתוח התוכנה (3.1 = נטיה ל"לא"), אבל הם מאמינים שהם צריכים לעשות זאת (3.9)
  • הם גם משתתפים במידה רבה בישיבות תכנון (3.9) - אבל מאמינים שצריכים להיות שם הרבה יותר (בערך 4.35).
  • בגדול ארכיטקטים מאמינים שהם צריכים להיות:
    • שותפים משמעותיים יותר בפיתוח המקצועיות ומתודולוגיות הפיתוח בארגון.
    • שותפים משמעותיים יותר בהגדרת המוצר / חקר השוק.
    • שותפים משמעותיים יותר בגיוס עובדים.
  • מה הם חושבים שהם צריכים לעשות פחות?
    • קידוד: עושים לא-הרבה (3.1) - אבל רוצים לעשות פחות (3)
    • אחריות על באגים / תחזוקת-קוד: עושים מעט (2.6) - אבל רוצים לעשות משמעותית פחות (בערך 2.3).
ניתן לקרוא את התוצאות ולומר: "ברור! כמו כולם הם רוצים להשפיע יותר, לעשות יותר עבודה כיפית - ופחות עבודה משעממת.". אין לי מדד להשוואה למפתחי תוכנה - אבל אני מניח שהיינו רואים מגמות דומות.

בכל זאת, שימו לב שהשאלה לא הייתה "מה הייתם רוצים לעשות", אלא "מה אתם חושבים שאתם צריכים לעשות (should do)". אני מעריך (היפותזה) שמפתחים ותיקים לא היו חושבים שהם צריכים "להנחות את הארכיטקטורה של כל פעילויות התכנון" ("Provide architectural guidelines for all software design activities" - ההדגשה שלי) - עושים: 4.1, חושבים שצריכים: 4.37.

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

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

אני חושב שהייתי מעדיף שיקראו לארכיטקט Principal Engineer או System Engineer וכו'...

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


Wix - להגיע ל n מליון משתמשים (n = כרגע 50 וקצת)
טוב... רציתי לגעת גם במצגת של יואב מ Wix - אבל גם רציתי לכתוב פוסט קצרצר.
אתם יכלים למצוא ביוטיוב את ההרצאה - בגרסה מעט יותר מוקדמת שלה.

כמה נקודות מעניינות שעלו:
  • אם Wix הייתה "עושה ארכיטקטורה נכונה מהתחלה" - היא לא הייתה שורדת את השנים הראשונות.
  • רכיבים במערכת צריכים להיכתב לתקופה קצובה - ואז להיכתב מחדש (טיעון מקובל בעולם ה Micro-Services). כתבו קוד שיהיה קל-להחלפה.
  • לא זקוקים לבסיס נתונים NoSQL בכדי לעשות NoSQL. עברתי, בזמנו, חוויה דומה - וכתבתי על כך פוסט.
  • כל מפתח מחזיק הרשאות ל production servers - אנו מעסיקים רק את מי שאנו סומכים עליו (אני מתרגם זאת לעצמי: אנו לא סומכים על אף-אחד, בנינו תשתית מתאוששת-עצמית - ולכן אנו יכולים "לסמוך על כולם"). זו גישה דיי מקובלת בעולם ה CD.
  • ההעדפה של Wix ל Managed Data Center (דוגמת Rackspace - אני לא יודע עם מי באמת הם עובדים) על פני AWS - שם כמות המשתנים הבלתי ידועים / נשלטים (למשל: מה החומרה שלי, latency) - היא קטנה יותר.
  • הערה: פרופיל השימוש ב Wix הוא דיי חריג בעולם ה Web (המון המון תוכן סטאטי) - ולכן אני מציע לשקלל עובדה זו בכל רעיונות Scalability שאתם לוקחים מהם.
כמו שאמרתי, Wix היא במיינסטרים של עולם ה Start-up Web ו CD.



סיכום


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

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


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