יום ראשון, 23 ביולי 2017

רברסים 2017

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

אם אתם לא מכירים את כנס רברסים - חפשו בגוגל...
לדעתי זה הכנס הכי משמעותי בעולם התוכנה שמתקיים בישראל.
אני חושב שחוץ מאשר הגימיקים (שזה שטויות) - הוא משתווה לכנסים הטובים ברמה הבין לאומית דוגמת QCON ו/או ;GOTO.




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

אני הצעתי סשן על Effective Software Design (או ESD) - שיתבסס על פוסט באותו נושא שפרסמתי לא מזמן.
נתקלתי בעוד 20~ הצעות של אנשים שאני מכיר - שזה תמיד נחמד!


הצביעו לסשנים שנראה לכם שתרצו ללכת אליהם. אני הצבעתי 😇.



איך מצביעים:
  • נרשמים באתר: https://summit2017.reversim.com/
    • אני מקווה שישלחו למי שנרשם לאתר תזכורת להירשם לכנס. כל המקומות נתפסים בד"כ ביום הראשון להרשמה.
  • ניגשים להצעות: https://summit2017.reversim.com/proposals

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

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

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



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




ככה לפחות אני עבדתי.



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



יום שישי, 21 ביולי 2017

קוטלין (Kotlin) למפתחי ג'אווה ותיקים - חלק ב': פונקציות

המשך לחלק א': קוטלין (Kotlin) למפתחי ג'אווה ותיקים - חלק א': הבסיס


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

כרגיל, ננסה ללמוד עוד קצת על הדרך:


  1. הנה כמה קל להשתמש בקוד ג'אווה: אני מבצע import מתוך java.lang.Math לפונקציית החזקה (power).
    בג'אווה, בכדי לייבא מתודה הייתי צריך להדגיש: import static. בקוטלין - ויתרו על התחביר המיותר.
    שווה לציין שכל שלכל קובץ של קוטלין מתבצע מאחורי הקלעים import לשורה של חבילות: *.java.lang וכמה חבילות של קוטלין.
  2. כאשר מספר הוא עשרוני, הקומפיילר אוטומטית מניח שהוא מסוג Double. לא צריך לכתוב d בסוף המספר (אבל כן צריך לכתוב F אם אתם רוצים שיוגדר Float).
  3. כך נראית פונקציה - שוב: מאוד דומה ל Go, מאוד "מודרני".
    שימו לב לטבעיות בשימוש בפונקציה pow שהגיעה מספריה בג'אווה.
  4. הדרך להפעיל (invoke) פונקציה - היא כמו בג'אווה.
  5. זו הדרך הפשוטה להציג רק 2 ספרות עשרוניות למספר - בעזרת פונקציית format של ג'אווה.
  6. אני יכול לקרוא לפונקציה תוך כדי שאני מציין את שמות הפרמטרים כמו שהוגדרו בפונקציה (ואז סדר הארגומנטים לא משנה).
    זה אולי קריא יותר, אבל ה IntelliJ מוסיף תגיות מאוד דומות בכל מקרה (כיביתי אותן כרגע).
  7. זו הדרך לבצע formatting לאלפים + 0 ספרות לאחר הנקודה - שוב, בעזרת פונקציית format של ג'אווה.

הנה הפלט:




Nullable Types

בוודאי אתם מכירים שה Exception הנפוץ ביותר בג'אווה הוא NullPointerExcpetion.

