-->

יום שני, 3 באפריל 2017

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

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

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

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

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


לא גלידה, לא פירמידה - אלא יהלום


המודל הקלאסי של בדיקות אוטומציה הוא מודל "פירמידת הבדיקות":


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


המודל המועדף עלי הוא דווקא מודל היהלום:


לאחר שנים שהייתי חסיד של מודל הפירמידה, וריבוי בכתיבות Unit Tests - השתכנעתי שמודל היהלום הוא יעיל יותר.
ההבחנה של ההבדלים בין בדיקות Integration, Component, ו E2E - היא משנית. העיקר הוא:
  • יש לנו מעט בדיקות ידניות: על מנת לא לשחוק, לא לעשות עבודה רוטינית שוב-ושוב-ושוב - אלא להשתמש במוח האנושי שאין לו תחליף, לזהות דברים לא טובים במערכת. (ויש אנשים שעושים זאת טוב יותר מאחרים).
  • יש לנו כמות בינונית של בדיקות יחידה: 
    • בדיקות יחידה הן מעולות (!!) לבדיקת Pure Business Logic, קרי parsers, business rules, אלגוריתמים וכו' - כל מה שיש לו מחזור: קלט - הרבה עבודה לוגית - פלט. ניתן לזהות ביתר קלות אזורי קוד כאלה בעזרת צפיפות של משפטי if ו for (בשפות המתאימות).
    • בדיקות יחידה הן פחות יעילות לקוד אינטגרציה ("עשה א, ואז עשה ב, ואז עשה ג" - כמו שליפת נתונים מבסיס נתונים).
    • בדיקות יחידה הן דיי לא יעילות ל UI.
    • בקיצור: נשתמש בהן ב sweet spot שלהן בלבד: Pure business logic.
  • הדגש של המודל הוא על בדיקות Component (לעתים נקראות אינטגרציה, או API) - הבודקות התנהגות של כל שירות בפני עצמו. בבדיקה פשוטה אפשר לכסות הרבה מאוד קוד, בסביבה יחסית מציאותית, מה שמייצר מעין  sweet spot של עלות-תועלת: בין כמות ההשקעה בבדיקה - והערך שהיא מחזירה.
העקרונות של הפירמידה עדיין נשמרים ביהלום:
  • כמה שעולים למעלה הבדיקות הן: איטיות יותר להרצה, דורשות יותר תחזוקה --> יקרות יותר, ולכן ממעיטים בהן.
  • כמה שיורדים למטה הבדיקות הן ספציפיות יותר, רצות מהר יותר, ותלויות פחות בסביבה / אמינות יותר.


מה עם סוגי הבדיקות השונים? 


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

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

לצורך הדיון, כך נראה שירות:


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

הנה כמה דוגמאות לבדיקות יחידה:



  • המחלקה A היא מחלקה "חברה" של מחלקה X - הבודקת אותה. זוהי בדיקת pure unit tests, האידאל של בדיקות יחידה.
  • המחלקה B היא מחלקה "חברה" של מחלקה Y - הבודקת אותה. מכיוון ש Y תלויה ב X, ואנו רוצים בדיקה "טהורה", קרי: נקודתית ומבודדת - אנו יוצרים Mock של X וכך מריצים את הבדיקה B על המחלקה Y בלבד. 
  • מחלקה C בודקת את המחלקה Z, אבל גם את החברה האחרת שלה - מחלקה X. לכן היא נקראת sociable unit tests. היא חברותית. 
  • כמה שבסיס הקוד שנבדק ע"י בדיקת יחידה הוא גדול יותר (יותר branching של ה flow - בעיקר), בדיקת היחידה היא יעילה פחות: יהיה קשה יותר לבדוק מקרי קצה, וכשלון של בדיקות יצביע בצורה פחות מדוייקת על מקור התקלה.
  • ככלל, אנו מעדיפים בדיקות pure unit tests על פני ב sociable unit tests - אבל זו הבחנה שלא תמיד מדייקת. למשל: אם עשינו refactoring למחלקה גדולה Z, והוצאנו ממנה קוד למחלקה חדשה X - אזי הבדיקה C הפכה ל sociable unit tests. למרות זאת, היא טובה בדיוק באותה המידה כפי שהייתה לפני ה Refactoring.
  • הערה: בתרשים נראה שאני בודק את כל המחלקות שיש לי, בפועל כנראה שאבדוק בעזרת בדיקות יחידה רק 10-30% מהמחלקות ב Service (תלוי כמובן בשירות)


המאסה העיקרית של האוטומציה מתבצעת ע"י בדיקות Component - הבודקות רכיב בודד במערכת.



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

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

