על 4 סגנונות ניהול

הפוסט נכתב בשיתוף עם יהודה גרנות – CTO & CO-Founder at Fincheck.

 

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

יש לו מספר וריאציות.

בווריאציה הפשוטה ביותר (מקור: Rensselaer Polytechnic Institute. Retrieved 24 May 2012) מגדירים שני סגנונות בלבד:

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

 

איננו מסכימים איתו! אולי לאחר קריאת הפוסט – גם אתם לא.

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

 

האם אתם יכולים לחשוב על מנהלים שאתם מכירים / עבדתם איתם – ולהבין לאיזו אסכולה הם שייכים?

מקור: Cinetropolis
 

להכיר את סגנונות הניהול

הוריאציה הקצת-יותר-מורכבת (מקור: Leadership & the One Minute Manager) מדברת על 4 סגנונות ניהול:

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

 

במידה ואתם בעצמכם מנהלים – איזה סגנון מאפיין אתכם?

 

 

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

 

אם תתקלו בהן, אז הנה שמות נרדפים לסגנונות: הגישה המעורבת נקראת גם Consultative, הגישה התומכת נקראת גם Democratic, והגישה הסומכת נקראת גם לסה-פר (Laissez-faire, שמשמעו "תנו לעשות, תנו לעבור").

מודל סגנונות הניהול, וריאציית חמשת הסגנונות.
 

בחן את עצמך (למנהלים): סגנונות הניהול השונים

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

מקרה #1 – אתה רוצה לבצע שינוי ארגוני משמעותי. ביצועי הארגון / צוות טובים – אך השינוי נחוץ. מה תעשה?

א. אתן לצוות להשתתף ולהשפיע על דרך הכנסת השינוי.

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

 

מקרה #2 – הצוות מפגין לאחרונה ירידה בביצועים: איחור ביום משימות, והאיכות ״לא משהו״. מה תעשה?

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

.
מקרה #3 – אתה מתוודע לשני חברי צוות שלא מסתדרים ביניהם במידה מזיקה. מה תעשה?

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

 

ובכן, הנה תוצאות ההדגמה:

  • הסגנון הסמכותי הוא ג, ד, א – בהתאמה.
  • הסגנון המעורב הוא בב, ד – בהתאמה.
  • הסגנון התומך הוא א, ג, ג – בהתאמה.
  • הסגנון הסומך הוא דא, ב – בהתאמה.
 
נד סטארק. מנהיג פנטסטי!

איזה סגנון ניהולי הוא המוצלח ביותר?

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

השאלה שעולה מיד לראש היא: "האם הסגנון שלי מוצלח, או לא?"
״האם סגנון הניהול הדומיננטי אצלי – הוא הסגנון הטוב ביותר?״

למנהלים – העניין הזה תופס מקום חשוב ורגיש במיוחד: "אולי אני צריך לשנות סגנון מ-A ל-B?"

התשובה המפתיעה היא זו: אין סגנון טוב ולא-טוב. כולם עשויים להיות טובים – לסיטואציה.

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

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

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

ע"פ "מודל הצרכים" (לא לבלבל עם פרמידת הצרכים של מאסלו) על המנהל:

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

"Nothing is so unequal – as the equal treatment of unequals"

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

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

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

צרכי העובדים

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

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

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

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

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

 

 

  • D1 – עובדים בעלי יכולת נמוכה, אך מחויבות גבוהה
    • לעובד אין ניסיון במשימה שהוטלה עליו.
    • לעובד יש מוטיבציה גבוהה ללמוד ולהתאמץ.
    • לפעמים, העובד בטוח ביכולתו להצליח – באופן לא מציאותי.
  • D2 – עובדים בעלי יכולת מסוימת, אך מחויבות נמוכה
    • לעובד יש ידע / מיומנות בסוג המשימה שמטילים עליו – אבל עדיין נראה שהוא לא יתמודד עם המשימה היטב לבדו.
    • לעובד יש תסכול, הוא מבולבל או "טעון" לגבי המשימה.
    • העובד עוד בשלב ההתפתחות בתחום, וזקוק לשגיאות כחלק מתהליך הלמידה.
    • ביצועי העובד בתחום הם לא אמינים או לא עקביים.
  • D3 – עובדים בעלי יכולת גבוהה, אך מחויבות משתנה
    • העובד עצמאי – אבל לא תמיד עושה את הדבר הנכון ביותר. עבודה עם אחרים עשויה לעזור.
    • העובד לעתים ספקן או לא בטוח בעשייה שלו.
    • העובד עשוי להפגין שעמום / עייפות ממה שהוא עושה.
    • העובד בסה"כ תורם בצורה משמעותית.
  • D4 – עובדים בעלי יכולת גבוהה, ומחויבות גבוהה
    • העובד יודע את העבודה, והוכיח את עצמו בעבר במשימות דומות.
    • העובד בטוח בעצמו וביכולת שלו להתמודד עם המשימה.
    • המשימה מושכת את העובד – וזה ניכר.
    • העובד יוזם, ולא מחכה להנחיות / אין לו הרבה שאלות.

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

בהינתן התאמה של עובד לקטגוריה D1 – D4, סגנון הניהול המומלץ הוא:

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

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

 

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

 

ההשפעות השונות של סגנונות הניהול השונים

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

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

סיכום

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

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

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

מה שנדרש ממני הוא גישה מעורבת במשימות 2,1 ו 3, וגישה סומכת במשימות 5,4, ו 6.
לפעמים קל לשכוח את זה.

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

Infrastructure as a Service: Terraform

אם אני מעוניין לתת דוגמה לפער בין התיעוד הרשמי ל\"מידע מהשטח\" בעולם של AWS – אני נותן את הדוגמה של Terraform.
בתיעוד של אמזון, הכלי המדובר להגדרת תצורה רחבות היקף הוא Cloud-Formation (של אמזון) – אבל בפועל, אני לא מכיר אף אחד שעובד עם Cloud Formation לאורך זמן: כולם עוברים ל Terraform.
אם תשאלו מישהו שעובד כבר עם AWS – הוא כנראה יפנה אתכם ישר לשם.

