יום שבת, 17 בדצמבר 2016

אז... אתם רוצים Continuous Deployment? (חלק ב')

בפוסט הקודם דיברנו על המוטיבציה ל CI/CD/CDD, על הציפיות והסיבות לאמץ את המתודולוגיות הללו, ותיארנו בפירוט מהו CI (הרעיון מעט שונה ממה שמקובל לחשוב).

בפוסט זה ארצה לפרט יותר על CD - ואולי גם כאן הרעיונות נבלעו תחת תפיסה פופולארית פשטנית.





Continuous Delivery (בקיצור: CD)


זהו הרעיון שקוד המערכת יהיה כל הזמן במצב ניתן לדילוור ("shippable state").

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

התרומה הראשונית של תנועת ה CD הייתה להחזיר את רעיון ה CI למרכז המפה, לא CI כסיסמה - אלא הבנה מעמיקה יותר של רעיון ה CI.

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

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

גם CD, באופן טבעי, הוא מוצהר יותר מאשר נעשה בפועל. זהו הטבע של התעשייה.


הצעד החשוב השני שתנועת ה CD עשתה היא להרחיב את מעגל האיטרציות ה SCRUM-י.
יישום נפוץ של סקראם (או מתודולוגיות אג'ייל דומות) בארגונים היה שצוותי הפיתוח עבדו באיטרציות קצרות - אך השלבים בתהליך שלפני הפיתוח (תכנון / אפיון מוצר) והשלבים שבאים אחריהם (בדיקות ו Release) - נותרו תהליכים ארוכים ולא גמישים.

ג'ז האמבל קרא למצב הזה Water-SCRUM-Fall, והוא מתואר בתרשים הבא:

מקור: ג'ז האמבל - http://www.slideshare.net/jezhumble/21-century-software

מי לא מכיר את המצב הזה? אני מניח שרובנו...


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

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

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


הספר Continuous Delivery יצא ב 2010, עוד לפני עידן ה SaaS. כלומר: לפני ש SaaS היה הצורה המקובלת לדלוור תוכנה. הספר מדבר בעיקר על Packaged Software - כזו שהלקוח מוריד את קובצי ההתקנה ומתקין בעצמו.

Case Study שג'ז האמבל אוהב להזכיר הוא הטמעת CD במחלקת המדפסות של חברת HP - כיצד לבצע CD ל firmware (הקוד שרץ בתוך המדפסת). זו דוגמה טובה לקוד שניתן לבנות אותו כל יום - אך עדכונים ישוחררו ללקוחות רק אחת לכמה חודשים (או אפילו פחות מכך).



יישום CD בצד הרעיוני


מדד-מפתח באימוץ של CD בארגון הוא ה Lead Time, אותו יש לשפר כל הזמן:


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

ההתמקדות ב Lead Time מספקת אופטימיזציה בארגון לתהליכים רבים: תקשורת, תעדוף, Build מהיר, handover ל QA, ותהליכי בדיקות אוטומטיים, ועוד. אם היינו מתמקדים רק ב Process Time, או רק בחלק הפיתוחי של ה Process Time - אולי הפיתוח היה עובד מהר יותר, אבל הפיצ'ר עדיין היה "תקוע":
"הפיצ'ר מוכן, אבל הוא עדיין מחכה רק ל QA/התקנה" או "אנחנו מוכנים להתחיל, אבל מחכים ל Product/עיצוב" - הוא תירוץ שמתכנתים מרגישים נוח איתו, אך הוא לא מספק את צורכי הביזנס.

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




עוד הבחנה ש CD מתמקד בה היא שהזמן שמושקע בפיתוח מתחלק לחלק נראה, ולבתי-נראה:



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

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

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


הנה השיפורים שהושגו, בחניכה של ג'ז האמבל במחלקת ה Firmware (מדפסות) של HP:



האם CD מציע לנו עולם שבו 80% מהזמן מוקדש לכתיבת קוד חדש ופיצ'רים? - לא ולא. יש הרבה עבודת אוטומציה ואחזקה. אבל, במקרה הנ"ל הצליחו להגדיל פי 8* - את הזמן שגוף הפיתוח משקיע בפיתוחים חדשים ("Innovation").
ההערה למטה בלבן מסבירה ש 23% מהזמן של הל המפתחים הושקע בכתיבת אוטומציה. כמעט חצי מהזמן שהושקע בכתיבת קוד שנותן ערך לללקוח.

* טוב, זהו Case Study, ויש כל אינטרס להציג את התמונה בצורה אופטימית ככל האפשר. בואו נניח ששיפרו את הזמן שמושקע בקוד חדש - רק פי 4-5 בפועל.



יישום CD בצד הטכני


המפתח ליישום CD מההיבט הטכני הוא בניית ה Deployment Pipeline - הצינור בו מעבירים קוד ממערכת ה Source Control - לפרודקשיין.

כל שינוי ב Source Control מפעיל Trigger שגורם לבנייה של תוצר הקומפליציה. במקרה של פיתוח בענן (נניח AWS) - מדובר כנראה בבניה של ה AMI (קרי Amazon Machine Image) או Container, ממנו ניתן "להרים" מכונה בפרודקשיין בפקודה פשוטה. בשל הפופולאריות של Containers, אתייחס אליהם - אם כי ב Gett אני רגיל ביום-יום לעבוד עם AMIs.

נניח שאנו עובדים ב Github ויש לנו branch בשם master עליו מפתחים, ו branch בשם release שמתאר את מה שרץ בפרודקשיין.
חשוב להדגיש: הכוונה היא לא שנבצע merge ל release פעם בשבוע-שבועיים (או לסירוגין: בסוף ה Sprint) ואז יבנה ה Container. זה יהיה Automated Delivery - ולא Continuous Delivery!
הכוונה היא שבכל שינוי ב master (ואם יש כמה כאלה בטווח של דקה, אז אחת לכמה דקות) - ייבנה Container, הוא יופעל בסביבת ה Staging - ועליו המפתחים וה QA יבדקו את הקוד. סביבת ה Staging אמור לשקף את מצב הפיתוח הרגעי, כך שברגע שאנו מתכננים להשיק ("Ship") - יש לנו קוד במצב טוב.


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

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

עדיין חשוב מאוד הכלל שאומר: שמירת ה Pipeline עובד היא בעדיפות עליונה. על הארגון לעזוב הכל ולטפל ב Pipeline שבור - ממש כמו שמטפלים ב Production.

זכרו: הטיפול ב Deployment Pipeline הוא משני בדחיפות רק ל Production.

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


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



נקודות חשובות:
  • את ה Isolated Testing Environment - מרימים לכל Service לדקות בודדות של בדיקה. לא אכפת לנו להפעיל כמה וכמה כאלו במקביל. וירטואליזציה או קונטיינריזציה - היא פלטפורמת ההרצה הטבעית לסביבה הזו.
  • ה Integration Environment היא סביבה יחידה - בה ניתן לראות את התנהגות כל השירותים במצב ה dev שלהם ביחד. 
    • ה Integration Environment דומה ככל האפשר לפרודשיין:
      • התקנה מבוצעת באותו האופן: clusters, מכונות נפרדות, DB נפרדים, קונפיגורציה - כמו בפרודקשין.
      • ה Data מגיע מפרודקשיין, אך עובר ניקוי למידע פרטי (שלא צריך להיות נגיש לעובדים), או מיותר (למשל: טבלאות audit גדולות).
    • לכאורה זו סביבה שעלולה להיות מאוד לא יציבה (גרסאות שונות ומשונות רצות ביחד), אבל עם התבגרות ה pipeline היציבות שלה אמורה להשתפר משמעותית:
      • קוד מגיע אליה לאחר שעבר כבר סבב בדיקות.
      • תאימות לאחור היא תנאי מחייב.
      • עדיף מאוד לבצע deploy ב immutable deployment (על מכונה "נקייה" ולא "מלוכלכת") - containers או AMIs מאוד עוזרים כאן. אחרת - חשוב מנגנון reset לסביבה, והוא כנראה יופעל מפעם לפעם.
      • כאשר יש התנגשות בין שירותים - אפשר להחזיר אחד השירותים לגרסה קודמת, אבל השאיפה היא להציע מהיר תיקון ולהתקדם קדימה. Rollback הוא פשרה.
  • ה Staging Environment מאפשרת לבצע בדיקות אינטגרציה בין שירות נתון - למצב שיש כרגע בפרודקשיין.
    • לא נדיר להגיע לסט בדיקות שהרצת כל הבדיקות שבו אורך שעות רבות (ראיתי גם יממה ויותר) - ועל כן לא מריצים את כל הבדיקות. חשוב לדעת לכל שירות איזה subset של הבדיקות הוא מספיק טוב. כלל אצבע שאני מכיר הוא לחתור ללא יותר מ 10 דקות של בדיקות. כלומר: ייתכן וסך כל הבדיקות אורכות שעתיים או שלוש (כי אנו מקפידים על שיפורי הזמנים: מסירים בדיקות לא יעילות, ועובדים לקצר בדיקות ארוכות) - אך אנו יודעים לסמן לכל שירות איזה סט של בדיקות שנכנס ב-10 דקות הוא ה 80/20.
      • לפני שינויים רגישים במערכת - אפשר לסמן ל pipeline להריץ את הסט המלא של הבדיקות. שייקח שלוש שעות. אני מדבר על אירוע שאמור לקרות פעם בחודש בערך. אם השינויים שאנו מבצעים בקוד הם קטנים - אז הם לא כ"כ מסוכנים.
    • סביבת Staging יחידה תיצור, מן הסתם, תור ארוך ב pipeline - כי מפתחים רוצים להכניס שינויים כל הזמן. בכדי להשיג מקביליות של עבודה - יהיו כמה סביבות Staging שכאלו: 2, 3, 5, 10 - תלוי בגודל הארגון. בדיקות מהירות מאפשרות לנו להחזיק בפחות סביבות Staging.
    • ה Staging Environment דומה ככל האפשר לפרודקשיין:
      • התקנה מבוצעת באותו האופן: clusters, מכונות נפרדות, DB נפרדים, קונפיגורציה - כמו בפרודקשין.
      • ה Data יהיה לרוב Data שהוכן מראש לבדיקות האוטומציה.

רק לאחר שכל התהליכים האוטומטים הסתיימו (Isolated + Stating Environments), והתאפשרו בדיקות ידניות (של מפתחים / QA) על סביבת ה Integration (או Staging - לבקשתם) - ניתן לבצע את ההחלטה "לשחרר ל Production".


אם אתם זוכרים את הפוסט הקודם, כך זה נראה בצורה הפשטנית:



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

הנה תיאור קצת יותר מפורט של ה Pipeline שהראתי למעלה:


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

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

על כן נוסף שלב נוסף ב Pipeline בשם Rollback Test. הוא הולך בערך כך:
  • מתקינים את השירות בגרסה N (בצורה isolated) ומבצעים DB migration.
  • מבצעים Rollback: מתקינים את השירות מחדש בגרסה N-1 (ללא rollback ב DB).
  • מבצעים בדיקות Service/API של השירות בגרסה N-1 - לראות שהוא עובד בצורה תקינה.
כל התהליך הזה קורה במקביל לשאר התהליך והוא לא אמור להיכשל. אבל אם הוא נכשל - מונעים את היציאה של השירות הזה ל Production (עד שמתקנים את התאימות לאחור).

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

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


בהקמת ה Pipeline, וגם לאורך חייו, הארגון ישאל את עצמו שאלות שונות:
  • האם את הבדיקות הראשונות של המיקרו-שירות, לבצע במכונה בודדת (עם stubs) - או האם להרים landscape שלם? מישהו צריך לשלם על מכונות ה landscape - וזה ייקח יותר זמן.
  • כמה אנו מוכנים לחכות לבדיקות? יותר בדיקות = יותר בטחון, מצד שני - פחות יעילות וזמן תגובה לשינויים ב Production?
  • היכן לעשות בדיקות ידניות? בסביבת אינטגרציה - ואז לגלות בעיות אינטגרציה מוקדם יותר, או בסביבת Staging? ואז להגביר את הסיכוי למנוע את הבעיה הבאה בפרודקשיין? זו לא רק שאלה של עדיפות פילוסופית: פריון עבודה מול יציבות הפרודקשיין - זו שאלה כמה מנגנוני ה Rollback והבדיקות השונות יעילים, והיכן יש לפצות אותם?
  • האם להשקיע ב Load Tests כחלק מה Pipeline - או האם להסתמך על Canary Tests (בהמשך) עבור Load?
  • האם לבצע הרצה של כל הבדיקות האפשריות מדי פעם (על תצורה שהגיעה לפרודקשיין), גם אם סט הבדיקות לוקח שעות רבות? (פעמים רבות - עושים זאת).
  • ועוד ועוד...

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

את המונח Pipeline as Code ייתכן ותשמעו מהפרסומים של Jenkins 2.0 - שלכאורה עבר שינוי מהותי בכדי לתמוך ביכולות הללו. בפועל הוצגה מערכת Plugins שעדיין רחוקה מהאידאל של Pipeline as Code. מקביליות בהרצת בדיקות עדיין מבוססת בעיקרה על Plugins ואיננה יכולת ליבה של המערכת - וכך גם השגת הגמישות ב Pipeline עצמו. ניתן לומר (באופן מעט מרושע) ש Jenkins 2.0 היא מוצר Pipeline by Plugins.

Jenkins הוא עדיין כנראה הכלי הנפוץ ביותר לבניית Deployment Pipeline, אם כי כלים כמו Concourse CI או goCD ו gomatic - נחשבים למתאימים יותר לבניית ה Deployment Pipeline. ייתכן והגיע זמנו של Jenkins לפנות את כס המלכות.



עוד כמה רעיונות של CD שכדאי להכיר


Infrastructure as Code / Everything as Code - מכיוון שחשוב שהקונפיגורציה של המערכות תהיה זהה בין סביבות ה Staging וה Production, ומכיוון שחשוב שהקמת סביבה לפי אותה קונפיגורציה נתונה יהיה תהליך אוטומטי, מהיר, ואמין - הרעיון הוא שכל הגדרות המערכת, או מה שגורם להן יהיה מנוהל כמו קוד, ב Version Control System - אם אותה בקרה (למשל: pull requests) ותהליכים שמוכיחים את עצמם עבור קוד.
אלו חדשות ישנות כבר - אני מניח.


Blue/Green Deployment - הרעיון בו שחרור גרסה חדשה של שירות מבוצע באופן הבא:


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

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

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

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


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


Canary Release - הרעיון הזה הוא וריאציה של Blue/Green Deployment. 
הרעיון הוא לבצע את ההתקנה באותו האופן (נניח שהגרסה החדשה שהתקנתי היא על סט המכונות הכחולות), אבל להעביר רק כמות מזערית של תעבורה לסט הכחול: במקום 100% מהתעבורה - להעביר רק 1% מהתעבורה.

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

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


Dark Deployment - הרעיון כאן הוא שאין חובה ש Deployment יהיה גם בעצם Release.
פיצ'רים רבים במערכת - ניתן לשחרר אותם עם Feature Flag כבוי. הפיצ'ר הוא Deployed, אך לא Released.

למה לעשות את זה? בזמן הזה QA או המפתחים יכולים לבדוק את הפיצ'ר בפרודקשן, בסביבה הכי אמיתית עם תעבורה אמיתית. אפשר לעשות beta testing למשתמשים נבחרים - ולהכניס בפיצ'ר שיפורים, ורק כשהוא מוכן, בדוק, ויציב - לשחרר אותו.

כיום הפרקטיקה של Dark Deployment היא דיי מקובלת, גם אם מי שעושה זאת לא מכיר ולא משתמש המונח הרשמי :).


סיכום


שוחחנו על CD לא מעט - זה נושא גדול, שנוטה להעסיק את הארגון רבות.
עדיין לא שוחחנו על איך מתחילים בהטמעה של CD בארגון שלא רגיל לכך, ולא על Continuous Deployment: האם זה באמת רק דילוג על שלב ה manual tests?


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



יום רביעי, 16 בנובמבר 2016

אז... אתם רוצים Continuous Deployment?

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

Continuous Delivery היא כבר שאיפה סטנדרטית: כמעט כולם רוצים להיות שם. כ"כ הרבה נמצאים "בתהליך...". כרגיל...

בפוסט הזה אני רוצה לחזור ולדבר על הציפיות הסבירות מ CD, על המשמעות, המעבר, וכו׳...






הפשט


בדומיין שאנו מדברים עליו יש 3 פרקטיקות דומיננטיות, שנהוג לפרש אותן בערך כך:
  • Continuous Integration (בקיצור CI) - יש לנו שרת Build עם בדיקות אוטומטיות. כל כמה זמן (לילה?) - כל הבדיקות רצות ואנו מגלים אם יש בעיות בקוד - ואז מתקנים.
  • Continuous Delivery (בקיצור CD) - יש לנו שרת Build אוטומטי, שגם אורז את הקוד ל Delivery. למשל: בונה את ה ISO (אם אנו מפיצים את המערכת על DVD - פחחח) או Docker Image - שניתן להטמיע בפרודקשיין (SaaS או On-Premises).
  • Continuous Deployment (בקיצור גם CD, לצורך הפוסט אשתמש בקיצור CDD) - כמו Continuous Delivery, אבל ההחלטה לשלוח ל Production היא אוטומטית. כל קוד שנכנס למערכת - מגיע ל Production. לכאורה, תוספת קטנה לתהליך.

התיאור הזה הוא נכון בגדול - אך גם שטחי למדי.


נכון, אך פשטני משהו...
מקור: notafactoryanymore.com



מוטיבציה - אז למה לנו CD עכשיו...?


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


אני רוצה להרחיב מעט יותר על המוטיבציות:

צמצום אי-ודאות / סיכון

כשמנהלים פרויקט או מוצר בארגון, תמיד יש לנו חוסר ודאות מסוים: לפעמים הוא בינוני, ולפעמים - גדול.
  • חוסר ודאות מה הלקוחות צריכים -לפעמים הם בעצמם לא יודעים, ופשוט יש לראות כיצד הם משתמשים במוצר.
  • חוסר ודאות לגבי התוצאות של פעולות שנעשות - האם המעבר ל NoSQL DB יספק את ה Scalability הצפוי. האם ה Design החדש של מודול Y יעמוד יפה בשטף הדרישות העתידיות?
  • חוסר ודאות לגבי הבנת תוכנית הפעולה והתיאום בין אנשינו - כאשר האנשים שעובדים איתנו לא מבינים את אותה התוכנית - הם עלולים למשוך לכיוונים מנוגדים.
שווה לציין שהרעיון של Continuous Deployment קיבל תנופה גדולה מתנועת ה Lean Startup, שם צמצום מחזורי הלמידה והפידבק הם ערך מרכזי. הדרישה ל CDD, ע״פ המתודולוגיה, אמורה להגיע כיעד עסקי מה CEO - זה לא עניין ״פנימי״ של ה R&D...

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

התרבות הארגונית של אמזון, שגובתה בעזרת יכולות CDD, אפשרה למפתח שמאוד מאמין במשהו לבצע A/B test (על אוכלוסיה קטנה) - ולנסות להוכיח את צדקתו. כל אחד כמעט - יכול להציע ולהתניע ניסוי.
הניסוי הנ״ל הראה גידול של כ 3% במכירות (נתון מרשים מאוד!) - מה שהסיר מייד כל התנגדות, והפך אותו בן רגע לפיצ׳ר רצוי ע"י הפרודקט.

אם כולם מאמינים במערכת ובנתונים שהיא מייצרת,  אזי נתונים מהשטח הם ״מחסלי ויכוחים ארגוניים״.

CDD, אם כן, בשילוב A/B Tests ותרבות ארגונית מתאימה - מספקת Empowerment לעובדים, ויכולה להביא רעיונות חכמים שלהם - לידי יישום.

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



פישוט תהליכי ה Integration / Deploy

כשהחברה גדלה, תהליכי ה Integration וה Deploy הם לא פעם - כאב ראש רציני!

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

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

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

אין כאן קסם:

בתהליכי Integration/Deploy תקופתיים (נאמר: פעם בחודש) - משקיעים המון.
וגם בתהליכי CD - משקיעים המון.

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


מקור: http://www.mindtheproduct.com


יציבות

לאחר מעבר מוצלח ל CD/CDD, המערכות נוטות להיות יציבות יותר.
זה לכאורה פרדוקס: שינוי בפרודקשיין הוא סיכון - והנה אנחנו הולכים לעשות הרבה יותר כאלה. במקום שינוי בחודש, אולי כמה שינויים כל יום!
מצד שני, כשהשינויים הם מאוד קטנים - הסיכון מאוד קטן, יכולת האיתור של תקלות משתפר פלאים, וכמו שאומרים: Practice Makes Perfect. הרבה אימון בתהליך מאפשר להשתפר בצורה מהירה יותר.

מודל היציבות של CD הוא MTTR (קרי: Mean Time To Resolve) על פני מודל של MTBF (כלומר: Mean Time between Failures). יהיו לנו יותר תקלות במספר - אך הן יתוקנו מהר, וסה״כ ה downtime שלנו יהיה נמוך יותר.

שאלה מפורסמת ב Lean היא: "כמה עבודה עליכם לעשות בכדי לבצע Deploy של שורת קוד בודדת במערכת?" (כלומר: נזניח את תוכן השינוי, ואז - מהי התקורה על כל deploy של גרסה?). התרגיל הזה ידוע גם כ Single Line of Code DevOps Kata.

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

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

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

הגישה של CD נקראת: Bring the Pain forward (כמו באג'ייל).
אם זה כואב, עשו את זה בתכיפות רבה יותר - עד שתשתפרו וזה כבר לא יכאב.

בפועל, באימוץ CD אתם הולכים "לשבור דברים" כ"כ הרבה פעמים - כך שתוך כדי אתם צפויים לפתח יכולות Recovery טובות במיוחד ולשפר מאוד את ה MTTR. כמובן שחשוב מאוד לשבור דברים קטנים, ולהיות עם יכולת recovery כמעט מיידית, למשל: לסגור את ה feature flag או לחזור ל deployment הקודם תוך שניות (ע"י blue/green deployment - פרטים בהמשך).

המערכת לא תהיה יציבה יותר כי היא "תשבר פחות".
אם תציבו לארגון ה R&D מדד פנימי של "מינימום תקלות" - קרוב לוודאי שתהרגו את תהליך ה CD.

המדד צריך להיות: תוך כמה זמן אנו מתקלים תקלה, end-to-end: זיהוי התקלה עד אימות התיקון.

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






Continuous Integration (בקיצור: CI)


זהו הרעיון שקוד המערכת יהיה כל הזמן במצב תקין ("working state").

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

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

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

המדד המקובל ליישום CI הוא:
כל מפתח, מבצע בכל יום עבודה - לפחות פעם אחת merge של הקוד שלו ל branch המרכזי. (ועדיף: חמש פעמים)


(רמז: Jenkins לא גורם לזה לקרות.)

שימו לב: זה לא שכל מפתח מושך את ה branch המרכזי (נקרא לו לצורך הפוסט: master) ועושה merge לתוך ה feature branch. זה פחות מועיל / מלמד על שברים. העניין הוא לבצע merge לתוך ה master בכל יום.

Feature Branches? לא כ"כ מומלצים, אלא אם אתם מקפידים לבצע merge ל master.
זה מחייב את המפתחים לחשוב ביחידות קטנות, לפרק את הפיצ'ר לשלבים קטנים (שזה טוב - בפני עצמו), ולדאוג כל הזמן שהקוד הנכתב - לא שובר את המערכת.

מה קורה עם קוד שמשנה חלק גדול במערכת? איך אפשר לעשות merge כאשר הקוד לא "מוכן"? - פשוט הכניסו feature flag, ואל תדליקו אותו עד שהקוד מוכן. תחשבו איזה יופי יהיה להדליק את הפיצ'ר רק עבור המשתמש שלכם בפרודקשיין - ולבדוק איך הפיצ'ר עובד בלייב עם traffic/data אמיתי!

העיקרון החשוב השני של CI הוא:
כאשר ה Build נשבר - לתקן אותו זו עדיפות עליונה של הארגון. לפני כל דבר אחר.

יעד מקובל הוא תיקון תוך 10 דקות - לרוב ע"י rollback.
אפילו יותר טוב: בדקו את ה merge בצד, ורק לאחר שהצליח - בצעו את ה merge בפועל. השיטה הזו עובדת יותר טוב כאשר יש code bases קטנים (למשל: microservices) ואין race condition על merges.

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

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


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


בדיקות יחידה (Unit-Tests) או אינטגרציה (Integration-Tests) הגיעו לתהליך ה CI מאוחר יותר - והפכו לחזות עיקר התהליך. אין ספק: הן חשובות מאוד, ומועילות מאוד. מה היה קודם לכן? קומפליציה + בדיקת המערכת end-to-end (שאורכת זמן רב, ותופסת רק חלק מסוים מהבעיות).

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

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

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

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


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


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



סיכום


בפוסט זה ניסיתי להסביר מה הציפיות הסבירות מ CI/CD/CDD - תהליך חשוב שלאט הולך ומוטמע באמת בעוד ועוד חברות. אימוץ תהליכים אלו הם לרוב מאמץ ארגוני אינטנסיבי של חודשים - אבל גם השיפור עשוי להיות משמעותי למדי.

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


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



יום שני, 24 באוקטובר 2016

התקפת מניעת-שירות, וכיצד האינטרנט בחוף המזרחי - הושבת?

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

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


סצנה מתוך סרט "הציפורים" של היצ'קוק. מקור: http://www.filminamerica.com/Movies/TheBirds

כיצד נראית התקפת DoS?


להלן דוגמה פשוטה מאוד:

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

Refresh Monkey. הטאב יבצע refresh חמש פעמים בשנייה - ואני יכול גם לפתוח מאה טאבים כאלו.

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

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


--

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

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


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


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

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


מקור: Scudlayer



על DDoS ו SDoS


לאחר שהבנו כיצד התקפת DoS עובדת - מה בעצם המשמעות של DDoS, מונח שהוא כנראה אפילו יותר מוכר?

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

יתרה מכך, מנגנוני ההגנה המקובלים בפני התקפת DoS היא לזהות כמות לא סבירה של traffic ממשתמש יחיד - ואז לחסום אותו ברמה היעילה ביותר (למשל: לדחות בקשות ל tcp connection, הנדרש בכדי לבצע בקשת HTTP, על בסיס כתובת IP של השולח).

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




על מנת לייצר התקפת DDoS יעילה, עלי לאסוף אלפי מחשבים, אולי עשרות אלפים, ואולי יותר - שאולי לשלוט בהם. כל מחשב כזה נקרא Zombie, וצבא של זומבים נקרא גם BotNet. האיסוף מתבצע בד"כ ע"י נוזקה שתתוקן במחשב ותהיה במצב רדום - עד אשר ארצה לבצע את ההתקפה. הנוזקה לא צריכה "להשתלט על המחשב": היא רק צריכה להתקין agent שמאזין ל port מסוים ומאזין לפקודות משרת ההפעלה שלי. בעת ההתקפה, בעל המחשב כנראה לא ירגיש בכלל שהוא שותף להתקפה. לא יפריע לו - ולא יהיה לו טריגר לנסות ולהסיר את ה agent שלי.
את הנוזקה אני יכול להפיץ באתרי הורדות קבצים במשך חודשים או שנים - עד לרגע ההפעלה. מי שרוצה לקצר תהליכים ויש ברשותו משאבים - יכול גם לרכוש רשתות BOTNET בשוק העברייני, ממישהו שטרח והקים אותן.

בהתקפה שהתרחשה בימים האחרונים על Dyn - ספקית שירותי DNS ("ספר הטלפונים של האינטרנט") גדולה, השתמשו ברשת Mirai - רשת Botnets מוכרת, שכבר שימשה לכמה התקפות בעבר, אם כי לא בסדר גודל כזה (מקור).

ההתקפה על Dyn. מקור: TechCrunch

מה שהיה חדש יחסית בהתקפה הוא השימוש ב "מכשירים בסיסיים" או "דברים" (IoT - Internet Of Things) - לביצוע ההתקפה. כלומר: הזומבים ב Mirai Botnet הם טוסטרים, שואבי אבק, מצלמות אבטחה - רכיבים שונים בעלי גישה לאינטרנט. הנוזקה "Mirai" סורקת את האינטרנט וברגע שמזהה מכשיר שכזה מנסה להתחבר אליו כ Admin בעזרת רשימה של users/passwords נפוצים שיש ברשותה. אלו הם לרוב ה defaults שמסופקים מהיצרן או שם וססמה קבועים - שלא ניתן בכלל להחליף.

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

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


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

SDoS הם ראשי תיבות של Self Denial of Serive (מושג מקביל: Unintended Denial of Service) בהם ארגון מייצר לעצמו traffic שהוא לא מסוגל לעמוד בו - ואז נאלץ לדחות (= לא לספק שירות), לכמות גדולה של משתמשים לגיטימיים.

דוגמה קלאסית: קמפיין שיווקי שלא תואם (או אולי תואם, ותוצאותיו לא נצפו ע"י ה R&D/Operations) - שמגדיל את התעבורה פי כמה מונים - אך המערכת לא יכולה לעמוד בכמות ה traffic שנוצר.

פאדיחות.


בהתקפת DoS/DDoS זה מה שאתם רוצים שבעלי האתר יראו: פחות traffic מטופל, וזה שמטופל - הוא איטי ומציק.
מקור התמונה: New Relic


סגנונות תקיפה נפוצים


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


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


HTTP Flood

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

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

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

טריק פשוט ומקובל הוא לייצר אלמנט אקראי (למשל: ב query string) ב URL - שיגרום ל CDN לחשוב שאין לו את המשאב - ולהעביר את הבקשה ישירות לאתר.
למשל:

https://feed_a_cat.co.il/comprehensive-cats-report?random=198982

הרכיב "random=198982" ב URL כמעט ואף פעם לא יגרום לשרת לדחות את הבקשה (מי מתגונן בצורה כ"כ הדוקה?) - ובד"כ יגרום ל CDN לחשוב שמדובר במשאב ייחודי שלא נמצא אצלו ב Cache.



התקפות רזות: SYN Flood ו UDP-Based

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

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

הרעיון של התקפות אלו הוא להימנע מיצירת ה TCP connection, שהיצירה שלו אורכת זמן (גוזלת מהמתקיף משאבים) - ואז יש יעד ברור לתשובה.
להזכיר: TCP Connection הוא הבסיס לביצוע HTTP Request. לא יהיו לנו בקשות HTTP בסגנון ההתקפה הזה.

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

אולי אפילו טוב יותר: הוא לא יענה במשך זמן ממושך (או בכלל) - ואז המערכת אותה תקפנו לא תוכל בכל הזמן הזה לשחרר את המשאבים שהקצתה לצורך ה connection. רוב המערכות יחכו כמה שניות ואז יוותרו על המאמץ לייצר connection, מערכת שלא עושה זאת (אין לה timeout) - היא פשוט טרף קל!

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

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

אפשר לבצע Ping / Echo ולתת לשרת לענות. אפשר לנסות Pings עם payload גדול - שעשויים להקשות על השרת המרוחק, ואפשר (זה ממש מרושע) לנסות לשקר שכתובת ה IP שלנו היא כתובת של שרת אחר ב cluster של המערכת המותקפת - ואז לתת לשרתים השונים של המערכת לבצע ping בינם לבין עצמם...

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



התקפות Amplification (הגברה)

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

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

בעקבות צפיפות גבוהה של התקפות DDoS שנעזרו בשרתי DNS הופעל לחץ כבד על ספקי ה DNS לשכלל את ההגנות שלהם, ולא לענות לכמות גדולה של Queries מורכבים שמגיעים לפתע למערכת.

מגברים "טבעיים" אחרים שניתן למצוא ברשת האינטרנט כוללים:
  • שרתים שעונים לפרוטוקול SNMP (פרוטוקול ניהול רשת) - היחס בין גודל הבקשה לגודל התשובה יכול להגיע לעד פי 600, יותר! לרוע המזל, אין הרבה שירותי SNMP שפתוחים לאינטרנט הרחב...
  • שירותי NTP (כלומר: Network Time Protocol, הפרוטוקול בעזרתו שרתים מסתנכרנים על השעה הנכונה) - הם יעד פופולארי. פקודת monlist של הפרוטוקול (המחזירה רשימה של 600 השרתים האחרונים שביקשו שירות) היא בעלת יחס החזרה של פי 200.
  • מערכות Peer to Peer - שניתן למצוא פרצה ולבלבל את כל ה Peer שאנו מתקשרים איתם באותו הרגע ולחשוב שהשרת המותקף הוא בעצם אני. הם עלולים לנסות שוב ושוב עד שיקבלו את התשובה שהם מצפים לה...
  • וכו'

התקפות הגברה נמדדות לרוב בכמות ה Bandwidth שהן מייצרות. השיאים נשברים כל הזמן, והשיא הידוע לי הוא 602 Gbps - כלומר: traffic של 602 ג'יגהביט בשנייה (או 75 ג'יגהבייט בשנייה). שיא שבוודאי יישבר.





סיכום


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

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

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


כיצד מתגוננים?
  • מעבירים את התעבורה לאתר דרך שירות שיודע לזהות ולסנן traffic של התקפת DDoS (כמו CloudFlare או Akamai) . שירות כזה עולה כסף, אך הוא מסוגל לאתר ולמנוע מכם את רוב ה traffic של התקפת DDoS. 
  • חוסמים לגישה מהאינטרנט כל port או endpoint שאינו הכרחי.
  • בונים את המערכת כך שיהיה ניתן להשבית (disable) בקלות מנגנונים יקרים במשאבים של המערכת. בעת התקפה, עדיף לאבד יכולת או שתיים של המערכת - מאשר את כל המערכת.


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




יום שלישי, 4 באוקטובר 2016

REST ו RESTful APIs - גרסת 2016

איי שם בשנת 2011 כתבתי פוסט על REST ו RESTful APIs. פוסט שנצפה דיי הרבה פעמים, וגם עורר שאלות ותגובות. לפני כשבוע שאל אותי עוד מישהו על אחת הדוגמאות שנתתי. דוגמה כיצד לא-לכתוב REST Endpoint.

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

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

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

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

מה כ"כ חזק ברעיונות ה REST שגרם לשינוי האדיר הזה?
מדוע פרוטוקולים "נבונים" יותר ו"מעודכנים" יותר, כמו GData, OData, או JSON API - לא זוכים לכזו תהודה?
מה סוד הקסם של REST?

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

כלומר: אפשר לומר שמרבית התעשייה עובדת עם "פסדו-REST", ורק חלקים קטנים יותר עובדים עם "REST תקני" או אפילו "REST תקני חלקית".
אם נשווה את מספר המשתמשים ב "REST תקני (חלקית)" - סדרי הגודל של המשתמשים דומים כנראה למספרי השמתמשים בפרוטוקולים חלופיים, קרי JSON API, OData, GData, או Thrift (שפותח במקור ע"י פייסבוק).

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




מה הרעיון ב REST?


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

בגישה זו, יש מספר לא מבוטל של יתרונות:
  • ל HTTP יש המון ספריות, לכל שפת תכנות בערך, והרבה אנשים מכירים אותו לעומק. (אם אתם לא מכירים - זה זמן טוב לקורא את הפוסט בנושא!)
  • אם נפעל בהתאם ל HTTP, נוכל להינות בהשקעה קטנה מצידנו מ Caching שרכיבי הרשת השונים כבר מספקים (Proxies, gateways, CDNs, וכו').
  • רכיבי אבטחת רשת מקובלים (IDS או WAF) מכירים HTTP. הנה לנו פרוטוקול שכבר יש לו תמיכה בלא-מעט כלי אבטחה.
  • HTTP הוא פשוט ויעיל. מתחת למכסה המנוע הוא פשוט כמה headers שנשלחים לפני ההודעה על גבי חיבור ה TCP.
  • HTTP הוא stateless (ברובו הגדול), וה Scalability שלו היא מוכחת! (ה world wide web, דאא)
  • HTTP קל לניטור והבנה (יש הרבה כלים + הוא מבוסס clear text).


ע"פ ההגדרות הפורמאליות, REST אינו בהכרח קשור ל HTTP. הוא מבסס עקרונות (או Constraints) של ה API של המערכת, שדומים מאוד לאלו של רשת האינטרנט:
  • תקשורת שרת-לקוח
  • ה API הוא Stateless
  • ניתן לבצע Cache לבקשות
  • ממשק אחיד, לכלל המערכת:
    • מבוסס מיפוי של משאבים (כלל מנחה: שמם מורכב משמות-עצם)
    • על כל המשאבים ניתן לבצע סט מוגדר של פעולות: קריאה, כתיבה, עדכון, וכו'. (דומה מאוד ל HTTP GET, HTTP POST, וכו').
    • ה API מתאר את עצמו - ולקוח ה API משתמש בתיאור זה בצורה "גנרית" על מנת להשתמש ב API.

כיצד הסתירה הזו מתיישבת? נסביר בהמשך.







היסטוריה: כיצד נולד ה REST?


רעיונות ה REST הופיעו בפעם הראשונה בעבודת הדוקטורט של Roy T. Fielding, חבר בצוות שהגדיר את פרוטוקול ה HTTP וכן co-author של ה Apache Web Server.

עבודת הדוקטורט של פידלינג עסקה באפיון של רעיון שנקרא "סגנונות ארכיטקטוניים", מן דפוסים מרכזיים וחוזרים בארכיטקטורות של תוכנות שונות. בפרק מספר 5 בעבודה הוא תיאר סגנון ארכיטקטוני בשם (Representational State Transfer (REST - אימוץ העקרונות מאחורי ה world wide web, על מנת לתקשר בין שרתים.

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

כמה שנים לאחר מכן, ב 2003 עד 2005 בערך - העולם נכנס לסערה של Service Oriented Architecture (בקיצור: SOA) והרעיון של Web Services (רשימת תקנים בשם *-WS).
אפשר להשוות את ההשפעה של SOA לאופנה הנוכחית של Microservices. לי, כמפתח צעיר, הרעיונות נשמעו מלהיבים וגדולים - ובחברה שעבדתי בה באותה התקופה החליטו "לא לפגר מאחור - ולאמץ SOA עד הסוף". כמובן שלי ולחברי לא היה מושג בדיוק כיצד להוציא מ SOA את המיטב - ופשוט מימשנו SOA ו Web Services.

Web-Services היו הפשטה גבוהה ועשירה/מסובכת מעל הפרימיטיביים של הווב. היה שם XMLs גדולים ומורכבים, שנעטפו בתוך XML נוסף (ה envelope) שהיה חלק מפרוטוקול התקשורת - SOAP, ותוארו ע"י פורמט שנקרא WSDL והופץ על גבי פרוטוקול בשם UDDI ואז היה ניתן להשתמש בכלי בשם DISCO על מנת למצוא אותם. וזה היה רק הבסיס.

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

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

ב 2004 ה W3C (ארגון התקינה של האינטרנט) הוציא מסמך שדן בארכיטקטורות אינטרנט. לקראת סוף המסמך, הופיעה פסקה קצרה המרחיבה את ההגדרה של Web Services: היא גם ציינה את REST כבסיס התיאורטי לפעולת ה Web Services, וגם ציין שהם יכולים להיות בלתי-תלויים בפרוטוקולים כמו WSDL או SOAP.

יריית הפתיחה נורתה, ושני מחנות החלו להיווצר:
  • אלו התומכים ב Web Services ע"פ סט תקני ה *-WS.
  • אלו התמוכים ב RESTful Web Services, כלומר: עלינו רק לתאום לכללי ה REST - וזהו Web Service בר-תוקף, בהכשרת ה W3C!
על עצם הצורך בהגדרה של Web Services, או של SOA - אף אחד לא ערער. זה היה באזז חזק שלא ניתן להתכחש לו.
היום כמעט כבר אין ממש זכר ל *-WS, ומעט מאוד מ SOA. הקונצנזוס הגדול התעשייה הוא סביב REST - כאשר עדיין יש הרבה חוסר הבנה מסביב לעקרונות הללו.


קצת עזרה מידידנו ריצארדסון


את חוסר ההבנה ב REST, ניסה קצת להבהיר / לסדר בחור בשם לאונרד ריצרדסון.

ריצרדסון הוא המחבר של שני ספרים מוכרים (הוצאת O'Reilly):
  • RESTful Web Services - 2007
  • RESTful Web APIs - 2013
בהרצאה בכנס QCON-2008, ריצרדסון הציג מודל בגרות של אימוץ רעיונות ה REST:

מקור: http://www.slideshare.net/josdirksen/rest-from-get-to-hateoas


רמה 0 - הביצה של POX (קיצור של Plain Old XML. פורמט ה XML היה בזמנו יותר פופולרי מ JSON)

רמה זו מתארת שימוש ב HTTP בכדי להעביר קבצי JSON או XML, נניח תמיד במתודת HTTP POST. זה יישום פשוט, Freestyle (שזה סוד הקסם שלו) - אך זה לא REST.

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



רמה 1 - מיפוי משאבים

ברמה זו אנו מקפידים על תיאור של ה URIs כך שיתארו משאבים. עבור הווב של משתמשי הקצה משאבים הם מסמכים: html, js, או css. עבור API - משאבים הם דומים יותר לאובייקטים, או חלקים בתוך האובייקטים.

בעוד שיכולנו לתאר API של מערכת לניהול כנסים כ:

  • POST /create_session
  • POST /set-session-title
מיפוי של משאבים יתייחס לקריאות הללו בצורה בה מתייחסים למשאבים:
  • POST /sessions/create
  • POST /sessions/<session_id>/title

מכיוון שה title שייך ל session, אנו מרכיבים את ה URI בצורה היררכית - כך ש session קודם (ולכן "מכיל") את ה title. כלומר: כל "/" מתאר בהכרח רמה היררכית של מבנה המשאבים.


מיפוי המשאבים מציב כל מיני דילמות, שאין להן תשובה חד משמעית:
  • כאשר אין קשר היררכיי ברור בין ה resources  - מה הסדר הנכון?
    • למשל: הזמנת-נסיעה ונהג - מי מכיל את מי? (בהנחה שכל אחד מהם הוא אובייקט שחי בפני עצמו. הזמנת-נסיעה נוצרת בלי קשר להשמה לנהג).
  • רזולוציה: האם למפות כל תכונה של אובייקט (למשל: title) לresource שיש לו URI משלו, או פשוט להסתפק ב sessions/update/ עבור כל התכונות יחדיו (בהתאם לפרמטרים שנשלחים בבקשה)?
  • כיצד לתאר גרסאות שונות של ה API? כחלק מה URI או כפרמטר?
  • ועוד...


רמה 2 - שימוש ב HTTP Verbs (ו Status Codes)

שימוש ב Method (נקראים גם Verbs) של פרוטוקול HTTP בכדי לתאר את הסמנטיקה של הפעולה:
  • GET - על מנת לבקש את ה state של המשאב אליו מפנה ה URI.
  • POST - על מנת לשלוח content ("נתונים"/"הודעה") למשאב לצורך עיבוד, עיבוד שייתכן וישנה את ה state של המשאב. לעתים הודעה זו תיצור תת-משאב (ואז נהוג להחזיר Status Code של 201 - "נוצר").
  • PUT - על מנת להחליף (rebind - "רישום מחדש") של התוכן של המשאב.
  • PATCH - על מנת לבצע עדכון חלקי של ה state של המשאב.
  • DELETE - על מנת למחוק את המשאב.
ניתן כמובן להשתמש גם במתודות האחרות של פרוטוקול ה HTTP,קרי HEAD, OPTIONS, TRACE - אולם הגדרת ההתנהגות שלהן עבור REST API היא פחות ברורה ויותר פתוחה לפרשנות.

כלל חשוב נוסף הוא שאין חובה לתמוך בכל 4 הפעולות הבסיסיות על כל משאב. ייתכן משאב שעליו ניתן לבצע רק GET ומשאב אחר שעליו אפשר לבצע רק POST. מצד שני הגדרת ה URI מחייבת שכל צומת מתאר משאב שניתן לגשת אליו. לדוגמה, אם הגדרתי משאב כ:

http://example.com/orders/2009/10/776654

אזי גם ה URIs הבאים צריכים להיות ברי-קיום:

http://example.com/orders/2009/10
http://example.com/orders/2009
http://example.com/orders
http://example.com

יתרון גדול בשימוש ב HTTP Verbs היא "קבלת Caching" בעלות מזערית. רכיבי רשת רבים: שרתי ווב, CDNs, רכיבי פרוקסי ו Gateway - מודעים ומכבדים את ה Verbs הללו. אם אנו עושים הרבה GET (ובעיקר: מוסיפים גם headers נכונים) - התשובה תהיה cached ב"רשת". כאשר נבצע POST לאותו משאב - ה caches יתנקו.

יתרון נוסף הוא שרכיבי אבטחת רשת IDS, WAF, ועוד - מודעים לבקשות הללו ול HTTP error codes - יודעים על פיהן להסיק ולזהות התנהגות חריגה / מסוכנת ברשת שלנו.

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

ההתנהגויות המוגדרות של HTTP verbs השונים. מקור: Lynda.com

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

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

"...Reunite the programmable web with the human Web... a World Wide Web that runs on one set of servers, uses one set of protocols, and obeys one set of design principles"
 -- Richardson & Ruby, RESTful web services, 2007.




רמה 3 - Hypermedia Controls

שמות נרדפים: Hypermedia transformations או Hypermedia As the Engine Of Application State (בקיצור: HATEOAS)

רעיון זה טוען שעל פעולה ב REST למשאב צריכה לתאר את פעולות ההמשך האפשריות כ links לפעולות הללו.
כשאנו גולשים באינטרנט, אנו הולכים למשאב מרכזי, למשל: https://www.bankhapoalim.co.il - ומשם אנו משתמשים בקישורים על מנת לבצע את שאר הפעולות: כניסה לחשבון, ביצוע העברה בנקאית, שליחת טופס לנציג הבנקאי האישי שביצענו טעות בהעברה הבנקאית (!!) - וכו'...

באופן דומה, הרעיון ב REST הוא שהתוכנה בצד השני (ה Client) לא "תדע" אלו פעולות זמינות, אלא תלמד אותן מהתשובה. למשל:



התשובה שלנו לכל קריאה, מכילה גם links שהם תיאור של הפעולות האפשריות. self למשל היא הפעולה הנוכחית, כאשר אני גם יכול לבצע product.search - ויש בידי את ה URI המתאים לביצוע התחזוקה.

עוד השלכה חשובה של ה HATEOAS היא שכל פנייה לשרת צריכה לפתוח בקריאת GET (או OPTIONS - לדקדקנים), ורק אחריה קריאת POST או PUT וכו'. יש מערכות שמסתמכות על ההנחה הזו.


משתמש אנושי יכול באמת להבין מה המשמעות של "product.search", אבל מה מכונה מבינה מזה? ישנן שתי אופציות:
  • המכונה מכירה את כל ערכי ה rel האפשריים - ולכן יודעת לפעול על פיהם.
  • המכונה לא מבינה.
הפער הזה נקרא ה Semantic Gap, עניין שאנשי ה Semantic Web (מספרם קצת הצטמצם בשנים האחרונות, לא?) - מנסים לפתור.

ישנם פרוטוקולים כמו XMDP או ALPS לתיאור סמנטיקה של פעולות API. מן שפות של meta descriptions.

מי שממשיך ומתקדם מעל רמה 3 - ראוי להיכנס להיכל התהילה של REST, כמי שיישם את מודל ה REST בצורתו הטהורה ביותר!



ספר על REST? - יש עשרות רבות...


מודל ה REST בפועל


האם זה הגיוני ליישם את שלב 3 במודל של ריצ'רדסון, Hypermedia Controls?
אם אתם מפתחים מערכת ווב טיפוסית - ברור שלא!

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

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

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

לדעתי האישית, אין טעם ברמה 1 ללא רמה 2: מיפוי משאבים ללא שימוש ב Verbs הוא אנמי וחסר. הייתי ממליץ על רמה 2 או 0, עם הסתייגויות.

ההסתייגויות הן שכללים רבים של "REST טהור" עשויים להיות פשוט לא יעילים ליישום במערכת שלכם. הם יכולים לגזול זמן מיותר - ולספק מעט תועלת.

הנה כמה כללים שאנחנו נוהגים להתעלם מהם במערכת הקיימת שלנו (בידיעה):
  • הפער הגדול ביותר: אנו משתמשים בפעולות POST גם לצורך קריאות שלא משנות את ה state של האובייקט. פשוט כמו GET שמכיל payload גדול יותר, אפילו אם לא מתבצע processing מורכב מאחורי הקלעים.
    • זה אומר ששברנו כמה כללים של ה HTTP: חלק מקריאות ה POST הן עכשיו cacheable ו idempotent.
    • מצד שני: שרשור של פרמטרים ה URL זה פחות קל, ופחות קריא. הכי מעצבן היה לגלות שוב ושוב חסימות לאורך ה URL ברכיבי הרשת השונים: פעם ב WAF, פעם nginx - ופעם ב Load Balancer. אמנם אין הגבלה בתקן ה HTTP עצמו, אבל כנראה שבעקבות הדפדפנים שנהגו להגביל את אורך ה URL - נראה שגם רכיבי הרשת אמצו, כברירת מחדל, את המסורת...
  • לא כל חלק של URI הוא בר-תוקף. ייתכן וישנו URI בשם {companies/{id}/roles/{role_id/ מבלי שיש ל companies/{id}/roles/ כל תוקף. למה לנו לפתח API שאף אחד לא הולך לקרוא לו?
  • אנחנו משלבים שמות של פעולות, ולא רק משאבים ב URI. אנחנו משלבים אותן בסוף, כמעט-תמיד. למשל:
    areas/by_point ו areas/by_rectangle
  • אם פעולה יצרה משאב חדש, אנו לא מחזירים header של location עם ה URI למשאב שנוצר. הרבה יותר פשוט להחזיר id של האובייקט החדש בתוך ה JSON של התשובה.
  • ויש כנראה עוד...

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

כמו שאני נוהג להטיף, גם כאן אני מציע: השתמשו בכל כלי בצורה שהכי מועילה לכם, ולא ע"פ כלל שרשום איפשהו.

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

אנו כן מקפידים ב REST לשמור על הכללים הבסיסיים:
  • למדל בצורה סמנטית (קרי - ברורה מפתח) ובחשיבה על resources במבנה היררכי את URIs שאנו משתמשים בהם.
  • להקפיד על שימוש ב Verbs של HTTP ועל Status Codes בסמנטיקה שהוגדרה להם. אנו לא משתמשים ב Verbs ו Status Codes שאינם חלק מתקן ה HTTP (על אף שתקן ה HTTP עצמו - מותיר זאת).
  • להיות "Good Citizens", ולהתאים את התנהגות ה APIs שלנו לכללי ה HTTP במידת האפשר.

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




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


---

קישורים רלוונטיים

הבלוג של מרטין פאוולר, על Richardson Maturity Model ו REST:
http://martinfowler.com/articles/richardsonMaturityModel.html

מצגת נחמדה שמתארת כמה מהבעיות שעלולות לצוץ ביישום REST (הרשאות, גרסאות שונות של API, טיפול בשגיאות, וכו'):
http://www.slideshare.net/MasoudKalali/masoudkalalirest-new-format


יום שישי, 26 באוגוסט 2016

Lean Startup - איך לגדל מוצרים מצליחים?

בספר The Lean Startup, אריק ריס מספר על חברה שהקים בשם IMVU. הרעיון שלה (פלוס מינוס) היה לייצר צ'ט שיש בו Avatar - מן דמות תלת-מימדית מונפשת שמתלווה לשיחה המתהווה ומעצימה את הצד הרגשי של השיחה. ניתן לפתח את הדמות (להלביש אותה, לעשות איתה כל מיני מחוות) כל שהמוצר הוא בעצם חצי צ'ט - וחצי משחק Second Life / The Sims.

שוק ה Instant Messaging (בקיצור IM) היה גדול מאוד ומבוסס באותה התקופה. מכיוון שמדובר במודל של Marketplace (בו הערך של המוצר הוא "כמספר המשתמשים בריבוע") - לא היה טעם להתחיל מאפס: מה טוב Chat Client שאין לי עם מי לדבר בו? האסטרטגיה המבריקה של החברה הייתה למשוך משתמשים בעזרת ה Avatar / הצד המשחקי של הצ'ט - וכך לגרום להם להעביר אט אט חברים לרשת ה IM החדשה.
החברה תייצר Client שיוכל להתחבר לרשתות IM קיימות - כי שם הרי כל החברים שלכם.
שיחה שתתבצע בעזרת שני משתמשים עם ה Client של IMVU - יתווסף עליה מימד ה Avatars.

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

(טוב, אופס! הייתה בעיה בכפתור ההורדה.) - מה שתוקן מייד ואז החלו ההורדות: 3, 7, 11, 23, 38, 43, 49, 65, 77, ... וכך המספר עלה. עשרות הורדות, אח"כ כמה מאות - שום דבר שדומה לציפיות על עשרות-אלפי משתמשים.

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

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

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

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

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

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

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

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

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

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






מתודולוגיית ה Lean Startup


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

מתודולוגית ה Lean Startup היא אחד החידושים המרעננים והחשובים (לדעתי) בעולם התוכנה בשנים האחרונות.


לכאורה, נראה שמדובר בעוד מתודולוגיית Agile.
מדוע אנו זקוקים ל*עוד* מתודולוגיית Agile?? האם לא מיצינו כבר את הכיוון הזה?


עיון בעקרונות ה Agile (ליתר דיוק: Lean [א]) הוא: ״Eliminate waste" - להתמקד בביטול פעולות לא-נחוצות כאמצעי לשיפור הפריון של הארגון.

מהו waste?
  • תכנון לקוי - בואו נשפר אותו.
  • ישיבות ארוכות - בואו נגביל אותן בזמן (timeboxing - רעיון דומיננטי של סקראם).
  • שכבות ניהול מיותרות - בואו נבטל אותן ונעצים את הצוות.
  • באגים שצצים בפרודקשיין - בואו נעשה מאמץ לאתר אותם מוקדם יותר.
  • וכו׳

כל אלה נושאים חשובים וטובים. הם שיפורים חיוביים, אבל הם לא מתמודדים עם "ה waste הגדול מכולם" או ה BWoA (קרי: Biggest Waste of All).

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


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

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

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

במקום זה, יותר יעיל למדוד למה באמת אנשים מגיבים (מעשים > דיבורים) - בעזרת סדרה של ניסויים.





במעט סרקזם, ניתן לומר שאם תשאלו אנשים מה חסר להם בסקראם - הם יובילו אתכם ל LeSS או SAFe [ב], אם תבחנו מה שורש הבעיה של ארגוני-תוכנה - תגיעו ל Lean Startup.



אז מה הוא בעצם ה BWoA?


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

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

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


"Fail early, Fail fast"

החשבון הוא פשוט:
  • אם השקענו שנה, בפיתוח של מוצר לא מצליח - אזי בזבזנו שנים-עשר חודשי פיתוח!
  • נניח שבעזרת ניהול פרויקט נכון יותר, ניהול ישיבות יעיל, ושלל תהליכים אותו פרויקט - סיימנו את הפרויקט הנ"ל בתשעה חודשים (נניח באופטימיות). אם זה לא פרויקט מצליח - עדיין בזבזנו תשעה חודשי פיתוח!
  • אם השקענו 100,000 שקל אצל מגדת עתידות שאמרה לנו בוודאות שהפרויקט ייכשל - אזי בזבזנו רק 100,000 ש"ח. חודשי פיתוח של צוות פיתוח הם יקרים הרבה יותר! הזמן שהתבזבז - עשוי להיות יקר יותר מכסף.
מכיוון שאין לנו בתעשיית התוכנה מגדת-עתידות אמינה, אנו נשקיע זמן פיתוח בפיתוח של Minimal Viable Product (בקיצור: MVP). המוצר הזה יאמר לנו בהשקעה קטנה ואמינות גבוהה (אם עשינו אותו נכון) - האם המוצר השלם הולך להצליח (ואז שווה להמשיך ולהשקיע בו) או האם עלינו לשנות כיוון משמעותי (מה שנקרא גם "Pivot" - "שינוי ציר התנועה").

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

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





Lean Starup היא מתודולוגיית פיתוח ״רזה״, המבוססת על רעיונות של חשיבה מדעית, המתמקדת בעיקר בשאלה: כיצד נצמצם למינימום את ההשקעה במוצרים/פיצ׳רים לא מוצלחים?

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

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

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

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

דוגמה אהובה היא הסיפור של חברת SnapTax, שביצעה במשך חודשיים וחצי בסוף השנה (תקופת חישוב המס בארה"ב) כ 500 ניסויים שונים על אופן השימוש המוצר שלה - זה אומר כ 11 ניסויים שונים שמתחילים כל יום!
אם היה ספק: רעיון ה Continuous Deployment (בניגוד ל Delivery) - נולד כחלק ממתודולוגית ה Lean Startup: ביצוע ניסויים הוא צורך קיומי של החברה, ולא ניתן לבצע ביצועים ברצף ללא ביצוע שינויים תכופים בסביבת הפרודקשיין. מי שאמור לדאוג לקיום של ה Continuous Deployment הם א
לא המפתחים - אלא ה CEO.

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

משהו שאין בתרשים: אם ב Agile אנו מתקדמים בכיוון כמעט אחיד ועושים שינויים בעיקר בסדרי העדיפויות / שינויים קטנים במוצר לאורך הזמן, ב Lean Startup המסלול, לפחות בהתחלה, הוא הרבה יותר כאוטי: שינוי הלקוחות שאנו פונים אליהם, ביטול או שינוי מהותי ליכולות עיקריות של המוצר, או אפילו כתיבה מחדש - של חלקים או כל המערכת. זמן פיתוח משמעותי מושקע בניסויים ואיסוף התוצאות שלהם - ולא רק בפיצ'רים. המדד להצלחה הוא לא כמה "Story Points" השגנו בזמן נתון - אלא כמה למידה משמעותית.

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



כיצד נראה תהליך של Lean Startup?


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

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

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

לאחר מכן הוא שכלל את האתר, ועשה A/B Test - "תיאור מוצר א'" מול "תיאור מוצר ב'". "תיאור מוצר ב' מול תיאור מוצר ב'2" - וכו'.

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

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

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


Zappos

עוד סיפור מפורסם של Lean Startup הוא הסיפור של זאפוס - היום חנות הנעליים הגדולה בעולם, עם מחזור מוערך של כ 2 מיליארד דולר בשנה (ב 2009 היא נרכשה ע"י אמזון).

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

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

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

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

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

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







מיתוס המנהיג בעל החזון המושלם.


ההסתייגות הראשונה לרעיונות ה Lean Startup מגיעה מסיפורים על איש אחד: סטיב ג'ובס.

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

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

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

יש גם כמה קווי דמיון שניתן למצוא בין הגישה של אפל ל Lean Startup:
  • כשאפל הציגה מוצרים לראשונה, היו להם כמה תכונות פורצות דרך - אבל גם הרבה תכונות מביכות. חשבו על השעון: מה עושים איתו? זהו פסודו-MVP: אפל שחררה מוקדם יותר - על חשבון ליטוש "המוצר המושלם".
    • שחרור ה iPod הראשון רק למשתמשי מק (בעלי חיבור firewire, לא היה לiPod חיבור USB) - עזר לאפל ללמוד הרבה, מקהל מוגבל יחסית - שהם מכירים היטב.
    • ה Clickwheel המפורסם של ה iPad הופיע קודם בדגם ה iPod Mini, ורק לאחר שהוכח כמוצלח - הועבר לדגם הרגיל ממנו היו רוב ההכנסות של אפל.
  • יחסית למוצר חומרה, אפל עובדת ב cycles קצרים: שחרור כל שנה. בכל cycle - יש כמה שיפורים משמעותיים. זה עניין של פוקוס - לעשות כמה דברים אבל טוב, ולא המון פיצ'רים לא-חשובים.

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




ביקורת 


תגובה צפויה להעלאת רעיונות ה Lean Startup היא: "זה נשמע נהדר - אבל זה לא מתאים לנו".

התירוצים הנפוצים הם:
  • כי המתחרים יעתיקו את הרעיון אם נחשוף אותו בניסויים מוקדמים.   
    • תשובה: הם כמעט תמיד מתעלמים ממה שאין לו עדין נתח שוק, ולהעתיק בלי הבנה מעמיקה - זה לרוב לא שווה הרבה. אם ניתן להעתיק את הרעיון בקלות - אז זה יקרה גם אחרי שיצאתם לשוק.
  • כי אנחנו חברה גדולה שחושבת בגדול - ואין לנו זמן ל"ביצוע ניסויים".
    • תשובה: כן, אבל לשרוף שנת פיתוח של 50 מתכנתים יש לנו זמן?
  • כי אין לנו כוח אדם מתאים: יש לנו מתכנתים - לא אנשי מחקר שוק. 
    • תשובה: רבים מהמתכנתים יכולים ללמוד לעשות את זה. זה מעניין, מאתגר, ומאוד מספק.
  • כי שחרור של גרסה מינימלית יפגע בשם הטוב שלנו - אסור ל Brand שלנו להוציא מוצר פחות מ"מענג".
    • תשובה: זה לרוב תירוץ. אפשר להוציא כ"בטא" או "אלפא", אפשר להוציא את הניסוי תחת מיתוג אחר של "חברת-בת לא ידועה".
  • לא יאשרו לנו בחיים לעבוד ככה. יש תהליכים בחברה.
    • תשובה: זו באמת בעיה. בעיה של החברה.
  • זה בכלל לא מתאים לחברות גדולות. זה ה Lean Startup.
    • תשובה: הכל בראש. אם HP וממשלת ארה"ב מסוגלות - אז גם חברה קטנה יותר, של כמה עשרות אלפי עובדים בלבד - מסוגלת.
    • האמת, שהשם Lean Startup הוא לא הכי מוצלח. "Lean Product Incubation" - הוא שם פחות קליט אך יותר מדויק: העניין הוא מוצר חדש בעולם לא מובן - לא גודל הצוות שמפתח אותו. 
    • כן אני אסכים שהסבירות להצלחת מתודולוגיה שכזו בארגון קטן וצעיר - היא גבוהה לאין שיעור מיישום בארגון גדול ומורכב. כן המתודולוגיה הזו מתאימה יותר לסאטרט-אפים.

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

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

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

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




סיכום


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

זה מדויק - אבל לא נכון.

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

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

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


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



---


[א] - אנשים רבים משתמשים במונחים "Agile" ו "Lean" כמושגים נרדפים - אך יש שוני חשוב בהשפעות והנחות היסוד של כל גישה. 

Lean היא השפעה ישירה של ה Toyota Production System או מה שקרוי Lean Manufactoring - וניסיון לתרגם אותם לעולם התוכנה. Kanban ו Lean Software Development - הם מתודולוגיות לדוגמה, והדובר הלא רשמי שלהם (עד לאחרונה) היו בני הזוג Poppendieck.

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


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