במונחים שלנו מדובר על End-To-End Tests, ובקיצור E2E Tests (מה שלעתים קרוי גם System Test):


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

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


  • בבדיקות אינטגרציה בודקים כמה שירותים כשהם עובדים ביחד. בדרך כלל זו קבוצה קבועה של שירותים הנמצאים בקשר עמוק זה עם זה, מה שניתן גם לכנות גם: "sub-system".
  • לפני הרצת בדיקת E2E - מריצים את בדיקת האינטגרציה המתאימה לשירות / תסריט (אם יש כזו). הקמת הסביבה היא מהירה וזולה יותר (נניח 2 עד 7 שירותים - במקום עשרות רבות של שירותים). הבדיקות רצות מהר יותר והן ממוקדות יותר (כלומר: סבירות גבוהה יותר לאתר תקלות).
  • עבור שינוי קטן או בינוני באחד השירותים, ניתן להסתפק בהרצה של ה sub-system הרלוונטי. עניין של בחירה וניהול סיכונים. 
  • ב Sub-System שבתרשים - שירות A הוא "המוביל" ותמיד דרכו ייעשו הבדיקות, גם כאשר השינוי שנבדק הוא בשירות אחר.
    • לא נשלח באמת SMSים, אלא נבצע Mock לשירות החיצוני.
    • ייתכן ואחד השירותים שלנו ב Sub-system הוא מורכב מדי להפעלה / קונפיגורציה - ולכן גם אותו נחליף ב Mock. כדאי להימנע מגישה זו במידת האפשר.

סיכום


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


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



יום שני, 27 במרץ 2017

מחפש ארכיטקט מערכת לגטט (Gett)

היי,

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

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


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

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

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

בגדול מה שעל הארכיטקט אצלנו לעשות הוא:
  • ארכיטקטורה 
    • להיות חלק מהמאמץ של צוות האכיטקטים לתחזק ארכיטקטורה טובה של המערכת: מודולריזציה טובה, flows מערכתיים טובים, טכנולוגיה מתאימה, ורמה מספיקה של תכונות אכות מסוג 3S, כלומר: Stability, Scalability, ו Security.
    • המערכת, כמובן, משתנה כל הזמן. הפיצ'רים משתנים - אך גם הצרכים משתנים.
    • איך עושים את זה?
      • ע"י Reviews (יושבים עם צוותים ולומדים מה קורה במערכת), מחקר (לפעמים צריך לחפור יותר ו/או ללמוד בצד), ותהליכים שונים נוספים שעוזרים להבין כיצד עדיף לבנות את המערכת.
      • התובנות הללו הופכות למשימות: 
        • חלקן גדולות, למשל: לשפר את מערכת זיהוי המתשמשים, ליישם תהליך של בדיקות יצביות ("chaos testing"), או להוביל מאמץ לשיפור Scalability בחלקים מסוימים של המערכת.
        • חלקן קטנות: לעבוד עם דבאופס על שינוי X, לעשות רביו לפיצ'ר Y, או להגדיר תהליך קטן Z.
      • את המשימות הללו יש לבצע. לגרום לדברים להתקדם, ולא רק להתקדם - אלא גם ברמה גבוהה.
      • חשוב גם לתקשר כל הזמן בצורה פרואקטיבית ל R&D את התמונה המלאה, את הארכיטקטורה - רק כך יוכלו להיצמד אליה ולהמשיך אותה (ולא לסתור אותה). זה אומר לכתוב מסמכים (קצרים ויעילים!), לעשות sessions, ולחשוב כל הזמן היכן יש פערים.
    • חשוב לציין שכיום, כארכיטקטים אנו מעורבים רק בפיצ'רים הקריטיים לכלל המערכת. שאר הפיצ'רים הם של הצוותים, ואנחנו עוזרים לייצר את הכללים כיצד משלבים את הפיצ'רים במערכת בצורה טובה. איך יתוכנן הפיצ'ר - זה עניין של הצוות, כל עוד הוא משתלב בצורה נכונה במערכת.
  • מקצועיות של R&D
    • קבוצת הפיתוח צמחה בחברה בקצב מהיר מאוד. כמעט גדלה פי 4 בשנתיים האחרונות, מאז אני הצטרפתי. 
    • הדרך היחידה לשרוד כזאת צמיחה היא לשמור על רמה גבוהה לכל האורך.
    • אנו עוזרים להגדיר את תהליכי הגיוס (בצד הטכני. לוודא שהמבחנים מספיקים והמראיינים יעילים), תהליכי ה On-Boarding, וכמובן שיפור מקצועי תמידי בתוך ה R&D. יש לכך היבטים רבים: בניית בסיס ידע, בניית קהילות טכנולוגיות בתוך החברה, תהליכי למידה (למשל: Code Review), ועוד... 
    • אנחנו רוצים להתחיל גם להיות פעילים בקהילת ה Startup הישראלית, ולשתף חלק מהידע החוצה / להביא יותר ידע מבחוץ פנימה.
  • שירותים טכניים כאלו או אחרים
    • ניתוחים טכניים כאלו או אחרים שנדרשים בחברה נעשים על ידנו. זה החלק הקטן של התפקיד.