Terraform הוא כלי שמנסה לספק כמה מטרות:

  • לספק תמונה אחת לכל תשתית המערכת שלנו.
  • לתמוך בתצורות production מודרניות (ענן, וכו\')
  • לספק אופן צפוי ובטוח לעדכן את תצורת התשתית שלנו.
  • לספק Workflow אחיד לעבודה מול ספקי-תשתיות שונים.
    • משום מה, אנשים נוטים להניח ש Terraform מאפשר להגדיר תצורה לספק ענן אחד (נניח גוגל) ואז להפעיל אותה על ענן אחר (נניח Azure). זה בהחלט לא המצב! זה לכל היותר מיתוס!

נפתח בדוגמה

מה ש Terraform (מעתה אשתמש בקיצור: טרה) מאפשר – הוא להגדיר תצורה רצויה בצורה פשוטה – ו\"לגרום לה לקרות\".

את הגדרת התצורה עושים בקבצים עם סיומת  tf. כמו זה:

\"היי!\" – אתם עשויים לומר, גם בעזרת  aws-cli , או סתם סקריפט פייטון שמשתמש ב AWS SDK – אני יכול להרים instance בצורה פשוטה למדי! אז מה ההבדל?

יש כמה הבדלים:

  • בעזרת טרה, אני משתמש באותה שפה ואותו תהליך אני יכול להגדיר תצורה על תשתיות שונות: AWS, גוגל, Dyn, Cloudflare – ועוד. זה קצת יותר פשוט מלהתחיל לעבוד עם כלים שונים ו SDKs שונים.
  • טרה מוסיף \"חוכמה\" של חישוב המסלול הנכון להגיע למצב הרצוי: טרה בודק מה המצב הקיים, ומחשב אלו שינויים יש לבצע בכדי להגיע לתצורה הרצויה. לעשות את זה לבד – זו הרבה מאוד עבודה!

נמשיך:
לאחר שיצרתי את קובץ הגדרת התצורה שלי, אני מקליד את הפקודה

$ terraform plan
ומקבל את הפלט הבא:

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

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

הפלט מופיע בתצורה של diff:

  • + – על משאב חדש שנוצר.
  • – על משאב שמבוטל.
  • ~ – על משאב שעובר שינויי תצורה.
  • -/+ – על משאב שמבוטל, ומוחלף במשאב אחר.

ניתן גם:

  • להעשיר את הפלט בצורה מותאמת אישית, בעזרת פקודות output (או פונקציות כמו count) בהגדרת התצורה. למשל: אני רוצה לדעת איזה IP ה ELB שלי הולך לקבל, או כמה instances מסוג מסוים יהיו על מכונות spot.
  • להשתמש בפקודה terraform graph על מנת לקבל גרף המתאר את סדר הפעולות המתוכנן. טרה עובד עם פורמט גרפים סטנדרטי, ואת הפלט של הפקודה ניתן לטעון ל webgraphviz.com – על מנת לצפות בגרף בצורה ויזואלית.
    • הפלט של פקודת plan מסודר ע\"פ סדר הא\"ב על מנת לספק יכולת סריקה מהירה של התוכן.
  • לשמור את תוצאת התכנון, בעזרת הפרמטר out=path-, כך שיובטח שבעת הפעולה תרוץ התוכנית שבחנתי.

כאשר אני מקליד:

$ terraform apply

עברה כחצי דקה ואני מקבל את ההודעה הבאה:

אני יכול גם להסתכל ולראות את ה instance שנוצר ב console

או פשוט לקרוא ל \"aws ec2 describe-instances\" ולראות אותו ב console.

לאחר ביצוע קבוצת ה apply, טרה יצר לנו שני קבצים: קובץ tfstate. וקובץ tfstate.backup.

הקבצים הללו (יש להם תוכן שונה זה מזה) מתארים את ה last-known-state של התצורה המרוחקת (כלומר: מה שקורה בפועל), והם ישמשו אותנו לפעולות הבאות.

במקרה שלנו הקבצים נוצרו רק לאחר פעולת ה apply (כי נוצר מצב שלא ניתן לשחזר בעזרת ה API של AWS בלבד), אבל גם בהרצת פקודת plan ייתכן והקבצים הללו ייווצרו / יתעדכנו.

את הקבצים הללו אני אוסיף ל gitignore. כך שלא יגיעו ל source control. מדוע – אסביר בהמשך.

נמשיך:

נעשה שינוי קטן בכדי לראות את ניהול הדלתאות של טרה:

ביצעתי שני שינויים. קראתי ל terraform plan וקיבלתי:

האמת שהייתי מצפה בשינוי instance_type שזו תהיה פעולת +/- – אבל כנראה בגלל שספציפית באמזון השוני בין t2.micro  ל t2.nano הוא רק ב CPU capping – אני מניח שה instance לא מוחלף פיסית. אם הייתי משנה AMI, למשל – זו הייתה פעולת +/-.

לאחר terraform apply אקבל:

הפעולה לקחה קצת יותר זמן ממה שציפיתי – אבל הזמן הזה קשור לאמזון ולא לטרה.

כמובן שלאחר ה apply אני מעדכן את הקוד בגיט: אני מאוד רוצה snapshot נכון של התצורה שהפעלתי בכל רגע: אנחנו מדברים הרי על infrastructure as code. אולי שווה אפילו לעשות מקרו שלאחר apply מוצלח דואג להכניס לעדכן commit – שלא אשכח…

והנה המצב ב Aws Console:

ניסוי אחרון, נעשה שינוי אפילו פחות מהותי ב instance:

נריץ plan:

נריץ apply:

הפעם השינוי היה מהיר מאוד. זה רק שינוי של metadata ופה בכל מקרה לא ישתנה לי ה instance ID.

נכניס את הקוד לגיט. נבדוק את ה console עכשיו:

כדי שלא נשלם הרבה $$, בואו נסגור את ה landscape שיצרנו:

פקדנו terraform destroy, אימתנו שזה לא בטעות – yes, וזהו. תוך כמה שניות כל המכונות (כלומר: instance אחד בגודל nano) – למטה.

אם אני מעוניין בניתוח של מה המשמעות של destroy אני יכול לפקוד: terraform plan -destroy – ולקבל הדמייה / הערכה.
destroy כמובן לא ייגע במשאבים שלא הוגדרו ע\"י טרה.

Great Success!

מה קרה כאן, בעצם?

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

הקובץ הוא בפורמט HCL (קיצור של HashiCorp Configuration Language) ומתאר בצורה דקלרטיבית קונפיגורציה של Infrastructure. הוא מבוסס על פורמט \"רזה\" של JSON בשם UCL בה משתמשים בקונפיגורציה של nginx.
אפשר לכתוב את הקבצים בצורה ה JSON-ית ה\"כבדה\" (מרכאות מסביב לכל אלמנט, וסוגריים מסולסלים מסביב לכל Key-Value pair) – או בצורה ה\"רזה\". אנחנו, כמובן, ניצמד לצורה ה\"הרזה\".

1. בתור התחלה אנחנו מגדירים עם איזה (provider(s. קובץ טרה יכול לעבוד עם כמה ספקי-תשתיות שונים במקביל.

  • טרה תומך בעשרות \"ספקי תשתיות\", כולל Cloudflare, New Relic, MailGun, ועוד. 
  • בתוך provider מסוג aws\' עלי לספק את ה region. בחרתי region זול (בכל זאת, לבלוג אין הרבה תקציבים…)
  • צורת העבודה, והשפה (HCL) הם אחידים עבור כל ספק תשתיות – אבל הערכים שזמינים לכל ספק הם שונים לחלוטין. ל Dyn אין בכלל regions, אבל נדרשים לתאר את שם הלקוח (שלכם). בענן של גוגל יש לתאר region אבל גם project.

    2. בכל ספק תשתיות, ניתן להגדיר כמות וסוגים שונים של resources. לכל סוג resource – הגדרות משלו.
    הפורמט הוא:

    resource  \"_\" \"\" {
     
    }
    כאשר: 
    • provider צריך לתאום ל provider שהגדרנו בתחילת הקובץ
    • ה type הוא ערך מתוך מרחב ערכים שמוגדל לכל provider. למשל ל dyn יש resource בשם \"dyn_record\"
    • ה resource_name הוא שם שיזהה בצורה ייחודית את המשאב הזה בתוך ההגדרות של טרה.
    • ה config הוא רשימה של שדות, שמרחב הערכים מוגדר ע\"פ הצמד provider ו type.

    3. AMI, כפי שאתם בוודאי מכירים הוא Amazon Machine Image. מאיפה בוחרים AMI, אם לא שלכם? אני בוחר בעזרת ה AMI Locator של אובונטו (רק AMIs של אובונטו). שווה להכיר ש:

    • ל regions שונים יש AMI ID שונים: ה AMI של אובונטו בצפון וריגיניה וזה של אורגון אולי יהיה זהים ברמת הביטים – אבל יהיה להם ID אחר.
    • במכונה מסוג t2.micro או t2.nano אני יכול להשתמש רק ב AMI שעובד עם hvm (וירטואליזציה) ו ebs (אחסון). סתם שווה להכיר.
    • אפשר לקבל במהירות עוד מידע על AMI בעזרת הפקודה הבאה:
      aws ec2 describe-images –image-ids ami-a60c23b0

    בגלל שה id של ה image לא אומר לי כלום – אני מוסיף הערה. Infra as Code משמעו גם להתייחס לקונפיגורציה שלכם ברצינות שמתייחסים לקוד Production שהולך ומזדקן עם הזמן.

    4. בתוך ה config של resource type מסוים יכולים להיות אובייקטים מקוננים, כמו אובייקט ה tags.
    tags מסוימים, כמו Name – הם משמעותיים מאוד ב AWS.

    ב HCL מגדירים:

    • ארגומנט (כמו אלו של ה resource) כקלט לקונפיגורציה. משהו שאנחנו יודעים ומציבים בקונפיגורציה.
    • Attribute (\"תכונה\") כפלט של הקונפיגורציה בעת ההרצה – פקודת apply. משהו שלא ידענו לספק בעצמנו אבל מתאר את התצורה. למשל: כאשר אני יוצר instance ב AWS אני לא יודע איזה כתובת IP הוא יקבל – אבל ייתכן והכתובת הזו צריכה לשמש אותי לקונפיגורציה בהמשך, למשל: בכדי ליצור רשומת DNS.
      • ה attributes הם חלק חשוב מה state – שנגדיר אותו מייד.
    כאשר אנו מתכננים plan, טרה מאחורי הקלעים יוצר גרף (מסוג DAG) של תוכנית הפעולה להגעה למצב הרצוי. הקונפיגורציה עצמה לא מתארת את סדר הפעולות (אלא אם נוסיף אילוץ – depends_on) – טרה מחשב אותו בעצמו.
    טרה ידע מתי הוא יכול למקבל פעולות – והוא ינסה לעשות זאת ככל האפשר, אבל יימנע ממקבול מתי שהוא מסוכן. למשל: כאשר אני מחליף instance ממכונה קטנה לגדולה – טרה לא יודע מה המשמעות של כמה השניות שהמכונות הללו יחיו במקביל. בגלל שזה עלול להיות מזיק – הוא יימנע מכך ויעשה את סדר הפעולות סדרתי.
    קונספט חשוב נוסף הוא ה State
    בטרה מדברים על:
    • Last known state – המורכב מהארגומנטים השונים, משתני הסביבה בעת ההרצה, וכו\' – כל מה שטרה עשוי להשתמש בו בעתיד. הוא נשמר בקבצי terraform.tfstate ו terraform.tfstate.backup.
    • Actual state – המצב בפועל של התשתית שלנו. זהו מצב לא ידוע כי ייתכן ויש שינויים שלא נעשו ע\"י טרה, או אפילו לא ע\"י העותק הנוכחי של טרה.
    לפני שטרה מבצע תוכנית או apply הוא פונה ל APIs ולומד מה שהוא יכול על ה actual state. אנחנו בהחלט רוצים להימנע מטעויות.

    הוא גם ייעזר ב local state על מנת לבצע:

    • מיפוי נכון, למשל ה resource x הוא בעצם instance עם id כזה וכזה ב EC2
    • לשפר את מהירות הפעולה: אם instance id קיים – אני יכול להניח שכמה attributes שלו לא השתנו.

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

    • מישהו, מתישהו, הולך להפעיל את טרה עם קבצי state שאינם up-to-date (למשל: שכח לעשות git pull לפני). אתם יודעים, כל טעות בפרודקשיין עשויה להיות אסון. לא טוב!
    • כל קבצי ה state נשמרים כ plain text וכוללים את כל משתני הסביבה. יש סיכוי טוב שסודות (ססמאות, keys, וכו\') יכנסו לתוכן הקבצים. אתם לא מכניסים ססמאות לתוך ה source control שלכם – אני מקווה!
    בקיצור: ההמלצה הגורפת היא להכניס את הקבצים הללו ל gitignore. ולא לעדכן אותם לתוך ה source control.
    אז מה עושים בקבוצה?

    לטרה יש מנגנון שנקרא remote state (אולי היה אפשר לקרוא לו shared state) ששומר את ה state באחסון מרוכז (consul, S3, ועוד) – ומשתמש בהם משם. כמובן שאת שטח האכסון (למשל: S3) – חשוב להגדיר כמוצפן.

    Remote State דורש קצת עבודת הגדרות – אבל הוא בהחלט הדרך הנכונה לעבוד!

    דוגמה ל folder structure של פרויקט טרה. מקור

    נקודת מפתח שאולי לא הזכרתי מספיק בטרה, היא באמת הפילוסופיה של Infrastructure as Code. אפילו שזה קוד דקלרטיבי – ישמש אתכם מאוד לעבוד בפרקטיקות טובות של קוד.

    למשל: קבצים גדולים? חס וחלילה – קשה להתמצא ולקרוא את הקוד.
    טרה מעודדת לפרק את הקוד לקבצים קטנים יותר: כל הקבצים בסיומת tf. ו/או tf.json. בתוך אותה התיקיה – יעברו merge לפני שיורצו.

    יש כאלו שמפרקים את הפרויקט לקבצים כמו: variables, output ו main – חלוקה בהחלט לא scalable מבחינת ניהול קוד.
    תצורה עדיפה היא חלוקה ע\"פ תוכן: dns, instances, launch_configurations, security_groups, וכו\'.

    כמו כל פרויקט, וקצת מעבר – ההמלצה היא לפרק את הפרויקט לתתי פרויקטים (כמו בתרשים למעלה).
    החלוקה לתתי פרויקטים היא ה bulkhead שלכם! אם משהו משתבש – אתם תרצו שהוא ישתבש ב scope מצומצם ומוגדר היטב.

    כלים נוספים בשפת ה HCL הם:

    מודולים

    אם יש לכם 100 שירותים בפרודקשיין, אני מקווה בשבילכם שאתם לא מנהלים 100 עותקים מאוד דומים של קוד!
    אתם רוצים להגדיר מודול של service_instance, של service_elb, של service_db וכו\' – ולשכפל מעט עד כמה שאפשר קוד.

    Interpolation (התייחסות למשאבים אחרים)

    בעזרת תחביר ה interpolation אנחנו יכולים לקצר ולייעל את הקוד שלנו (וגם להשיג דברים – שאחרת פשוט לא יכולנו). התחביר נקרא לעתים גם \"dirty money\" והוא נראה כך:

    אני מגדיר בתוך רשומת ה DNS את כתובת ה IP של ה ec2 instance בשם example. ערך שאי אפשר לדעת לפני הריצה.
    ה interpolation הוא, כמובן, כלי עיקרי לטרה לקבוע את סדר הפעולות ההרצה.

    משתנים

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

    סיכום

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

    לאורך הפוסט ניסיתי להדגיש גם את האלמנטים של Infrastructure as Code.

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

    —-

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

    מדריך לכתיבת מודולים בטרה: https://linuxacademy.com/howtoguides/posts/show/topic/12369-how-to-introduction-to-terraform-modules

    Terraform Comprehensive Training – מצגת שנראה שמקיפה הרבה נקודות:
    https://www.slideshare.net/brikis98/comprehensive-terraform-training

    על סביבת הריצה החדשה: ה Docker Orchestration

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

    באה ג'אווה ומיד אחריה סביבת NET. והפכו את סביבת הריצה שהיא מערכת ההפעלה – לשניה ל VM וסט הספריות שלו. ניהול זיכרון, ניהול תהליכים, ו IPC – כבר הפכו לפחות רלוונטיים.

    משם המשכנו לענן – ופתאום סביבת הריצה המשמעותית השתנתה פעם נוספת:
    Autoscaling, התנהגות בוירטואליזציה, תקשורת בין Availability Zones או בתוכם? רשת משותפת? VPC? Spot instances? – כל השיקולים הללו התווספו לסביבת הריצה של האפליקציה שלנו.

    עכשיו סביבת הריצה מקבלת הרחבה נוספת, בדמות ה Linux Containers והמימוש המאוד פופולרי שלהם: Docker.

    סביבת הריצה העכשווית של מערכות צד-שרת

    —-

    תזכורת קצרה על Docker

    מי שמכיר – שידלג.

    להלן 2 דרכים מקובלות להעביר קוד ממכונת הפיתוח לפרודקשיין:

    דרך #1 (המקובלת יותר): להעביר את קוד המקור (או ה binary המקומפל) למכונה.

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

    דרך #2: ליצור Virtual Machine ולהריץ אותו על Hypervisor / ספק ענן

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

    הקשיים: ה image הוא לרוב גדול (כמה GB) ולוקח זמן להוריד ולאתחל אותו.
    לבדוק את ה image על מכונת פיתוח – לא כ"כ נוח: צריך הרבה זיכרון וזו מערכת הפעלה נפרדת לחלוטין, מה שמקשה מעט על תהליך debugging / בדיקת לוגים וכו׳.

    על גבי המכונה שנוצרה מה image נרצה לבצע עדכוני תוכנה (patches) וגם עדכונים של הקוד שלנו – ועם הזמן קל לאבד שליטה על מה שקורה בו. זוהי גישה שנקראת convergence.

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

    מקור

    גישת ה Containerization (להלן Docker) היא גישת אמצע:

    • נארוז את כל ה user space של המכונה: ה distro של מערכת ההפעלה + ספריות שהותקנו + קוד האפליקציה ל docker image.
    • את ה docker image נעביר למערכת המארחת בה יש hypervisor וגם Linux Kernel.
      • שימו לב ש docker image שנבנה היום עלול לא לרוץ כשורה עוד כ 5 שנים: ה Kernel (של המערכת המארחת) מתעדכן עם הזמן, ואז קריאות מערכת (system calls) – עלולות להפסיק ולהיתמך. הנה דוגמה להמחשה.
      • מכיוון שכל ה user space ארוז ב docker image – אין בעיה להריץ הפצות שונות זו לצד זו: Debian לצד OpenSUSE, לצד CentOS.
    • ה docker image ירוץ כ container על המכונה המארחת:
      • יכולת ה Linux Containers (בקיצור LXC – זו שהחלה את המפכה) מאפשרת להריץ תהליך נפרד עם isolation מסוים ברמת מערכת ההפעלה:
        • namespaces – הפרדה ברמת המודעות לתהליכים אחרים, תקשורת, ומערכת קבצים. pid, hostname, וה ip שהתהליך ייחשף אליהם הם וירטואליים – ומבודדים משאר העולם.
        • cgroups – הגבלה ברמת צריכת המשאבים. לא ייתכן שתהליך שנמצא ב cgroup אחר ישמש ביותר מ %x של CPU.
      • Docker הוסיפה אבסטרקציה נוספת למערכת הקבצים ול Network stack.
    • ה overhead של כל container שרץ הוא זניח: כמעט ורק זיכרון (בניגוד ל VM). אין בעיה להריץ 15 וגם 50 containers על אותה המכונה ביעילות – ממש כפי שניתן להריץ 15 או 50 תהליכים על אותה המכונה ביעילות.

    ה tradeoff של פחות isolation (יחסית ל VM) – אבל ניצולת גבוהה של משאבים קוסמת מאוד לחברות השונות: "על ה images שלנו אנחנו סומכים!". כל עוד המערכת המארחת מריצה רק containers שלי – הדאגה מבחינת אבטחה ו/או "חטיפת משאבים" היא נסבלת לחלוטין.

    עוד דבר נחמד ש Docker עושה הוא בנייה של ה docker image בשכבות.

    כאשר דוקר הוריד למכונה את ה docker image של שירות #1, הוא הוריד כל שכבה בנפרד. כעת, את שירות #2 הוא יכול להוריד במהירות, ממש כמו התקנה של source code / binary – כי רק השכבה של MyService 2 השתנתה.

    כנ"ל לגבי שירות #3 – שעושה שימוש חוזר ב layer הגדול של אובונטו.

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

    • שכבה שדורשת עדכון – תגרור הבאה מחדש של כל השכבות מעליה (כי מדובר בדלתאות), ולכן יעיל יותר להגדיר את השכבות באופן שמירב העדכונים יהיו בשכבות העליונות.
    • שכבה שמסירה קבצים, גדולים ומיותרים ככל שיהיו, לא תחסוך את הורדת הקבצים הללו – שוב, כי מדובר בדלתא. אם הקובץ גדול כדאי לבנות image ייעודי ורזה יותר של מערכת ההפעלה / אותה שכבה עם קבצים מיותרים.
    • ה docker images של מערכות ההפעלה השונות הם מינימליים ולרוב כוללים סט כלים מצומצם ביותר (bash, grep, package manager, ורק מעט מעבר) ולכן יהיה עליכם להוסיף שכבות משלכם.

    ישנן כמה מוטיבציות עיקריות ליישום Docker:

    • ניצול טוב יותר של משאבים – ובמיוחד בסביבה של מיקרו-שירותים.
      • חשבו על שירות הגיוני ונחוץ, אך שצורך לא יותר מ 1% CPU ממכונה קטנה של ספק הענן שלכם.
    • שיפור תהליך ה Continuous Deployment – כאשר יש פחות סבירות לתקלות שנובעות מחוסר התאמה בין סביבות הפיתוח, הבדיקות, והפרודקשיין. למשל: "אופס! שכחנו לעדכן ב deployment script עדכון של libssl שאיזו ספרייה שלנו משתמשת בה"
      • עקרון חשוב כאן הוא immutable infrastructure (או servers) – אותה הסברתי בפוסט נפרד.
    • Easier) Multi-Cloud deployment) – אם לצורך גיבוי, פריסה גאוגרפית טובה יותר, זמינות שאינה תלויה בספק ענן יחיד, גישה לשירותים של ספקי ענן שונים (למשל: BigQuery) או לצורך צמצום ה Lock-in.
    הסיכונים, גם הם קיימים:
    • קונספט חדש, שעדיין לא הבשיל לרמה של הקונספטים הקיימים.
    • שיתוף משאבים הוא נהדר, אבל לא לכל טכנולוגיה. למשל:
      • ברובי on ריילס צריכת הזיכרון היא גבוהה למדי – מה שמגביל על הרצה של הרבה containers על אותה המכונה.
      • ג'אווה אגב, גם לא טמנה את ידה בצלחת: ובשל שיקול תכנוני שנראה נכון בזמנו – גם תהליך פשוט של ג'אווה יכול לצרוך מאות MB של זיכרון.
      • מערכות שעושות שימוש אינטנסיבי בזיכרון (Redis, בסיסי נתונים in-memory)
      • מערכות שעושות שימוש אינטנסיבי ב I/O (למשל: בסיסי נתונים. אפרט עוד בהמשך).
    • עלויות מעבר והתאמות הנדרשות לסביבה החדשה: התאמה של תהליכי deploy, תהליכי CI/CD וה debugging. עד שלא תעבדו חודשיים-שלושה עם Docker בפרודקשיין – לא תגלו הכל.
    סיימנו עם דוקר, ובחזרה לפוסט…

    —-

    הכירו את ה Container Orchestration Frameworks

    Docker עצמו אינו מספיק, במיוחד לא לסביבת production מורכבת.

    • מישהו צריך להרים את ה containers הנכונים ובזמן. איך מתבצע עדכון גרסה של התוכנה?
    • מישהו צריך לשמור שאם container נפל – יקום במקומו אחד אחר.
    • מישהו צריך לדאוג שאם מכונה עמוסה מדי, יזיזו container רעב למשאבים – למכונה אחרת.
    • מישהו צריך לדאוג שאם יש דרישה לעוד כוח מחשוב (high traffic?) – מישהו ירים עוד containers על מנת לספק את הצורך.

    ה"מישהו" הזה – נקרא בימנו Container Orchestration Framework.

    נכון, Docker הוא כ"כ דומיננטי כיום, שאני בכלל לא מתייחס לאלטרנטיבות, ובראשן rkt (נקרא כמו: "rock-it") של coreOS. בהמשך ארחיב על קוברנטיס – Framework שמספק גם תמיכה ניסיונית ב rkt. גם Lock-In לדוקר הוא משהו שיש ומנסים להימנע ממנו.

    Container Orchestration Frameworks (בקיצור: COF) יש כבר לא מעט – והן מתפתחות במהירות:

    • הכל התחיל ב Kubernetes ו Mesos, כך נדמה לי.
    • אמזון ומייקרוסופט נבהלו שהנה "אובד" ה Lock-in לעננים שלהן, ומיהרו לפתח את ECS ו ACS – בהתאמה.
    • HashiCorp, בעלי המוניטין המרשים בעולם ה DevOps הציגו את Nomad – החזון שלהם לעולם ה COF.
    • Docker, שמאחוריה חברה מסחרית הבינה שהפוטנציאל המסחרי נמצא ב COF הרבה יותר מאשר הוא נמצא ב Docker – והצטרפה לחגיגה בעזרת Swarm, הממותג כ ״COF הרשמי".

    אפשר לעסוק עד בלי די בכוחות הפועלים מסביב ל Ecosystem של ה Linux, ובתחרות העזה שמתנהלת בין ה COFs השונים. זה לא יקרה בפוסט הזה 🙂

    אני רוצה להציג COF לדוגמה, וקצת לצלול לאופי של Framework שכזה.
    אני אציג את Kubernetes שהוא היום הפתרון המוביל מבחינת יכולות ובשלות.

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

    קדימה לדרך, קוברנטיס!

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

    נתחיל בהגדרת המונחים הלוגים העיקריים בעולם של קוברנטיס:

    Pod – היא יחידת ה deploy הקטנה ביותר. בד"כ זה יהיה קונטיינר יחיד, אבל יכולים גם להיות 2 או יותר קונטיינרים בפוד – שרוצים להריץ אותם ביחד.

    Service – הוא הפשטה לקבוצה לוגית של Pods (מסוג זהה) והמדיניות המתירה גישה אליהם. לקוח של המערכת ניגש ל virtual IP של ה service ומשם המערכת מבצעת routing + load balancing ל pod מתאים כלשהו.

    Volume – הוא בעצם Mount של Storage ל Pod. ב Docker יש קונספט של Volume, אבל הוא פחות או יותר mount של folder מה host – ואינו כולל lifecycle מנוהל (למשל: ניקוי הנתונים לאחר שה Container ירד). קוברנטיס מציעה Persistent Volume שיחייה גם לאחר שה Pod ירד.

    Namespace – יחידה לוגית שמרכזת משאבים כמו הנ"ל (Pods, שירות, ו Replica Set), ומבודדת אשכולים שונים שלהם זה מזה. למשל: production ו staging.

    הנה תרשים ויזואלי של האלמנטים הללו:

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

    חשוב להדגיש שזהו תרשים גנרי:

    • לקוברנטיס יש תצורות מעט שונות בעננים השונים: Azure, AWS EC2, IBM Blumix, GCE, Open Stack  ועוד.
    • יש לא מעט מקום לגמישות ו customization, אני אנסה לתאר תצורה פשוטה וסטנדרטית ככל האפשר.
    הרכיבים הכחולים הם רכיבי Runtime, בעוד הרכיבים האדומים הם רכיבי Management

    ה Kubernetes Cluster מורכב מ Nodes ו Master. המכונות עצמן מנוהלות ו provisioned ע"י פתרון הענן / פתרון שאינו קוברנטיס. ברגע שה Master עולה ומזהה ברשת את ה kubelets המותקנים על ה nodes – הוא מתחיל לפעול.

    ה Master עושה scheduling של ה pods שנדרשים ממנו ל nodes השונים, ע"פ כללים שונים. הוא מעביר לכל kubelet את ה podspecs הרלוונטיים (בד"כ: קבצי xxx_pod.yaml) וה kubelet פועל מול ה container engine (בד"כ: Docker) על מנת להוריד את ה docker images המתאימים, לקנפג אותם, לחבר להם volumes – אם קיימים, ולהריץ אותם.
    ל Kubelet יש עצמאות לעשות restart ל containers שאינם מגיבים.
    כל ה Pods על אותו node יכולים לתקשר זה עם זה בעזרת localhost או IPC. קונטיינרים באותו ה pod משתפים ביניהם גם storage.
    ה Pods השונים מזוהים ע"י Labels (צמד key/value – לצורך זיהוי) ו Annotations (מחרוזות המשמשות כ metadata לצורך קלות הניהול).
    Replica-Set מוגדרת כקבוצה של Pods התואמים ל Label Selector, או פרדיקט, בנוסח:
    role = webserver, application != honeypot.
    כאשר role ו application הם ה keys של ה Labels, ו webserver ו honeypot – הם ערכים אפשריים.
    המערכת תדאג שה Replica-Set תשאר בגודל הרצוי – ואם למשל נפל node וחסרים Pods ב replica-set – המערכת תשלים אותם אוטומטית.

    מי שמנהל מרכזית את ה Replica-Set הוא רכיב בשם Controller Manager – הרץ כחלק מה Master. ה Master נדרש בעיקר לשינויים ולא לריצה שוטפת. אם הוא נופל, אי אפשר יהיה לבצע שינויי קונפיגורציה – אבל ההתנהלות בתוך ה nodes תמשיך לפעול כרגיל. עבור צרכים של Higher Availability, ניתן להפעיל יותר מ Master אחד.הרכיבים המרכזיים ב Master הם:

    • API Service, החושף את ה REST API בו משתמשים ה kubectl ו/או ה Management UI של קוברנטיס. הוא אחראי ל input validation ובדיקה שהתצורה המבוקשת תמיד תקינה.
    • ה Controller Manager הוא רכיב הניהול המרכזי. הוא רץ בלופ תמידי שבודק את מצב המערכת (נתונים מגיעים מה cAdvisors דרך ה Kubelet וה API Service) מול התצורה הרצויה וכל הזמן מנסה להביא את המצב הקיים למצב הרצוי.
      • Replication Controller, Endpoints Controller, Namespace Controller, וכו' – הם תתי הרכיבים של ה Controller Manager.
    • ה Scheduler שהוא רכיב המנהל שורה של כללים עסקיים ("Policies") ומבצע שינויי תצורה ב Cluster בכדי לספק High Availability, ביצועים מספיק טובים, ו Quality of Service. כאן בעצם מגיבים למצב המערכת (high / low load, ביצועים לא מספיקים, מחסור במשאבים וכו') – ומשנים את התצורה הרצויה בכדי לשפר את תגובת המערכת.
    • etcd – פרויקט אחר של גוגל לניהול key/value בצורה מבוזרת המשמש לאחסון כל ה state של ה cluster.
      • ניתן להריץ את ה etcd או על המאסטר או כ cluster נפרד (עבור higher availability). אני בחרתי לצייר אותו בתרשים מחוץ ל Master.
    עבור צרכני המערכת, מה שנגיש הוא ה Services. הם אלו שדרכם ניגשים ל APIs / Endpoints של המערכת.
    את ה load balancing / service discovery הראשוני של ה services נעשה בעזרת DNS. קוברנטיס מספקת DNS משלה שהוא bulit-in בשם Kube-DNS. ניתן להשתמש בחלופות אחרות ל service discovery ו load balancing – אבל Kube-DNS היא הדרך הפשוטה.בתוך ה Node, יהיו פעמים רבות מספר Pods מאותו הסוג (המזוהים ע"י אותם ה Labels). את ה load balancing והחיווט הפנימי בתוך ה Node – עושה רכיב בשם ה kube-proxy.

    אם יש פתרון multi-cloud (ולכן multi-kubernetes-cluster) – אזי load balancing מוקדם יותר יעשה ע״י DNS חיצוני, למשל כמו זה של Dyn או Akamai.

    Kubernetes Management Dashboard. מקור: Kubernetes

    מדוע Stateful Pods הם בעייתים בקוברנטיס?

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

    ל Database בקוברנטיס (וב Docker בכלל) יש כמה בעיות. קוברנטיס פותרת כמה בעיות, כמו היכולת לנהל lifecycle מורכב יותר ל Pod – אבל זה רחוק מלהספיק:

    • שיתוף של דיסק בין כמה Pods הוא בעייתי. ה Database זקוק למקסימום I/O בכדי לפעול. אפשר לחשוב על דיסק משותף כ Bandwith משותף שמתחלק – אבל זה יהיה לא מדויק בכלל. הבעיה היא ב latency. אם מדובר בדיסק מכאני, שבו ה Database צריך להתחרות על התור בהזזת הראש המגנטי – מצב ה latency יהיה חמור, אבל גם ב SDD – יש עניין של latency כאשר יש ריבוי קריאות. רבות מהאופטימיזציות של ה Databases היום – לא יעבדו בצורה טובה בכלל, כאשר הדיסק משותף עם עוד Pods.
    • אפשר להגדיר Pods "ענק" שרץ לבד על המכונה – וכך פותרים את בעיית שיתוף הדיסק. מצד שני – זה לא מצב טבעי (היום) בקוברנטיס, וזה פותח פתח לקונפיגורציות מורכבות יותר לאורך כל המערכת.
    • מה קורה כאשר רוצים לעשות Replicas לבסיס הנתונים (מצב דיי שכיח)? – הקוניפוגרציות של קוברנטיס גם לא חינניות למצב הזה – והן הולכות להסתבך עוד יותר.
    • נפילה של master ו/או Replica היא לא עניין זניח – ופה כמה הנחות יסוד של קוברנטיס לא עובדות יפה.
    בקיצור: ההמלצה הגורפת היא לא לנהל בסיסי נתונים בקוברנטיס ו/או Docker – במיוחד לא ב Production. כנ"ל לגבי מערכות שהן memory hungry וזקוקות למלוא רוחב ה memory bus על מנת לפעול בצורה יעילה.

    שווה להזכיר את Minikube – סביבת הרצה לקוברנטיס שאפשר להריץ על המחשב האישי. המגבלה: יש רק Node אחד. היא מתאימה לפיתוח ולבדיקות פונקציונליות.

    סיכום

    Container Orchestration Frameworks לוקחים את עולם ה Containers לרמה הבאה – והמאוד מוחשית. ה Frameworks הללו מציעים כמה יתרונות חשובים – אבל הם עדיין לא הגיעו לרמת הבגרות של פתרונות הענן הקיימים.

    קוברנטיס, שקצת יותר סקרנו לעומק – הוא ה Framework הבשל והמפותח ביותר כיום. אחד הרשמים החשובים, שאני מקווה שהצלחתי להעביר, הוא שהוא לא משהו פשוט. קוברנטיס הוא לא עוד AWS Lambda, אלא פתרון ברמת מורכבות של… חצי ספק ענן. אם ללמוד לעבוד עם עוד ספק ענן לוקח X מאמץ, לעבוד עם קוברנטיס עשוי לקחת X/2 מאמץ.

    ה Sweet Spot הנוכחי של קוברנטיס (או Frameworks אחרים) הוא מערכת של Stateless Services, ללא בסיסי נתונים, וללא תלויות מורכבות בין השירותים ו/או ה Pods השונים.
    רבים מאלו שמאמצים Container Orchestration Frameworks היום, עדיין משתמשים בהם רק בסביבות הפיתוח והבדיקות – ועדיין לא בפרודקשיין.

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

    "האם הבחור הזה מתאים לנו?" (על מודל החשילות)

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

    מקור (https://www.fastcompany.com/27454/dee-hock-management). Dee Hock הוא המייסד והמנכ"ל האגדי של חברת ויזה, והוגה דעות חשוב בתחום הניהול.

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

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

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

    • אם אנחנו קרובים למועמד ויכולים לעמוד על טיב הניסיון – זה דבר אחד.
    • אם אנחנו שומעים "סיפור" – זה דבר אחר.

    האם שינוי הוא קשה?

    חברת הייעוץ ghSmart, המתמחה בתהליכי גיוס, פיתחה מודל בשם מודל החשילות (Malleability).
    המודל הזה בא לעזור ולנבא אלו תכונות סביר יותר שמועמד יוכל לשנות / להתאים לתפקיד החדש – ואלו פחות.

    מודל החשילות בא לסייע בדילמה: "הבחור הזה נראה לי ממש מתאים חוץ מא' וב' – כמה סביר שהוא יתאים את עצמו לתפקיד?"

    כמטאפורה:

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

    נ.ב. – הפוסט נכתב בלשון זכר, רק מכיוון שזה מפשט את הכתיבה / קריאה.

    —-
    [א] – גילוי נאות: אני בעל 15 שנות ניסיון בתעשייה, ובאמת שאין לי תמריץ "לזלזל" בחשיבות הניסיון.

    על Effective Software Design (או ESD)

    תקשיבו: הנה נושא חשוב שמעולם לא כיסיתי בבלוג.

    לא התעלמתי לגמרי. כתבתי מסביבו:

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

    מהו תהליך ה"דזיין" (כלומר: Software Design) הזה? תהליך שכל מפתח משתתף בו מספר פעמים בשנה?

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

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

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

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

    אז איך עושים דזיין – בצורה לא יעילה?

    אני אפתח בכמה דוגמאות כיצד שאני נתקלתי בהן, כבר יותר מכמה פעמים:
    דזיין = הצגת הפתרון
    ישיבות דזיין רבות סובבות סביב התיאור של מה שהולכים לעשות: בעיה –> פתרון.
    הקהל מודרך בתוך סיפור שאין לו רקע משמעותי לגביו. כמובן גם שאין לו מושג על ההתלבטויות שהיו – אך לא הגיעו לידי מימוש.
    הפורמט הזה אולי טוב בכדי לשתף בידע את קהל השומעים, אך הוא איננו יעיל באיתור בעיות משמעותיות ושיפורן.
    במקום לדון בבעיות הגדולות, פעמים רבות הזמן של הישיבה מושקע בכיסוי מפורט של הפרטים השונים (והברורים מאליהם) של הדזיין. "כן… בחרנו להשתמש ב Database!", "יש לנו controller ו view על מנת לייצר את ה UI!"
    אם מטרת הדיזיין היא לשמוע "הממ… כן.. זה נשמע הגיוני.." – אז זה הפורמט הנכון עבורכם!
    דזיין = "חפירה" בסכמת בסיס הנתונים
    סכמת בסיס הנתונים היא השתקפות, במידה רבה, של המודל הקונספטואלי, עליו דיברתי בהרחבה בפוסט על DDD.
    המודל הקונספטואלי מרכיב בתוכו הנחות משמעותיות על דומיין הבעיה והפתרון שלה –> שזה מצוין!
    סכמה של בסיס נתונים (אם אין מודל קונספטואלי) – היא כלי יעיל להעלות על בעיות מהותיות ושיפורים אפשריים.
    שתי הבעיות הן:
    • המודל / סכמת בסיס הנתונים היא רק מימד אחד של התוכנה שנכתבת – ואזורים חשובים אחרים כנראה לא זוכים לכיסוי.
    • חוק התכנותיקה קובע: רמת הדיון תותאם לרמת הפרטים המוצגים. כאשר מציגים טיפוסים של עמודות, אינדקסים, ו null / not null – הקהל נוטה לחשוב ברמה הזו ולמצוא שיפורים ברמה המשנית הזו. כן, אולי יהיו כמה שיפורים – אבל הפרטים הגדולים יותר של הדזיין נוטים להיעלם מאחורי הפרטים הקטנים והלא חשובים.
    תוכנות wireframe, כמו axure, מכילות סט כלים על מנת לייצר low-fidelity wireframes בהם יש פרטים חסרים / לא שלמים / קווים לא ישרים המחצינים את חוסר הבשלות / שלמות של ה wireframe.
    כאשר מציגים למשתמשים wireframe מלוטש ומהוקצע – הפידבקים נוטים להיות על הליטוש: צבעים, מיקום של כפתורים, וטקסטים.
    כאשר מציגים למשתמשים low-fidelity wireframe – הפידבקים על המהות, ה flow, והתוכן המוצג – תופסים חלק משמעותי יותר.
    דזיין = 90 דקות של מסירות – ואז שריקת סיום

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

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

    סיכום ביניים

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

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

    אז איך עושים דזיין – בצורה יעילה?

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

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

    אם מישהו (anyone) מהצוות שיעבוד על הפיצ'ר לא יודע לדקלם, כשמעירים אותו ב 3 בלילה, בשתי שפות שונות (לפחות) – מהי הבעיה שהולכים לפתור…. אז יש פה פוטנציאל פספוס גדול.
    אני נוהג לשאול בזמן עבודה על דזיין, מישהו אקראי – שיסביר במשפט או שניים מה בעצם רוצים להשיג כאן. כשהוא לא מבין ומחדדים לו – אני שומע איזה אסימון נופל, ומתגלגל למקום טוב יותר.
    הקשר (context)
    חשוב מאוד להבין היכן הקוד / מודול / שירות המדובר נמצא ברחבי המערכת הקיימת:
    • מי פונה אליו?
    • למי הוא פונה?
    • באיזה flows גדולים של המערכת הוא מעורב.
    זה נשמע טריוויאלי – אבל זה הרבה פעמים זה מידע שחסר, ואף אחד לא מעז לשאול.
    תרשים קטן כזה, על הלוח / דף שצולם באייפון / פאוור פויינט – מבאר מאוד את הדברים – ומעמיד אותם על דיוקם.
    הוא כמעט תמיד שווה את ההשקעה.
    על התרשים שווה להסביר את ה flows החשובים. אחד או כמה. זה יכול להיות בטקסט או בדיאגרמה.
    אני אישית מאוד אוהב UML 1.x Collaboration Diagrams.
    בגלל שאני רגיל לשרטט אותם – אני גם עושה זאת במהירות.
    לפעמים ה flow החשוב – הוא בתוך המודול (או שירות) שלנו.
    לפעמים ה flow החשוב – הוא בין המודול שלנו לאחרים.
    מה שחשוב הוא לא להציג תרשים בפורמט כזה או אחר.
    מה שחשוב הוא "לשים על השולחן" את ה 1 עד 3 flows החשובים ביותר ולראות שהם:
    • פותרים את הבעיה שלשמה אנו עומלים, ובצורה טובה.
    • שהם אכן הדרך הכי פשוטה שאנו מזהים לפתרון הבעיה.
    • שהם משתלבים במערכת הקיימת בצורה יפה, ולא מסבכים דברים. פשטות היא ערך מרכזי.
    • שלא עולים מקרי קצה, אמיתיים או בעייתים – שכדי לשים לב אליהם כבר מעכשיו. עולים? מצוין – נחשוב איך מתמודדים איתם. לפעמים מקרה קצה אחר יהפוך את כל הדזיין על פיו.
    בשלב הזה כבר יש לנו (= קבוצת האנשים שעמלה על הדזיין) כבר תמונה טובה של הכיוון אלינו אנחנו הולכים: מהי הבעיה? מהו ההקשר? ומה הפתרון המוצע.
    זה השלב לעצור.
    Stop!
    ועכשיו נרצה להתמקד בדילמות / החלטות הגדולות ביותר שלקחנו כאן. בטח התלבטנו עם עצמנו ו/או עם אחרים על משהו.
    מצאנו את דרך א' כלשהי – שנראה שתעבוד. יהיה אפשר לכתוב קוד באופן הזה שירוץ בצורה נכונה.
    הנטייה האנושית היא לקבע, להתרגל, ולהסתגל לאותה דרך א' – כי "היא פותרת דברים" או "זה עובד!".

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

    הנה דוגמה לאופן לתאר החלטה גדולה של דזיין:

    ——
    החלטה גדולה מספר 1: איך השירות שלי מקבל נתונים שלהם הוא זקוק?
    אופציה א': שירות אחר יעדכן אותנו בכל שינוי דרך RabbitMQ
    • יתרונות: פשוט… יעיל ….
    • חסרונות: הרבה הודעות ….
    אופציה ב': השירות שלנו יקרא לשירות השני בכל פעם וישלוף את הנתונים.
    • יתרונות: פחות הודעות ברשת. הנתונים יותר up-to-date
    • חסרונות: התלות "מרגישה" לא נכונה.
    בגלל xyz בחרנו באופציה א'.
    ——-
    תיאור שכזה הוא בסיס לסיעור מוחות איכותי.
    • סיפקנו לאנשים בדיון מידע עומק מספיק על מנת שיעקבו אחרי ההחלטה שלנו.
    • אנו משקיעים זמן בדברים החשובים ביותר – הרי זו "החלטה גדולה"
    חלק גדול מפריצות הדרך בסיעורי מוחות שכאלו קורים כאשר המשתתפים מסכימים עם ההחלטה – אבל לא עם ההנחות!
    מישהו אומר: אבל לא לקחתם בחשבון את חסרון x באופציה א'. זו בעיה ממשית כי….
    ערעור הנחות היסוד מוביל לעתים לבחירה באופציה השנייה שהועלתה, ו/או ליצירה של אופציה שלישית.
    לא תמיד דיון על החלטה יוביל לשינוי – אבל הסבירות להגיע לשיפור ("קפיצת מדרגה קטנה") בסוג כזה של דיון היא גבוהה כמה מונים מפורמט של דזיין בנוסח "הנה חברים – זה הפתרון. לכל שאלה שתעלו – יש לנו תשובה".
    אני ממליץ להתעקש על דיון ב 2-3 "החלטות גדולות" עבור בדזיינים משמעותיים.
    מה זה "משמעותיים"? נניח, דזיינים שהולכים להשקיע בהם שני חודשי עבודה מלאים של מפתחים, או יותר.
    המודל
     
    כפי שציינתי – המודל (שלרוב מתבטא כסכמה של בסיס נתונים, רלציוני או לא) הוא כלי יעיל לדיון ושיפור הדזיין.
    הדיון במודל יהיה יעיל יותר כאשר:
    • נשמיט שדות לא חשובים. created_at ו updated_at אולי הם שדות רצויים – אבל יש סיכוי טוב שהם לא באמת חשובים לדיון. כלל זה גם טוב אם המודל מאוחסן ברדיס, או MongoDB – למשל.
    • נשמיט טיפוסים של בסיס הנתונים, כדי להימנע מדיונים משניים.
      • הדיון על varchar vs. char vs. text ב postgreSQL הוא מעניין – אבל לא מצדיק את ההשקעה ברוב המוחלט של הפיצ'רים.גם אם מדובר בדיון 1 על 1 – הרשו לעצמכם לדלג על הדיון הזה.
    • נתאר את השימושים העיקריים של ה data, אם מדובר בכמויות / קצבים משמעותיים.
      • דיון קצר על אינדקסים ומבנה הסכמה, לאור השימוש המצופה – כן יכול להיות דיון משמעותי ששווה את הזמן.
      • כמו כן: העובדה שיש לנו מיליון אובייקטים / רשומות שנוספים כל יום – הוא מידע שעלול לערער הנחה ו/או חלק אחר בדזיין של המערכת. דיון על כמויות שימוש במודל עשויות להעלות נקודות שלא היינו חושבים עליהן אחרת.
    דוגמה: הצגה פשוטה ויעילה של מודל. מתמקדים בפרטים העקרוניים / משמיטים את הפרטים המשניים.
    צ'ק ליסט
    לכל ארגון ולכל מערכת – יש את הטעויות הנפוצות שלה. בעיות אבטחה או privacy, חשיבה על האופי המבוזר של המערכת, אי חשיבה על scale, תצורת פרודקשיין, איך לקוחות מסוג מסוים משתמשים בפועל במערכת, וכו' וכו'.
    הרכיבו לעצמכם את הצ'קליסט הקצר, היעיל, והכי מחובר לקרקע שאתם יכולים – על מנת לנסות ולתפוס בעיות בזמן תהליך הדזיין. עברו על הצ'ק ליסט לבד או ביחד – מה שעובד הכי טוב.
    ———–
    תהליך דזיין כמו שתואר למעלה אפשר לעשות ביום-יומיים, עם צוות מיומן.
    אפשר לעשות ישיבה אחת לא רשמית אחרי כמה שעות לשתף רעיונות, ועוד ישיבה לקראת הסוף – לגבש אותם.
    אם כל מפתח ישתתף בדזיין כל ספרינט, הסיכויים להשתפר ו"לשפשף" את התהליך – גדלים.
    כמה עצות כלליות:
    זדיין הוא לא נוסחה מתמטית
     
    ולכן זה לא סוג הפעילות שיעיל לעבוד עליו לבד לאורך זמן.
    אם אני יושב עם עצמי לבד בשקט ו"חושב על דזיין" – אחרי שעה בערך אני מפסיק להיות יעיל. אני זקוק להפרייה-הדדית. לדיונים עם אנשים. לספר, לשמוע, להחליף רעיונות.
    אני אישית מוצא השקעה של שעה-שעתיים-שלוש בה אני "משרבט" קוד, שלד של flow כפי שאני מתאר לעצמי אותו – כיעילה ל"הזרמת חמצן" לחשיבה.
    הלו? – שנות התשעים עברו
    תוצר טוב של דזיין הוא לא הפתרון הכי גנרי, ולא הפתרון שמיישם מספר רב ביותר של תבניות עיצוב ™.
    רדו מזה! חשבו על פשטות, על תחזוקה, על הרמוניה עם המערכת הקיימת, על עקרונות SOLID או GRASP.
    עשו דברים הגיוניים, שעובדים לביזנס שלכם.
    דזיין הוא תהליך של קונצנזוס
    שזה אומר כן… תהליך חברתי. לא הדבר שהכי טבעי לכל אנשי התוכנה על כדור הארץ.
    במהלך הדזיין חשוב להגיע להבנות משותפות, ולפשרות במקומות הפחות משמעותיים.
    אם בתהליך לא יצרתם תמונה משותפת לכלל האנשים שיעבדו על הקוד, וגם מעבר לכך – אז… חבל.
    אם אתם משקיעים שעות בדיון האם להעביר את שדה ה data ב json ברמה העליונה או רמה משנית – אז …. באמת חבל.
    מהנדס תוכנה, חכם ככל שיהיה, שלא יודע להתגמש ולהתמקד בעיקר – עלול להוביל את הדזיין לאזור לא יעיל.
    הדזיין לעולם לא נגמר
     
    מסמך הדזיין – יעלם לו בדרך כלל בתיקיה בה הוא נשמר. אחרי חודש-חודשיים – הוא כבר כמעט לא רלוונטי.
    יש נוסחה שאומרת שההתיישנות של מסמך הדזיין = המרחק הפיסי שלו מהקוד x אורך המסמך.
    ולכן, מסמך דזיין שמופיע כשני עמודים של readme.md בתוך ה git repository – הוא זה שהסיכוי שלו להישאר רלוונטי הוא הכי גדול.

    הרבה יותר חשוב מהדזיין, או מישיבת ה Review (אם יש כזו) – הוא הידע, ההבנות, והחשיבה שנעשו. התהליך שעברנו בזמן העבודה על הדזיין.
    "חשיבת דזיין" תמשיך להיות בשימוש תוך כדי כתיבת הקוד, תוך כדי Refactoring בקוד, או תוך כדי דזיין / עבודה על הפיצ'ר הבא באותו האזור של המערכת.
    בעזרת מטאפורות, תרשימים פשוטים ומאירי עיניים, וקוד ברור שמחצין את הכוונות – אפשר לשמר את חשיבת הדזיין שנעשתה לאורך זמן, ולהנחיל אותה למפתחים הבאים שיעבדו על הקוד.
     
     
    שיהיה בהצלחה!