כמו שפות מודרניות אחרות, יוצרי קוטלין החליטו להגדיר את השפה כ "null-safe by default". כעיקרון, אין nulls, אלא אם אתם מתירים אותם.


  1. זו תהיה שגיאת קומפליציה. מה פתאום לקבוע ערך null? אין מצב!
  2. אם אנחנו מגדירים ש y הוא מסוג Nullable String - אז אפשר לקבוע בו ערך null. בסדר.
  3. גם זו שגיאת קומפילציה: השתגעתם? לקרוא למתודה ()length למשהו שעשוי להיות null? אנחנו לא רוצים nullpointerException!
  4. פה הקומפיילר חכם: אם כבר בדקתי שהערך איננו null - אז יאפשרו לי לקרוא למתודות על האובייקט ה nullable.
  5. דרך אחר לעשות זאת, להשתמש באופרטור ?. במקום . - שמגן עלי בפני nullPointerException.
    אם y הוא null - אזי תוצאות כל הביטוי תהיה גם היא null.
  6. מה קורה עם מחלקה שאני מביא מג'אווה? בג'אווה - כל האובייקטים הם Nullable.
    אתם רואים שאני צריך לבנות מבנה דיי מורכב (ולא מעניין) על מנת להגן על עצמי מ NullPointerException.
    החלטה תכנונית של שפת קוטלין היא לא להגן עלי בכוח בפני אובייקטים של ג'אווה - כי כך אני רגיל. ההגנה ברמת הקומפילציה היא רק בפני אובייקטים של קוטלין שהם Nullable.
  7. בכל זאת, קוטלין מספקת לי תחביר מקוצר ובטוח לעבודה עם אובייקטים שהם Nullable. התחביר הזה תופס גם לאובייקטים של ג'אווה, וגם לאובייקטים של קוטלין שהם Nullable (ואולי יש להם פונקציה שערך ההחזרה שלה הוא Nullable).
    במקרה הזה, מכיוון ש ()getExtID מחזיר null (נניח), כל הביטוי יוערך כ null - ולא ייזרק NullPointerException.
  8. לקוטלין יש כמה כלים לעבוד עם רשימות שחלק מהאיברים בהן עשוי להיות null.
    גישה ראשונה היא השימוש בפונקציה let שתפעל רק אם הערך הוא לא null.
    אפשר להשתמש ב let גם ללא קשר לרשימת איברים.
  9. גישה שניה, היא להשתמש בפונקציה / פילטר בשם ()filterNotNull, כלומר: להשאיר רשימה הכוללת רק איברים שאינם null.
  10. אני יכול לבדוק אם משתנה הוא null ולהגיב בהתאם.
  11. או בגלל שזו פעולה שכיחה, להשתמש באופרטור ה :? (נקרא Elvis Operator) - בכדי להשיג בדיוק אותו הדבר בכתיבה מקוצרת.
  12. אם אני ממש מתעקש, אני לומר לקומפיילר: "עזוב אותי באמאשלך! אני אסתדר עם ה null-ים שלי בעצמי", בעזרת אופרטור ה .!!.
    אופס!, חטפתי KotlinNullPointerException.


הנה הפלט:




ערכי החזרה מיוחדים


שימו לב לחבר'ה הבאים:



1. לפונקציה foo לא הגדרנו ערך החזרה. היא בעצם בעלת ערך החזרה מטיפוס Unit (בצורה לא מפורשת).


    Unit הוא כמו void בג'אווה - אבל ניתן לשמור את הערך (עבור גנריות של הקוד).
    אם יופיע בלוג "kotlin.Unit" - מכאן זה מגיע.

2. ניתן להגדיר את אותה הפונקציה כ Unit בצורה מפורשת.
3. הפונקציה fail היא מסוג Unit, אבל בעצם היא לעולם לא תחזיר Unit - כי תמיד היא זורקת Exception (שימו לב שבקוטלין לא משתמשים ב new).
4. ניתן להגדיר פונקציה שלעולם לא תגיע ל return - כבעלת ערך החזרה מטיפוס Nothing.


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

5. כאן נקבל שגיאת קומפליציה מסוג Conflicting declaration - הקומפיילר לא יודע איזה טיפוס להגדיר ל data:
    Int - בגלל Zoo?
    או אולי Any (ה root בהיררכיית האובייקטים בקוטלין, כולל null) - בגלל ש fail הוא מטיפוס Unit?

6. במקרה הזה הקופיילר רגוע: מ ()gail לא יכול לחזור ערך (הוא מסוג Nothing), ולכן data יוגדר כטיפוס Int.


מעניין אולי לציין ש null הוא singleton מטיפוס ?Nothing.