דרישות:

כמקובל, הגדרנו דרישות שיעזרו לנו למקסמם את סיכויי ההתאמה של מועמד. אני רציני לגביהן ומנסה לבחון אותם ברצינות כחלק מהתהליך:
  • חמש שנות ניסיון בפיתוח של מערכות צד-שרת/ווב. זה לא המון - אבל זה חשוב!
  • לפחות שנה אחת בסביבת SaaS/Production משמעותית. חשוב מאוד "לחיות" פרודקשיין. 
  • ניסיון של שנתיים כארכיטקט בתפקיד דומה. אני זקוק למישהו שיכול להתחיל לתפקד תוך כמה חודשים. 
    • בזמנו קיבלתי הרבה קו"ח של מתכנתים מנוסים / מובילים טכניים - ודחיתי אותם. המעבר לתפקיד ארכיטקט (היבטים לדוגמה: hands-off - eyes on, השפעה ללא סמכות, חשיבה ברמת המערכת) הוא לא קל, ולצערי כרגע אין לי את הפריווילגיה לגדל מישהו לתפקיד - מוכשר ככל שיהיה. אני צריך מישהו שהוא כבר שם.
  • 10% Hands-On. ידיד הציע לי לא לכתוב את זה, כי אולי זה לא נשמע אטרקטיבי - אבל חשוב לי לשקף את המציאות:
    • אין כתיבת קוד כחלק מהתפקיד. אולי ייצא מדי פעם קצת ב POC, או איזה כלי, או לבצע איזה Pull request - אך זה חלק קטן למדי בפעילות.
    • אני מאמין בכל לבי שאדם שלא ילמד את שפות התכנות שאנחנו עובדים בהן (Go ורובי) ולא יוכל להתעמק בקריאת קוד בעת הצורך - לא יוכל לפרוח בתפקיד. הרבה פעמים התיאור מהמפתחים כיצד משהו עובד נשמע משהו אחד - ורק נבירה בקוד יכולה להסביר מה באמת מתרחש שם. הבנה עמוקה של שפת התכנות וסביבת הריצה הן לפעמים ההבדל בין עצה מעמיקה, לעצה לא-רלוונטית.
    • כלומר: נבירה בקוד היא כלי חשוב, ובהחלט חלק מהתפקיד. חשוב לי שהארכיטקטים בצוות ישארו ברמה הזו ולא יאבדו את היכולת הזו - ואנחנו משקיעים בזה.
  • מקצועיות טכנולוגיות גבוהה: רוחב אופקים (מכיר הרבה שיטות וטכנולוגיות), אך לא פחות נדרש עומק: יכולת לצלול לנושאים לעומק, גם נושאים סבוכים, ולהביא תובנות משמעותיות.
  • יכולת לעבוד בסביבה דינאמית ובשוק תחרותי מאוד. זה נשמע קלישאתי, אבל קצב ההתרחשויות בחברה הוא באמת גבוה מאוד. זו לא סביבה "קלה".
  • היכולת לפשט נושאים / רעיונות סבוכים לתיאור פשוט וממוקד - שקל לתקשר הלאה. יש לנו הרבה פרטים וידע במערכת - הדורשים זיקוק תמידי על מנת שהדמויות הרבות בפיתוח יוכלו לעקוב אחריהן.


זהו, פחות או יותר.

אם אתם מתאימים - אנא שלחו לי קורות חיים ל liorb[@]gett.com    (הפורמט נועד להקשות על ספאממרים הסורקים אחר כתובות אימייל)
אם אתם מכירים מישהו שעשוי להיות מתאים - אודה לכם אם תשתפו איתו את הפוסט!

נ.ב. - אם יש שאלות, אפשר לפרסם - כמובן.

תודה!



יום ראשון, 5 במרץ 2017

על העיקרון הפתוח-סגור (ארכיטקטורה)

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

העיקרון הפתוח-סגור אומר ש:

Software Entities (classes, modules, functions, etc.)
should be open for extension, but closed for modification.

העיקרון הפתוח-סגור (בקיצור: OCP, שזה ה Open-Closed Principle), הוא חלק ממערכת ה S.O.L.I.D - מערכת כללים לבחינת איכות של עיצוב (Design) תוכנה שהגדיר הדוד בוב (Robert C. Martin) בתחילת שנות ה 2000.

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

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


לא עזרתם בהרבה! מקור: http://www.tomdalling.com


בגרסה היותר ידידותית, העיקרון אומר משהו כזה:
  • כתבו את הקוד כך, שרכיבי התוכנה (מחלקות, מודולים, פונקציות, וכו') לא ישתנו לאחר שסיימו לכתוב אותם - להלן: "Closed for modification".
  • תוספת של פונקציונליות - יש להוסיף ברכיבי תוכנה חדשים (עוד מחלקות, עוד מודולים, או עוד פונקציות) - להלן "Open for Extension".

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


---------

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


שאלות ראשונות


מדוע לא לשנות קוד שכבר נכתב?

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

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


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

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


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


מדוע "הרחבה" של קוד היא בסדר?




בשלב הראשון אנו כותבים את ה "Basic Functionality". הקוד עובד ומתייצב עם הזמן.
כאשר אנחנו נדרשים להרחיב את הפונקצינליות אנו מוסיפים את תוספות 1, 2, ואז 3.

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

כמו כן - הרחבה תכופה תאפשר לכל איזור קוד להיות קטן ופשוט מספיק בכדי להבין אותו: "Scalability" של כתיבת קוד.

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



מדוע עדיף לנו שבאגים יופיעו באיזור החדש של הקוד, ולא באיזור הישן?

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

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


כיצד ממשים OCP בפועל?


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


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

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

אני בונה את המנגנון כך: Broker שמקבל את הבקשה ואז מעביר את רשימת ההתאמות האפשריות לרכיב "Base Condition" - הרכיב ידרג את ההתאמות מהטובה ביותר, להכי פחות טובה.

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


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

מנגנון ה Broker קורא מקובץ קונפיגורציה - באיזה סדר להפעיל את התנאים.

ובאמת לאחר כחצי שנה המנגנון נראה כך:


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

בפבואר הוספתי את Condition 2 - ועד אפריל הוא התייצב בצורה טובה.
במרץ הוספתי את Condition 3 - ועד מאי הוא התייצב בצורה טובה.
במאי הוספתי את Condition 4 - ועד יולי הוא התייצב בצורה טובה.

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

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

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

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

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


ספקות לגבי OCP


ה OCP הוגדר בצורה לא ברורה. את זה כבר הזכרנו. היו כמה מאמרים שהתפרסמו בביקורת הזו (למשל: Say "No" to the Open/Closed pattern של Marco Cecconi ו The Open-Closed Principle, in review של Jon Skeet)

במאמר מאוחר של הדוד בוב מ 2013 הוא סיפק את ההגדרה הבאה ל OCP:

What it means is that you should strive to get your code into a position such that, when behavior changes in expected ways, you don't have to make sweeping changes to all the modules of the system. Ideally, you will be able to add the new behavior by adding new code, and changing little or no old code.

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


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

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

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

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

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

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

אם המערכת שלנו תתרחב ל 10 צורות, וכמו המתודה DrawAllShapes יש מתודות כמו EditAllShapes, ResizeAllShapes ועוד - אז ברור לי שבסיס הקוד שלי הולך וגדל ללא היכר. זה מקרה ברור בו כן היינו רוצים ליישם את ה OCP.
בסיס קוד גדול יותר => קוד שקשה יותר לשלוט בו => קוד שקשה יותר לשנות / יותר באגים.

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

OCP מתבטא ב Patterns כמו Plug-ins, State, Strategy, ועוד. אולי גם Composite ו Delegate.
זוהי רשימה קלאסית של Patterns שאנשים נטו ונוטים לעשות בהם שימוש מוגזם: השימוש עשוי להרגיש "טוב" (המערכת שלנו היא "כמו בספרים"), אך בפועל ייתכן ויצרנו מערכת יותר מסובכת ויותר יקרה לשינוי / תחזוקה.

OCP הוא במיטבו כאשר ממשים אותו במידה, אבל מהי המידה הנכונה?


מקור: https://www.slideshare.net/PaulBlundell2/open-closedprinciple-kata


קרייג לרמן, ו PV


ובכן, אם לא הכרתם עד עכשיו - אז שווה להכיר:
במקביל לדוד בוב שהגדיר את עקרונות ה S.O.L.I.D, עבד בחור קנדי בשם קרייג לרמן על מערכת חוקים מאוד מאוד דומה בשם GRASP. המערכת של לרמן הרבה יותר פשוטה להבנה! מה שהופך אותה לעדיפה בעיני.

מסיבות שאינני יודע למנות, SOLID הפכה למערכת המוכרת, ורוב האנשים מכירים דווקא אותה.

העיקרון המקביל של GRASP ל OCP נקרא Predicted Variations או בקיצור PV. והוא מוגדר כך:

Identify points of predicted variation and create a stable interface around them


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

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

We can prioritize our goals and strategies as follows:
1. We wish to save time and money, reduce the introduction of new defects, and reduce the pain and suffering inflicted on overworked developers.
2. To achieve this, we design to minimize the impact of change.
3. To minimize change impact, we design with the goal of low coupling.
4. To design for low coupling, we design for PVs.

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


אנסה לתמצת את הרעיונות במילים שלי:
  1. זהו במערכת מקומות שבהם אתם צופים תוספת של קוד, ונסו להכין ממשקים ידועים להרחבות הללו.
  2. בעצם מדובר ב"ניהול סיכונים": הסבירות שאכן המערכת תתרחב לשם (תזכורת = בני-אדם נוטים לבצע הערכת יתר בציר הזה)  X  כמה קוד וסיבוכיות אתם צופים שתתווסף.
  3. עבור שינויים קלים (שורות קוד בודדות) - הערך ביישום OCP הוא גם נמוך. נסו לכוון למקומות משמעותיים.
  4. קלעתם טוב - השגתם ערך; לא קלעתם טוב - השקעתם זמן מיותר. זה בעצם העניין כאן.
  5. אפשר לנקוט בגישה אגי'לית: כשאתם רואים שאכן המערכת מתפתחת לכיוון מסוים, בצעו Refactoring והוסיפו ממשק מתאים / PV. אם יש לכם בדיקות יחידה - אין סיבה לפחד מ Refactoring.


אני מניח שאם GRASP הייתה השיטה השלטת - הפוסט שלי היה מתקצר בחצי: המטאפורה של Predicated Variations הרבה יותר קולעת מה Open-Closed Principle (סליחה, הדוד בוב).

לא מצאתי את הציוץ של הבחור שהציע: "בואו נחליף את OCP ב PV - ונתחיל להשתמש ב SPLID".


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


----

מקורות רלוונטיים:


יום ראשון, 26 בפברואר 2017

על היוגי והקומיסר

דמיינו ישיבה: כמה ראשי-צוותים, כמה ארכיטקטים, כמה מובילים טכניים.

"כבר עשינו עבודת הכנה מקיפה לגבי המעבר ל MDA (קרי: Model-Driven Architecture):", פתח הארכיטקט הבכיר (להלן א׳, שמו שמור במערכת). "הגדרנו Meta-Model לכל המערכת שלנו, וביססנו אותו על Meta-Meta Model (או super model). יש לנו רשימה של נקודות שצריך עוד לסגור - אבל אנחנו כבר יכולים להתחיל. הצוות של יוסי החל ליישם Repository למודלים, ועוד חודשיים נוכל כבר לתת לכל שאר הצוותים בארגון להמיר את הקוד שלהם למבנה ה MDA."

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

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

"זו פרקטיקה בצמיחה, יש כבר 'body of knowledge' שהולך ונבנה בתחום, ויש גם כמה יישומים מוצלחים (במיוחד בעולם ה Databases)" - ענה א׳ בלי למצמץ, בלי לשדר אי-נוחות, בלי בושה.

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

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


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

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

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

מה קורה פה בעצם?

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


מקור: https://vidyow.com/video/the-main-differences-between-t/vcbaDoo8guL

ציר טראמפ-אובמה


למזלנו, ההיסטוריה העכשווית מספקת לנו מטאפורה רלוונטית שקל להתייחס אליה*.

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

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

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


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

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

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


הנה סיפור נוסף לדוגמה מעולם הטכנולוגיה. איזו חוסר הבנה!....:

מקור: הפוסט http://getindata.com/blog/post/lean-big-data-how-to-avoid-wasting-money-with-big-data-technologies-and-get-some-roi

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

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


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


מה הסיפור שלכם?


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

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


It's all about tradeoffs


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



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

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



סיכום


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

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

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


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

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

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


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



יום שבת, 21 בינואר 2017

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

בפוסט הקודם בסדרה דיברנו על Continuous Delivery (בקיצור CD), על ה Deployment Pipeline, ופרקטיקות נוספות.

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


תנו לי CDD - ועכשיו!


Continuous Deployment הוא הרעיון שהפער בין קוד המערכת לסביבת הפרדוקשיין יהיה מינימלי - דקות עד שעות ספורות לכל היותר.

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

הנה תיאור ה Deployment pipeline שהשתמשנו בו בפוסט הקודם:



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


יש לכך כמה קשיים עיקריים:

המעבר מביטחון של 95% באוטומציה לביטחון של 100% באוטומציה - אינו קטן!

שמעתי הרצאה של קבוצה בגוגל שלאורך 18 חודשים (שנה וחצי) ניסתה לעבור מ CD ל CDD - ועדיין לא הצליחה. עדיין כ 1% מה commits היו בעייתיים למרות שעברו את הבדיקות, ותהליך השחרור אצלם נותר ידני. כלומר: מפתח מבצע החלטה בכדי להעביר commit לפרודקשיין.
כותרת ההרצאה הייתה אודות "Continuous Deployment" - למרות שלא עמדו בתנאי הרשמי הזה (בסדר מבחינתי!). קצת הופתעתי שהדבר הטריד אותם ונראה שהיה חשוב להצהיר שתוך כמה חודשים הם חושבים שכבר יוכלו לעשות שחרור אוטומטי לחלוטין.

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


עם הזמן מספר ה commit ילך ויגדל

אולי כי הארגון גדל, ואולי כי המפתחים באמת השתפרו בתהליך ה CI?
כמות ה commits בשעה תלך ותגדל: 1 בשעה, 2 בשעה, אח"כ 5 בשעה, וכו'.

כבר באזור שלושה-ארבעה ה commits בשעה - תהיה בעיה: תהליך ה deploy אורך כ 30 דקות.
מה עושים? נותנים לתור ה commits להצטבר? להיכנס לשעות העומס של המערכת או שעות הלילה? אולי לגלוש למחר?
אולי פשוט נאחד כמה commits ונעשה להם deploy ביחד?
אולי נשקיע מאמץ במיקבול טוב יותר של תהליכי ה deploy?

הבעיה הזו כנראה לא הולכת להיעלם, במיוחד אם אתם ארגון בצמיחה. גם אם תמקבלו את התהליך, את שלב ה deploy עצמו (blue/green או rolling) ואז צפייה בשינויים בסביבה בעקבות ה deploy - תהליך שאורך 10 דקות לפחות, כנראה ולא תוכלו ממש למקבל.

הפתרון המקובל הוא אימוץ של Microservices Architectures. הרבה repositories שונים של קוד, שעוברים deploy לשרתים שונים - מאפשרים מקביליות. כאשר יותר שורות קוד --> יותר שירותים (תנאי של Microservices Architecture) - המקבילות היא, תיאורטית, אינסופית.


Database migration

אם אתם עובדים עם RDBMS אזי המיגרציות:
  • יכולות לארוך זמן רב (שעה? שעתיים? - כאשר הטבלאות גדולות), ולא ניתנות למיקבול של ממש.
  • יכולות לגרום ל downtime קצר בכל מיגרציה (כאשר נניח משנים או מוחקים עמודה).
  • טעויות במיגרציה יכולות להיות הרסניות לפעילות המערכת.
הפתרונות המקובלים הוא לעבור לפתרונות בהם כמעט ולא צריך מיגרציה: Document Databases על פני Relational Databases, או Databases שבהם המיגרציה היא נוחה יותר (למשל PostgreSQL על פני MySQL).

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

* "תקוע" הכוונה שהשירות עובד - פשוט אי אפשר לבצע עוד deploys בזמן הזה.




אז למה באמת ארגונים בוחרים ב CDD?!


(אני קצת חוזר על הנאמר בפוסט הראשון)
הרעיון של Continuous Deployment קיבל תנופה גדולה מתנועת ה Lean Startup, שם צמצום מחזורי הלמידה והפידבק הם ערך מרכזי. הדרישה ל CDD, ע״פ המתודולוגיה, אמורה להגיע כיעד עסקי מה CEO - זה לא עניין ״פנימי״ של ה R&D...

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

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

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


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


מקור: Ash Maurya

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



אך איך מיישמים CD/CDD בארגון שעדיין לא שם?


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

נתחיל בגישות העיקריות, הנוגעות לארגונים שרק מתחילים בתהליך האימוץ:

גישה: AquaSlump

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

בעצם יש פה פרויקט שצריך להריץ:
  • שלב א' - משקיעים בתשתיות build - חשוב מאוד לוודא שמהכנסה של קוד עד להגעה לפרודקשיין הכל הוא 100% אוטומטי.
  • שלב ב' - בונים סביבת staging יציבה לאוטומציה. יש פה עניין של הקמת סביבות בצורה אוטומטית ומהירה - זהה לפרודקשיין, הבאת נתונים אמיתיים מפרודשיין, וכתיבת בדיקות End-to-End שיכסו אותנו בצורה טובה ויספקו אמינות שהקוד שאנחנו משחררים הלאה ב pipeline הוא באמת תקין.
  • שלב ג' - מביאים את כל חלקי המערכת לרף הבדיקות שנקבע: למשל 85% Code Coverage.
  • שלב ד' - מתחילים לאפשר לצוותים לשחרר קוד לפרודקשיין, אזור אחר אזור.

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

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

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


CI/CD/CDD Maturity Model - מודל אידאלי ואוניברסילי ליישום השיטה. תורת הצורות/האידאות של אפלטון בהתגלמותה! מקור



גישה: Guerilla Transformation


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

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

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

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

אבל זה יותר CD/CDD ממה שארגונים מגיעים אליהם אחרי חודשים של עבודה קשה, בגישת ה AquaSlump.

ג'ז האמבל (המחבר של ספר ה CD המפורסם) מציע ששני המדדים העיקריים לאימוץ של CD יהיו:
  • כמה commits ל master ביום / ביחס למספר המפתחים.
  • כמה זמן אורך מרגע שיש רעיון - ועד שהוא מגיע לפרודקשיין (קרי: lead time). 

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

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

בשלב הבא, כשמעט מתבגרים - אלו כנראה הדברים שתרצו להתמקד בהם:
  • בדיקות אוטומטיות מהירות, עם כיסוי סביר.
  • תהליך של canary release.
  • בדיקות post-deployment ויכולת ל rollback מהירה.
  • יצירת אווירה שבה טוב ונוח למפתחים לעשות הרבה deploys ביום.

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

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






כמה בעיות של CDD שאולי לא חשבתם עליהן בתוכנית ה AquaSlump שלכם...


"פקקים" ב Deployment Pipeline

במהלך השעה האחרונה נכנסו לי סדרה של ארבעה commits לשירות מסוים: A, B, C, ו D.
commit A - עבר deployment בהצלחה.
commit B - נכשל.
האם אפשר לקחת את commits C +D לפקודקשיין בצורה אוטומטית? חבל לבזבז זמן!
 איך יודעים האם הם תלויים ב commit B או לא?

הבעיה איננה בעיה לוגית כ"כ גדולה: בד"כ אפשר לבצע merge אוטומטי של commit C על גבי commit A וללא commit B - ואז להעביר את השינוי ב pipeline. מה שנקרא "commit selection" או "מי הבא בתור?". אבל זה עדיין תהליך, הדורש עבודה וליטוש.


זיהוי בעיות ב UI

בעוד בדיקות אוטומציה הן טובות מאוד לקוד לוגי - קשה הרבה יותר לבדוק UI בצורה אוטומטית ומלאה.

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

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

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

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

שוב - אין פה rocket science, אך יש פה צורך ספציפי למוצר - שניתן להבין וללמוד אותו רק בעקבות "התנסות בשטח".


תלויות בין מיקרו-שירותים

נניח שיש לי פיצ'ר בשירות X שדורש API מתאים בשירות Y?
זה נשמע אתגר קטן: נגדיר את התלויות. סגור!

בפועל: מצב ה pipeline של כל שירות הוא דינאמי - ולכן קשה לתכנון. בכל רגע נתון יכולים להיות לפני ה commit שלי מספר commits שמחכים להרצה ב pipeline. כיצד אם מוודאים שהשינוי ב API (שירות Y) יהיה זמן בפרודקשיין, לפני שהקוד בשירות X "נוחת" בפרודקשיין בעצמו? אם יש שלושה commits בתור בשירות Y, אך אין תור כלל בשירות X?

שוב - אין פה מדע טילים, אך יש בעיה מציאותית שצריך לפתור, כאשר לא כל פתרון מתאים באותה מידה לכל מוצר / מערכת.


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


קצרים


רעיונות אחרונים בנושא שארצה להוסיף לגבי יישום של CD/CDD:
  • פגישת Slow Deployment Retrospective - לא משנה השם, אבל אם לא תדאגו לשפר כל הזמן את תהליך ה deploy שלכם - הוא הולך להיות אטי ומסורבל עם הזמן. במיוחד כאשר המוצר והחברה בשלבי גדילה.
  • ב Lean Startup (ממנו הגיע ה CDD) ה Definition of Done של פיצר הוא "הפיצ'ר ייצר את האימפקט המצופה בפרודקשיין". לא סוגרים "טיקט" עד שלא מגיעים לשם, כלומר: עושים עוד ועוד איטרציות על הפיצ'ר עד שהאיפקט מושג. לסירוגין: אפשר להחליט שהפיצ'ר פשוט לא שווה את ההשקעה המסתמנת.
    • ב CDD מן הראוי, לא לסגור טיקט של פיצ'ר לפחות עד שלא רואים אותו בפרודקשיין. שינוי קטן ב Jira - ושינוי קצת יותר גדול ב mindset.
  • תזכורת: כמו ב CD - בעיות פרודקשיין ובעיות ב Deployment pipeline מטפלות בדחיפות הגבוהה ביותר בארגון! הזנחה של הכלל הזה - היא דרך מצוינת להכשיל יישום CD/CDD.
  • Hello Prod (על משקל "Hello World") - כאשר מפתחים שירות חדש, דבר ראשון שלחו את ה template של שירות חדש (להלן "Hello Prod") לפרודקשיין - ועליו תתחילו לפתח. בפרודקשיין. אל תחכו שבוע או שבועיים עם קוד בצד לפני שראיתם פרודקשיין. מייד!
    • זה תרגיל מצויין כדי להתחיל לתרגל CDD, גם אם אתם ממש בתחילת התהליך.
  • שאיפה של מוצר CDD הוא שעם הזמן (וגדילת מספר העובדים), קצב השחרורים לפרודשיין /יחסית למספר המפתחים - רק יגדל!




סיכום


CD ו CDD מרגישים ממש קרובים - אבל הם לא.
אם ב CD שיגרנו חללית לחלל, מיד גילינו שיש לנו עוד עבודה לגרום לה להשתחרר מהכבידה של כדור הארץ (להלן CDD). לא מאמץ קטן!

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

ולכן אתקן: אני ממליץ לכל מוצר SaaS להגיע ל 90% CDD. שיהיו הרבה deploys ביום / ביחד למספר המתכנתים. יותר deploys ביום ממפתחים - לפחות.
אם יש מוצר SaaS ואתם משחררים לפרודקשיין רק פעם בשבוע או שבועיים - זה מרגיש פספוס.

אם תבחרו בגישת הגרילה - זה גם לא יהיה כ"כ קשה. מפתיע כמה זה קל!

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


נ.ב. - יש!! סיימתי סדרת-פוסטים!



יום רביעי, 11 בינואר 2017

רברסים 2016 - סיכום אישי

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

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

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


אולם וויקס, האולם הגדול ב Keynotes - ובתפוסה מלאה


אני נתתי הרצאה בשם Software Punk: Controversial ideas in Software Development That just might work.

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

הנה ההרצאה:


והנה השקפים:
http://www.slideshare.net/baronlior/software-punk-70388554


בסשן היו מספר לא מבוטל של קוראי הבלוג - היה משמח לראות אתכם שם!!


אולם קטן וצפוף :-)