default value ו vararg



  1. אני יכול להגדיר בפונקציה פרמטרים עם ערך ברירת מחדל - למשל: cores.
  2. אני יכול לקרוא לפונקציה עם כל הארגומנטים (ה annotations הם של ה IDE).
  3. אני יכול לקרוא לפונקציה ולהשמיט את הארגומנט - ואז לקבל את ערך ברירת המחדל.
  4. הנה הגדרתי פונקציה לחישוב ממוצע ה CPU utilization במכונה - ע"י חישוב הממוצע של ה cores.
    שימו לב שניתן להשתמש בכתיב מקוצר (=), אם הפונקציה גוף הפונקציה הוא ביטוי (expression) בודד - גם אם אין ערך החזרה. הגדרה כזו נקראת shorthand function.
  5. אני יכול גם להגדיר מספר משתנה של פרמטרים - בעזרת המילה vararg (המקבילה של ... בג'אווה).
    המשתנה core הוא מטיפוס <Array<out T  - אסביר את הנושא של out, כשנגיע ל Generics.

    אם יקראו ל printStats עם 2 פרמטרים - הפונקציה הראשונה תופעל.
    אם ל printStats עם מספר שונה של פרמטרים - הפונקציה השנייה תופעל.


התוצאה:




פונקציות מסדר גבוה

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


  1. הנה אנחנו מגדירים פונקציה בשם profile המקבלת פונקציה אחרת (func) כפרמטר.
    התחביר הוא סוגריים עם רשימת משתנים, חץ (<-) וערך החזרה.
    מעבר לכך, זהו פרמטר לכל דבר.
  2. בכדי להוסיף ערך מוסף כלשהו, השתמשתי בפונקציית ה profiling של ג'אווה, המחזירה את הזמן הנוכחי בננו-שניות.
  3. הפעלה של הפונקציה func נעשית בצורה טבעית למדי.
  4. עכשיו אגדיר 2 פונקציות דומות המתאימות בחתימה לפרמטר func של profile: מקבלות 2 מספרים שלמים - ומחזירות ערך של מספר שלם
  5. כעת אני סקרן לדעת איזו פונקציה יעילה יותר מבחינת ביצועים!
    כך אני מפעיל את הפונקציה "הגבוהה" profile:
    הקומפיילר צריך לדעת שאני רוצה לשלוח רפרנס לפונקציה ולא להפעיל אותה, את זה עושים בעזרת האופרטור :: - המחזיר reference לפנוקציה.
    הקפדתי על ארגומטים עם ערך זהה, על מנת לא להטות את בדיקת הביצועים 😉
    אם אני רוצה רפרנס למתודה של אובייקט, התחביר הוא object::method.
  6. מה קורה כאשר אני רוצה להגדיר חתימה של פונקציה שלא מחזירה כלום?
    אם אגדיר רק (Int) - הקומפיילר יתעלם מהסוגריים ויניח שמדובר בפרמטר מסוג Int.
    עלי לציין ערך החזרה מסוג Unit (כפי שראינו מוקדם יותר בפוסט) - ואז הקוד יתנהג כמצופה.

הנה הפלט:


אלף ננו-שניות הן מיקרו-שניה (ולא מילי-שניה, לא לבלבל!).
הממ... משהו מוזר לי בזמנים של הפונקציה add - הייתי מצפה לכ 50,000 ננו-שניות (5 הפעלות של פונקציה) ומטה (אופטימיזציות של הקומפיילר)...


Lambda Expressions

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

לא היה נחמד יותר לכתוב את גוף הפונקציה inline?



  1. הנה אני יכול לכתוב את הפונקציה inline, כ anonymous function. זה התחביר - ללא שם. זה עדיין לא מאוד אלגנטי.
  2. יותר אלגנטי יהיה לכתוב את אותה הפונקציה inline כ lambda expression. זה התחביר.
  3. מכיוון שהקומפיילר יודע מה החתימה של profile - זה מיותר לציין לו טיפוסים על הפרמטרים, ולכן ניתן לכתוב את הפונקציה בצורה קצרה יותר.
  4. חשוב לציין שאם אני עושה extract variable ל lambda expression, והיא כבר לא inline - הקומפיילר לא יידע להסיק את הטיפוסים של הפרמטרים - ויש לציין אותם בחזרה.
  5. לצורך ההסבר, נעבור לעבוד עכשיו עם פונקציה דומה ל profile בשם profileOne, המצפה לפרמטר אחד בלבד.
    שימו לב שהחלפתי את סדר הפרמטרים בפונקציה, כאשר func הוא הפרמטר האחרון. מייד אסביר מדוע זאת היא הקונבנציה ב higher order functions בקוטלין.
  6. כאשר יש פרמטר יחיד לפונקציה, לא צריך להגדיר אותו. אפשר להשתמש בצורה מקוצרת המדלגת על ההגדרה (<- num) ישר לגוף הפונקציה. אם לא הוגדר שם משתנה - ההתייחסות אליו תהיה כ it.
    זה יכול להיות קיצור נחמד, אבל הייתי ממליץ לכם להימנע ממנו כאשר יש פונקציות מקוננות - אז זה נהיה מבלבל.
  7. הנה הסיבה מדוע הקונבנציה בקוטלין היא שהפונקציה תהיה הפרמטר האחרון: אם ורק אם הפונקציה היא הפרמטר האחרון, אפשר לכתוב את גוף הפונקציה מחוץ לסוגריים.
  8. למה זה טוב? זה שימושי אם אתם רוצים לייצר משהו שדומה ל DSL (יש עוד מה להרחיב בנושא בפוסטי המשך).
    למשל: הגדרתי את הפונקציה enhance (שאולי מוסיפה לוגים, בדיקות אבטחה, ניטור, וכיוצ"ב) ואז אני פשוט שולח לה קוד. זה דומה מאוד ל DSL.
  9. אשנה קצת את ה layout של הקוד בכדי להדגיש: אתם יכולים להגדיר פונקציות שלכם, שנראות "כמו" מילה בשפה. כמה מבלבל הוא לראות enhance שכזה (מבלי להכיר את קוטלין) - ולא למצוא בגוגל מה הוא עושה 😏

אז עם כל התחביר הנחמד הזה של למבדה, מה הטעם להשאיר את ה Anonymous Function?
יש מקרים שבהם הוא בכל זאת שימושי, למשל: כאשר אתם רוצים לעשות return מתוך מקומות שונים בתוך הפונקציה.
מקרה אחר: אני יכול להגדיר return type - שאולי הוא subtype של מה שמגדירה הפונקציה מסדר-גבוה, המארחת.



Closures

פונקציה אנונימית ו lambda expression מסוגלים לגשת למשתנים של הפונקציה שעוטפת אותם - וגם לשנות אותם (זה שוני מג'אווה).


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

משתנה שניגשנו אליו בתוך Closure לא "יוקפא הערך שלו" - כמו בג'אווהסקיפט, למשל.

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





סיכום


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

האם סיימנו לכסות את נושא הפונקציות?
עוד לא.

יש עוד Local Function, Infix Functions, Inline Functions, Extension Functions - ואולי עוד שכחתי משהו.

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


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



יום רביעי, 19 ביולי 2017

על 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.
לפעמים קל לשכוח את זה.



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



יום שלישי, 18 ביולי 2017

קוטלין (Kotlin) למפתחי ג'אווה ותיקים - חלק א': הבסיס

קוטלין?!

קוטלין (על שם האי קוטלין) היא שפה static-typed, עם תחביר מודרני, הרצה מעל ה JVM. היא פותחה ע"י JetBrains - חברת ה IDEs הנודעת מרוסיה.

החבר'ה של JetBrains כתבו הרבה קוד בג'אווה כחלק מפיתוח ה IDEs שלהם. התחושה - שהקוד verbose מדי. הם התלבטו בין Ceylon (של RedHat, המתקמפלת גם לג'אווהסקריפט) וסקאלה, אבל ממספר סיבות - החליטו שאף אחת מהשתיים אינה מתאימה להם.

הפתרון: לפתח שפה בעצמם.



שש שנים אחרי, חברות טכנולוגיות כמו Uber, Netflix, Pinterest ועוד - משתמשות בקוטלין: בצד השרת, ובאנדרואיד.
קוטלין היא דיי חדשה, ה GA שלה הוא החל מפברואר 2016.

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

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

בקצרה:
  • לקוטלין יש תחביר דומה מאוד לג'אווה - אבל מודרני ומינימליסטי. אלמנטים רבים בתחביר שלה מזכירים את השפה האחרונה שסקרתי בבלוג - Go.
  • פונקציות הן First Class Citizens. שמעתי טענה ש Kotlin היא "שפת Object-Oriented ו Functional" - טענה מוגזמת לטעמי: immutability ו pure functions הן לא משהו מפותח בשפה.
  • לקוטלין יש Interoperability טוב מאוד עם ג'אווה - הרבה יותר טוב מסקאלה.
  • לקוטלין יש coroutines (יכולת שהיא עדיין ניסיונית) - היכולת להריץ תהליכים רזים ברמת ה runtime של השפה, עם כלים פשוטים לטיפול במקביליות, כמו async, yield ו await.
  • לקוטלין יש IDE מצוין - עם תמיכה מתקדמת. זה חשוב.
  • קוטלין יכולה להתקמפל לג'אווהסקריפט. שימו לב שלא כל תוכן הספריות הסטנדרטיות תומכות גם ב JVM וגם ב JS - ויש סימון מתאים. ה Interoperability עם ג'אווהסקריפט הוא קצת יותר מורכב, בשל האופן הדינאמי של ג'אווהסקריפט.
  • בדומה ל Swift - הגבילו בשפה את השימוש ב Null.
  • אין Checked Exceptions (יששש!)

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

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





שלום, קוטלין!


תודו שפאן (fun) נשמע הרבה יותר טוב מדף' (def - נשמע כמו מוות)

הנה ה Hello World של קוטלין.

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


הקוד בקוטלין מתקמפל ל bytecode של ה JVM (עם הסיומת kt לשם קובץ ה class.):


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

את ה class שנוצר בקומפליציה לא ניתן להריץ, ללא ה runtime של קוטלין: kotlin-runtime.jar.

אם עובדים עם command line הכי פשוט לארוז את הפרויקט ב jar עם הקומפיילר של קוטלין, לצרף את ה runtime - ואז להריץ:

$ kotlinc <class name> -include-runtime -d <jar name>
$ java -jar <jar name>



משתנים והשמות



  1. משתנה מגדירים בעזרת המילה השמורה var. קודם מופיע שם המשתנה - ורק אז הטיפוס (הפוך מג'אווה או C).
  2. ניתן באותה השורה גם לאתחל ערך.
  3. בעצם, ונראה את זה שוב ושוב: מה שהקומפיילר יכול להסיק לבד - לא צריך להגדיר לו. c יוכר כ Int כי זה הערך שהשמנו לו.
    var אינו "כלי קיבול גנרי". c מעתה והלאה - הוא static type מסוג Int.
  4. המילה השמורה val מגדירה ערכים שהם "immutable" (ליתר דיוק: פשוט לא ניתן לקבוע ערך אחר - בדומה ל final בג'אווה).
    בדומה לרובי, ניתן להשתמש במספר בקו תחתון, בכדי להקל על קריאת אלפים (או כל חלוקה אחרת שתרצו).
  5. בדומה לג'אווה, אני יכול להכריז שערך הוא מטיפוס Long ע"י הוספת האות "L" בסוף המספר.
  6. זו שגיאת קומפילציה. מדוע?
    כי המשתנה a לא אותחל, וקוטלין לא מקבלת השמה לערך שאינו מוגדר. אין אתחול באפס או null.
    בקוטלין כל המספרים הם אובייקטים. אין פרמיטיביים.
    אובייקטים לא יכולים לקבל ערך null, אלא אם הגדרתי אותם ככאלו (על כך בפוסט המשך).
  7. גם זו שגיאת קומפילציה! מדוע?
    אם אני מציב Long ב Integer (או להיפך) - עלי להצהיר על הטרנספורציה במפורש.
    אין casting, ואופן הצרנספורמציה הוא שימוש בפונקציה שהתנהגותה מוגדר היטב.
  8. כך צריך לבצע את ההמרה. להזכיר: b הוא אובייקט לכל דבר - אין פה autoboxing.


מחרוזות



  1. מחרוזת היא עוד אובייקט בקוטלין, כאשר יש ערך - לא צריך להכריז על טיפוס.
  2. כמו בפייטון (או עוד שפות) ניתן להגדיר Raw String בעזרת מרכאות משולשות.
    1. Raw Strings לא מקבלות escaping: הביטוי n\ הוא מחרוזת, ולא שורה חדשה.
    2. כמו בשפות אחרות, ה margin הוא חלק מהמחרוזת.
    3. בכדי לצמצם margin ניתן לסמן את ה margin הרצוי בעזרת סימן "|" בתחילת כל שורה, ולקרוא ל ()trimMargin.
  3. בקוטלין יש interpolation למחרוזות בעזרת סימן ה $. כאשר הביטוי שם אטומי (יחיד) של משתנה - מספיק רק סימן הדולר.
  4. כאשר הביטוי הוא יותר מאטום אחד - יש לעטוף אותו בסוגריים מסולסלים.
  5. אם רוצים פשוט להקליד $ - יש לעשות לו escaping.
  6. בקוטלין יש custom operators, והשוואה בין מחרוזות מתרחש באמצעות האופרטור == (המקביל ל ()equals)


למען הסר ספק, הנה הפלט של הקוד לעיל:





לולאות



  1. כמו בפייטון, ניתן להשתמש ב range.
    rangeTo (כלומר: ..) הוא בעצם אופרטור של אובייקט ה Int, המחזיר אובייקט מסוג IntRange שהוא <Iterable<Int.
  2. ניתן, כמובן, לעשות איטרציה גם על <Iterable<T. דאא.
    מעניין לציין ש Iterable הוא לא Lazy, והופך לרשימה מלאה בעת ה evaluation שלו. השיקול: ביצועים. זיכרון רציף יעיל יותר לגישה ע"י המעבד.
  3. אפשר גם לספור לאחור, בעזרת downTo ויש גם step.
    downTo ו step הן לא מלים שמורות בשפה, אלא infix functions - כלי דומה לאופרטור, ששווה להסביר עליו בפוסט המשך.
  4. ()listOf היא פונקציה גנרית שמקבל רשימה (varargs) של ארגומנטים - ומחזיר אותם כרשימה <List<T. כמובן ש List, הוא גם Iterable.
  5. אם אני רוצה לבצע איטרציה ולעבוד עם אינדקס - זה התחביר.
  6. אם אני רוצה להתעלם ממשתנה (להימנע ב wanrnings / קוד קריא יותר), כמו בשפת Go - אני מחליף את המשתנה שלא אשתמש בו ב _ .
    (כמובן שבמקרה הזה שלב 4 הוא הדרך הפשוטה לכתוב את הקוד).

הנה הפלט:



נמשיך עוד קצת:


בזריזות:
  1. יש while.
  2. יש do {} while
  3. בקוטלין אפשר להגדיר Label (מסתיים ב @) אליו אפשר להתייחס בלולאות מקוננות.
    כמה פשוט ונוח לומר: "אני רוצה להפעיל continue, אבל לא ללולאה הפנימית - אלא ללולאה החיצונית".
    הפקודה הן <break@<Label או <continue@<Label.
  4. יש גם repeat. האנוטציה ":times" היא של ה IDE - ואינה חלק מהקוד.
    זה מה שנקרא: "Five Whys".

הנה הפלט:




קצת על Control Flow



  1. בקוטלין אין ternary operator, קרי: v = cond ? a: b.
    הדרך המקבילה הכי פשוטה היא one liner if..else.
  2. משהו נחמד הוא ש if..else נחשב כ expression.
    1. אם, ורק אם יש לנו גם if וגם else (הרי אנחנו רוצים להימנע מ null / ערך לא מוגדר) - ניתן "לאסוף" את הערך מתוך ה expression.
    2. הערך הוא תוצאת ה evaluation של השורה האחרונה בכל בלוק - ממש כמו בשפת רובי.
    3. זה בעצם מה שמתרחש בסעיף #1 - רק שסעיף #1 הוא הצורה הפשוטה יותר לתבנית הזו.
  3. במקום switch, יש בקטולין את when.
    1. כפי שאתם רואים אפשר להשתמש במגוון ביטויים.
    2. בניגוד ל switch, ה evaluation של התנאים יפסיקו ברגע שימצא התנאי הראשון שהוא אמת. לכן הפלט יהיה ש "5 הוא ספרה בודדת", אף על פי ש 5 הוא גם מספר ראשוני, ואינו בסדרת ה 20.

הנה הפלט:




סיכום


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


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



----

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

Cheat Sheet למעבר בין ג'אווה לקוטלין. https://github.com/MindorksOpenSource/from-java-to-kotlin

יום ראשון, 16 ביולי 2017

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>_<type>" "<resource_name>" {
  <config>
}

כאשר: 
  • 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