עוד כמה הרצאות שהייתי רוצה להמליץ עליהן:

זאת העבודה שלך!   https://goo.gl/FFzYnh
הרצאה של שי כפיר (שעבר איתי פעם בסאפ) על תפקיד ראש הצוות. זה לא קידום חברים - זו פשוט הרצאה טובה!

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


הובלה ללא סמכות, של מוביל טכני  https://goo.gl/PXR1a2
אורן אלנבוגן (VP R&D של פורטר, המחבר של Leading Snowflakes, וכו') דיבר על כמה התנהגויות קטנות לכאורה - אך משמעותיות מאוד אם הן לא שם.


קריאה למהנדסים להפוך למנהלי מוצר https://goo.gl/YtmcDb
הרצאה קצרה שמשתלבת במגמה של השנים האחרונות לחבר את ניהול המוצר יותר לפיתוח, ולהפיג את המיתוס שהגדרת מוצר היא דבר שמהנדסים לא יכולים לעשות (או לפחות: להיות חלק ממנו).


בונוס: אתם מעולים בכתיבת קוד - עכשיו הגיע הזמן להיות מעולים בסיפור סיפורים https://goo.gl/zPR7It
כבר דיברנו רבות עד כמה תקשורת היא פעילות מרכזית בהנדסת תוכנה, לפחות כאשר מדובר בקבוצה שגדולה מצוות יחיד.
כבני אדם, המוח שלנו לא כ"כ בנוי לנהל רשימות ומספרים - הוא בנוי לספוג סיפורים. ולכן - סיפור סיפורים היא יכולת חשובה לכל מי שרוצה להשפיע מעבר לכתיבת הקוד האישית שלו.


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

דווקא מספרים שלא היו שם והיו יכולים לעניין - הם על הסשנים.



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