2020-08-22

תאוריה ארגונית: מתן משוב

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

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

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

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

למשל: רבים מאיתנו רגילים לשיחות הערכה שנתיות בהן אנו מדורגים למדד ביצועים בטווח בין 1-5 (כאשר רוב האנשים נופלים לערך 3 שאומר ״אתה בסדר״). ובכן, המודל המאוד-נפוץ (ולא אהוד?) הזה, שהיה קיים בכל חברה שעבדתי בה ב 17-18 שנות הקריירה שלי - כבר נחשב, ב cutting edge של התאוריה ניהולית, כשנוי-במחלוקת במקרה הטוב - או ממש מזיק במקרה הרע.

למה? - על זה ארצה לספר בפוסט.



התאוריה המקובלת למתן משוב

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


מדוע לתת משוב?

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

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

אלו הם רעיונות ניהוליים בסיסיים ומקובלים.


מהו משוב ״טוב״?

קשה לי להאמין שיש מנהלים שעברו הכשרה בשנים האחרונות ולא מכירים את מודל ה SMART למתן משוב (ו/או יעדים):

  • Specific - דרשו תוצאה ברורה. תנו משוב על אירועים ספציפיים, עם דוגמאות.
  • Measurable - התמקדו במדדים אובייקטיבים ככל-הניתן. לא ״לא הרגשתי שעשית עבודה טובה״ אלא יותר ״איחרת כך וכך פעמים בלוחות הזמנים ברבעון האחרון״.
  • Achievable - העובד צריך להסכים ליעד, ולהאמין שהוא מסוגל להשיג אותו (גם אם לא בקלות). לגבי משוב - עליו להאמין שמה שמתבקש ממנו הוא אפשרי.
  • Relevant - התמקדו במה שמשמעותי להצלחת העובד בתפקיד (אפשר לנסות ״לדרוש יותר״ ו/או ״להוציא אותו מאזור הנוחות״ שלו).
  • Time-based - קבעו לוחות זמנים לשיפור הרצוי. ברור ששינוי לא קורה ברגע - אבל יש גם סכנה שללא מסגרת זמנים ברורה - השינוי הרצוי ״יתמסמס״.
אפשר להקביל את ה SMART לעקרונות של Gamification: אנו ״משחקים״ במשחק השגי, אך נוכל להשיג את המעורבות של העובד רק אם המשחק יהיה צפוי (specific, measurable), הוגן (relevant achievable, specific), שלא משנים את החוקים באמצע, ועם מסגרת כלשהי (time, rewards).


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

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

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


מגמות חדשות במתן משוב


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


Feedback or Feedforward?


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

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

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

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


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

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

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

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



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

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




המשוב שלא מתיישב

את החלק הזה אני כותב על בסיס מאמר בשם The Feedback Fallacy שפורסם ב Harvard Business Review לפני כשנה. אחד הכותבים שלו הוא מרקוס בקינגהם, שאולי מוכר לכם בעקבות הרעיון שהוא מקדם לאורך שנים: ״התמקדו בשיפור החוזקות של העובדים, ולא בהתכתשות בחולשותיהם״.

כפי שציינתי, מגמה שהולכת ומתחזקת היא מתן ״משוב מתמשך״, בתכיפות, ולא כפעולה תקופתית.

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

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

ע״פ המאמר, מחקרים[א] מראים שדווקא לא כל-כך.

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

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

האם המידע הזה הוא באמת נכון? - גם כאן מוטלים ספקות גדולים:

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


לסיכום, אם אני כמנהל: 

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


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

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

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

הגישה הזו גם פחות מתיישבת עם סגנון ניהול סמכותני (״אני יודע!״) או סגנון ניהול גנרי (״מתודולוגיה ניהולית היא מה שיש לי להביא כמנהל״). 


מצוינות



אבל מה עם מצוינות?
האם אנחנו לא הופכים ל״נחמדים״ על חשבון המצוינות? סלחני כלפי בינוניות?


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

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

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

כמובן שאמירה כללית כמו ״מצוין, מלך!״ היא לא משמעותית כל-כך:
  • היא לא משדרת כנות והבנה.
  • האם אתם בטוחים שזו הצלחה? שאתם לא מחזקים משהו שנראה ברגע הראשון כמו הצלחה - אבל תצטערו על זה?
    • בוודאי אתם מכירים פרויקט שנראה נהדר בהתחלה וזוכה לתשבוחות - אבל אז מתבררים שבעצם הוא לא תופעל כל-כך טוב...
  • היא לא עוזרת לעובד לפתח את המקור להצלחה - מה שנדרש בכדי לשחזר אותה.
המודל המועדף על כן הוא משוב בנוסח: ״התוצאה טובה מאוד בעיני בגלל סיבה 1 סיבה 2 סיבה 3; מה בעצם גרם להצלחה הזו? אתה יודע להסביר?״

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

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

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

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


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

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

זו תוכנית טובה לכתיבת תסריט הוליוודי. בסרטים זה עובד. 
במציאות - זו לא תוכנית כל-כך יעילה.


סיכום


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

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

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

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



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



-------

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


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


2020-07-11

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

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

Single Layer of Abstraction Principle (בקיצור SLAP) - הופיע לראשונה בספר Smalltalk Best Practice Patterns של קנט בק (כן, שוב הוא...). העיקרון אומר שפונקציה צריכה להכיל ביטויים באותה רמת-הפשטה.


פירוש הגדרת ה SLAP


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

למשל:

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

זו הכוונה.

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


דוגמה 


הנה פונקציה (ממערכת אמיתית), שתשמש כדוגמה. קראו אותה עד הסוף:



הפונקציה אכן ארוכה. במקור היא ארוכה אפילו יותר - קיצרתי אותה לצורך הקריאות.

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

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

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


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

הכלי העיקרי לתיקון פונקציה עם רמות הפשטה שונות הוא Extract Method Refactoring. הנה התיקון שלי:



סימנתי ב:
  • צבע תכלת - מג״דים
    •  => flow logic, קוד שמנהל החלטות גדולות ב flow המערכת.
  • צבע כחול - מ״פים 
    • => פעולות טכניות ברמת הפשטה גבוהה: גישה לבסיס נתונים או מערכות צד-שלישי, הפעלה של לוגיקה עסקית ממוקדת (במקרה הזה: ולידציה), וכו׳.
  • צבע כחול עמוק - חפ״שים 
    • => פעולות לוגיות בודדות ("one liners״), control flow בסיסי, כתיבת לוגים, וכו׳.

אתם בוודאי מסכימים שהפונקציה קצרה וקריאה יותר. עכשיו היא נראית יותר כמו ״סיכום מנהלים״ - שקל לקרוא ולעקוב אחריו. כל אחת מהפונקציות שהוצאתי: ()startFlowTypeI ו ()startFlowTypeII, וכו׳ - צריכה לשמור על SLAP בעצמה, ואם לא - אוציא ממנה גם עוד פונקציות.

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


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

התשובה הקצרה, היא ש SLAP הוא בסה״כ guideline. לא כדאי להיות קנאים.

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

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

אם ננסה לשמור על SLAP ב 100% - סביר שהקוד שלנו יהפוך לקריא פחות. חשוב למצוא את נקודת האיזון הבריאה. 


מורכבת נוספת ביישום SLAP


שימו לב שהשינוי בפונקציה לא היה רק פעולות Extract function, אלא גם גם שינוי עמוק יותר למבנה. במקום להחזיר ערכי Status שונים של כישלון מגוף הפונקציה - הפכתי את הדיווח על שגיאות ל Exception ותפסתי אותו בפונקציה הראשית. ה try..catch לא היה בפונקציה המקורית.

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

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



הוספתי טיפוס חדש ופרטי של Exception בשם ValidationException. הוא ישמש אותי גם בפונקציות ()startFlowTypeI ו ()startFlowTypeII. הגדרתי טיפוס חדש כדי שאוכל ב catch להבחין בבירור בינו לבין שגיאה ממקור אחר.

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

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




סיכום

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

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

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

שיהיה בהצלחה.





2020-05-30

איך לנצח את הסיבוכיות?

בתואר שני במדעי המחשב, היה קורס חובה בשם ״סיבוכיות״. עסקו בו במושגים כמו DTime, NP-Hard, NP-Complete או PSPACE. בעצם, סיווגו בעיות קשות מדי לקטוגריות ואבחנו אבחנות שונות לגביהן.

זו בהחלט גישה של מדעני תוכנה. תאורטית.

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

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

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

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

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

בתוכנה יש שני סוגי סיבוכיות: סיבוכיות נחוצה (essential complexity) וסיבוכיות מקרית (accidental complexity). את הראשונה ראוי למתן (אפרט בהמשך) ואת השנייה יש להכחיד.

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


זיהוי סיבוכיות


שלב ראשון בטיפול בסיבוכיות - הוא הזיהוי שלה. 

סיבוכיות היא כל מה שמקשה על הבנה או שינוי של קוד.

  • אלגוריתם מורכב = סיבוכיות
  • ריבוי תלויות = סיבוכיות
  • קוד המפוזר באזורים שונים במערכת = סיבוכיות
  • קוד בלתי צפוי (פונקציות ״calc״ שמעדכנת ערך של האובייקט בבסיס הנתונים) = סיבוכיות.
  • שימוש בסגנון / קונבנציות / ספריות לא מקובלות = סיבוכיות
  • יישום Design Pattern מדהים היכן שאינו באמת נדרש = סיבוכיות
  • וכדומה....

קוד שקשה (/מסוכן) לשנות אותו - הוא מסובך. קוד שקל לשנות אותו - הוא פשוט.

שאלה: כיצד ניתן להוסיף קוד, לקוד מסובך - ולפשט אותו?

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

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

כלים, כמו IDE, עוזרים לפשט את הקוד (במעט).



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

אם דיי אנשים חושבים שהקוד שלכם הוא מסובך - אז הוא מסובך.

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

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

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

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

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

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

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

Code Review ו/או Code Inspection הם תהליכים יעילים לאיתור סיבוכיות בקוד.


זיהוי סיבוכיות בקוד לאחר מעשה

לפעמים אנו מבינים סיבוכיות של קוד רק תוך כדי עבודה על שינוי:
  • שינוי קונספטואלי אחד (״מעתה הרשה לפעולה להתרחש 3 פעמים, ולא רק 2״) - דורש שינויים במספר (גדול) של מקומות בקוד. 
    • השאיפה תמיד בקוד היא ששינוי קונספטואלי אחד - ידרוש שינוי מאזור ממוקד אחד בקוד.
  • Design Weight - הקוד גורם לנו לעומס קוגניטיבי ומאלץ אותנו זכור ולקשר נקודות, מידע שקשה ״להחזיק״ בראש מבלי לאבד פרטים ולהזדקק לחזור ולקרוא בקוד. קוד מסובך הוא כמו ספר בפיסיקה, שכל פעם צריך לחזור לפרק הקודם ולהיזכר ולהבין מחדש במה בדיוק מדובר. קוד פשוט הוא כמו עיתון שניתן בכל רגע לקפוץ לכל עמוד ופסקה - ובקלות להבין במה מדובר.
  • תוך כדי שינוי שנראה פשוט בתחילה, אנו מגלים עוד ועוד נקודות שיש לקחת בחשבון. לעולם איננו יודעים בבטחון אם סיימנו 50% עבודה או רק 10% עבודה. יותר גרוע: כאשר ככל שאנחנו מתקדמים, הבטחון שלנו מתי וכיצד יראה הסוף - הולכים ומתרחקים.

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

בספר “A Philosophy of Software Design”, שהוא הטריגר לפוסט (מזמן רציתי לכתוב על הנושא, אבל הייתי זקוק לטריגר שכזה) - וגם חלק מהפוסט מבוסס עליו - מאפיינים דמות בשם ״הוריקן טקטי״ (לקחתי לי חופש תרגום מ Tactical Tornado) של מפתח החולף על פני המערכת, תוך כדי שהוא מספק פיצ׳רים במהירות, אבל פיצ׳רים שסגורים רק ב 80% - ובסופו של דבר דורשים עוד עבודה ו/או מסבכים את המערכת. המנהלים לעתים רואים אותם כגיבורים, ״למה אין לנו עוד מפתחים שמספקים תוצאות כל-כך מהר?!״ - אבל המפתחים שנתקלים בקוד, ועוקבים אחרי הדינמיקה שמתרחשת בפועל - מבינים במה מדובר. 

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

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



אז מה עושים?


זה החלק הקשה. חפשו קצת באינטרנט - בטח תמצאו. יאללה ביי!

(זה מה שמתחשק לי לומר, אבל מרגיש לי קצת לא אחראי)

----




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

קונבנציות, Linting, תהליך Design Review, דפוסי עיצוב או SOLID, וכו׳.

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

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




צמצום שימוש בכלים מתקדמים

הורשה, Threads / co-routines, Generics, ועוד - הם כולם כלים ראויים שיש להם מקום במערכות פשוטות. עדיף לנסות להשתמש בהם בשימוש הבסיסי ביותר: הורשה בעומק של 1, Generics של פרמטר אחד, וכו׳. 
פעמים רבות אנשים נוטים להאמין שהקוד יהיה טוב יותר אם נשתמש יותר ב״כלים מתקדמים״, וכך יש שרשראות הורשה ארוכות, Thread המקצרים זמנים בלתי-מדידים (מרוב שהם קטנים), או תסבוכת של טיפוסי Generics.

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

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


פיזור הסיבוכיות

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


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

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

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


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


הוא עדיין לא פשוט לטעמי, אבל הרבה יותר נשלט / נסבל. הוא ראוי לעוד סיבוב של פישוט.

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

״החוכמה״ בליצור ביטוי קצר, תמציתי, ובלתי קריא - היא ״חכמת טיפשים״.



הכמסה של סיבוכיות 

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

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

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

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


System Decomposition

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

מתוך הספר A Philosophy of Software Design. תודה לתומר רוטשילד שהכיר לי את המטאפורה היפה הזו, ואת הספר.

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

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

הנה פונקציה לדוגמה שלא מוסיפה הרבה ערך:

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

דוגמה המופיעה בספר היא ממשק קריאת הקובץ בגירסאות המוקדמות של ג׳אווה:


האם מישהו מכם זוכר שהוא אי פעם נדרש לפתוח קובץ ללא BufferedInputStream? או הרכיב Streams אחרים?

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

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

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

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

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

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

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


סיכום


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

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

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



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

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

Defining Errors Out Of Existence - פוסט של תומר רוטשילד, על רעיון נוסף מהספר ״A Philosophy of Software Design״








2020-05-23

על מובילי-דעה (gurus) בעולם התוכנה

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

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

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

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

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



הרשימה שלי, ביום שישי כלשהו בחודש מאי


הרשימה הראשית:
  • מרטין פאוולר (Martin Fowler)
  • הדוד בוב (Uncle Bob aka Robert C. Martin) -- גם מגדיר ה SOLID וה Clean Code
  • קנט בק (Kent Beck) -- גם מיוצרי ה Wiki, גם מכותבי JUnit, גם TDD, ומה לא...
  • David Heinemeier Hansson - DHH -- גם מיוצרי ה Ruby On Rails
  • יואל ספולסקי (Joel Spolsky) -- גם אחד היוצרים של StackOverflow
  • אנדי האנט (Andy Hunt) -- גם ה "Pragmatic Programmer״
  • לינוס טורבאלדס (Linus Torvalds) -- גם יוצר הליבה של לינוקס
לא כללתי ברשימה, בכוונה, מובילי-דעה בטכנולוגיות ספציפיות (ג׳אווה, nodeJS, ראקט, גו, וכו׳) - יש כמה וכמה כאלו לכל טכנולוגיה, אך הם כמעט חסרי-משמעות למי שלא חלק מקהילת המשתמשים של הטכנולוגיה. DHH מעניין לכולם, לדעתי.

לא כללתי ברשימה מובילי דעה בעולם ה SCRUM וה Agile. רובם, לדעתי - לא ממש מעניינים. אם כבר לתת כבוד למישהו זה לזוג Poppendieck ולאריק ריס - שנמצא ברשימה למטה.

לא כללתי ברשימה, בכוונה, ״כינורות שניים״: לכמה מהדמויות פה יש כמה שותפים קרובים. למשל Dave Thomas הוא לא פחות ה ״Pargmatic Programmer״ מאנדי - אולי אפילו יותר, אבל אנדי יותר מעניין לדעתי. Jeff Atwood הוא היוצר השני של StackOverflow וגם פעיל ומעניין - אבל פחות מיואל, לטעמי.

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


רשימת ה one-trick pony:
  • אריק ריס (Eric Ries) -- מקים תנועת ה "Lean Startup״
  • ג׳ז ״הצנוע״ (Jez Humble) -- מחבר ה Continuous Delivery
  • אריק אוונס (Eric Evans) -- מוביל תנועת ה DDD
  • מייקל ניגארד (Michael Nygard) -- פשוט פרסם כמה דברים טובים! מחבר הספר "!Relase it"
אני מקווה שהכותרת אינה בוטה מדי.
אלו אנשים סופר-מעניינים שכדאי להכיר, אבל כשרציתי להמשיך עם הכתבים / חומרים / הרצאות שלהם - ראיתי שאותם רעיונות חוזרים שוב ושוב בוריאציות שונות. זה לא מוריד מחשיבותם, רק אומר שאחרי שספגתם את עיקרי הדברים - אין הרבה טעם להמשיך ולעקוב אחריהם. לפחות זה הניסיון שלי.


הדור הקודם:
  • אריך גמא (Erich Gamma) -- מהרביעיה שהגדירה את ה Design Pattern. כתב עם קנט בק את JUnit.
  • קרייג לרמן (Craig Larman) -- היה מקביל לדוד בוב לתקופה, אך הדוד בוב קטף את כל התהילה
  • פרדריך ברוקס (Fred Brooks) -- מחבר ה Mythical Man-Month
  • דיוויד פרנס (David Lorge Parnas) -- חשוב כמו פרדריך ברוקס - אבל פחות מוכר כיום.
  • אליסטר קוברן (Alistair Cockburn) וסקוט אמבלר (Scott Ambler) -- לא היו באמת צמד, אבל רק באיחוד כוחות אני מרגיש נוח להכניס אותם לרשימה החשובה הזו.
לו היינו מחברים את הרשימה בשנת 1999 - החברים בקטגוריה הזו היו במרכז הרשימה הראשית.
בשנת 2020, הרעיונות שלהם עדיין משפיעים - אבל צריך להתאמץ יותר בכדי להגיע ולהתחבר לתכנים המקוריים שלהם. רק למי שמעוניין.

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

    אני מסתכל על הרשימות, ואין דמות נשית ברשימות. בכלל.
    צר לי על כך, אבל באמת יש פחות ״מובילות״ דעה בתחום. בכדי מעט לאזן, אציין את יוהנה רוטמן (Johanna Rothman) שהספר שלה ״Behind Closed Doors״ פתח לי כמה ״דלתות״ בחשיבה, ואת טרישה ג׳י (Trisha Gee) שמופיעה יותר ויותר בכנסים בשנים האחרונות, וגם עשתה כמה Keynotes בכנסים חשובים. היא מדברת לעניין, בלי הסחות דעת וססמאות. יש גם דוברת ישראלית בשם חן שפירא (Gwen Shapira) שהגיעה לכמה פורומים מכובדים.


    מוביל דעה: מרטין פאוולר (Martin Fowler)




    זה הבחור שהשפיע עלי אישית, במידה הרבה ביותר.

    איזו חותם הוא השאיר?

    מרטין טבע כמה מהמונחים המוכרים והנפוצים בעולם התוכנה: 
    • Refactoring
    • Dependency Injection
    • (Domain Specific Languages (DSL
    • ועוד...
    מרטין חיבר כמה מהספרים החשובים בעולם התוכנה שנכתבו בשני העשורים האחרונים:


    אציין כמה מהספרים החשובים ביותר:
    • Refactoring - ספר שרובו טכני עד שעמום, אבל הפך לפרקטיקה שגורה וחשובה של כל איש תוכנה. יש גם גרסאת רובי (שפה שמובילי דעה רבים עברו דרכה)
    • Patterns of Enterprise Application Patterns - דפוסי עיצוב של מערכות מידע / מערכות ווב. ספר חשוב ורלוונטי.
    • UML Distilled היה ספר פורץ דרך וחשוב בזמנו. מרטין טען שבמקום מדריכים ארוכים ומורכבים על UML שרובם היו 500-1000 עמודים ולא ממצים - הוא יכול לזקק את העניין לספר ממצא בן 100 וקצת עמודים. הוא עשה את זה - ו״הוריד את ה UML אל העם״. שפת ה UML כבר לא חשובה כל-כך - אבל זה היה תרגיל מרשים בפישוט והנגשת מורכבות.
    • Analysis Patterns הוא ספר חשוב מאוד (ולא קל לעיכול) על מידול של ביזנס לתוכנה. כעשור בערך מרטין עבר על רוויזיה של הספר שתהיה קלה, מודרנית ושלמה - אך מעולם לא סיים את העבודה. כלומר - יש רק ספר ישן וחצי אפוי - אבל ספר משמעותי מאוד.
    מרטין חתום על סדרה של ספרים של מחברים אחרים, שהוא נתן להם את החותם שלו ("Addison wesely martin fowler signature books״). 
    המצליח בספרים הללו הוא Enterprise Integration Patterns של בחור בשם גרגור הופ - שגם הוא מוביל דעה בעצמו.

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

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

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


    מה מייחד את מרטין פאוולר?

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

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

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

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

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

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


    מה מרטין עושה היום? איפה הוא עובד?

    מרטין הוא ה״מדען הראשי״ של חברת ייעוץ תוכנה בשם ThoughtWorks. החברה הזו נחשבת (לפחות בעבר, אולי גם כיום) לחברה מובילה בתחומה. הם יצרו את CruiseControl (לפני שהגיע Hudson/Jenkins והחליף אותו) וכאשר מייקרוסופט רצו review לפרוייקט השאפתני שלהם, בשם NET. - חברת ThoughtWorks היו ה reviwer.
    לא שמעתי דעות על ThoughtWorks כבר שנים, אני יודע שהם גדלו מאוד - ומקווה בשבילם שהצליחו לשמור חלק מהאיכויות שפרסמו אותם בתחילת הדרך.


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

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

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

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



    סיכום


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

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

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

    יודעים מה, אם אני מקבל 100 לייקים באינסטגרם - אני מבטיח פוסט נוסף! 😉

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



    2020-05-16

    הפילוסופיה של יוניקס

    ראשית כל, בואו ונשאל: למה שתעניין אותנו הפילוסופיה של יוניקס? - פילוסופיה של חבורת אנשים מזוקנים משנות ה 60 וה 70 של המאה הקודמת?!

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

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

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

    אז מה היא בדיוק הפילוסופיה של יוניקס?

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



    קיצור (אגרסיבי) של הפילוסופיה של יוניקס


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

    בכל מקרה, ממגוון הגרסאות, יש שני כללים שבולטים וזכורים יותר מכולם. נבחן אותם אחד אחרי השני:
    Make each program do one thing well. To do a new job, build afresh rather than complicate old programs by adding new “features.”

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

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

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

    אבל....

    מכיוון שכל אפליקציה היא קטנה פשוטה ועושה בדיוק דבר אחד - לא ניתן לבנות פונקציוליות עשירה ומורכבת, ללא הכלל השני:
    Expect the output of every program to become the input to another, as yet unknown, program.
    פונקציונליות עשירה יותר, מורכבת ע״י ״הרכבה״ של אפליקציות פשוטות בזו על זו.

    cat foo.txt | wc -l

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

    אנו משתמשים מכאן ב Pipe (אם אתם לא יודעים מה זה pipe - לכו מיד וקראו!), על מנת להעביר את הפלט לאפליקציה אחרת, wc (קיצור של word count [א]) ורק היא תשלח את התוצאה שלה ל standard output.

    תכנון ה pipe ע״י Doug McIlroy בשנת 1964. קצר, פשוט, ענייני.


    wc מקבלת פרמטרים (במקרה שלנו l-) המאפשרים לה לפעול טיפה אחרת, ובעצם לספור שורות.

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

    ה Pipe מאפשר הרכבה גמישה בין מרחב גדול כל-כך של אפליציות, ומאפשר ל Shell של יוניקס לבצע מגוון אדיר של פעולות פשוטות ומורכבות. ההצלחה של ה Pipe נובעת מתוך הגדרה של ממשק כללי ופשוט להחריד:
    • שטף של בתים (לא ביטים), בד״כ ב ASCII. כלומר: טקסט.
    • אפשר שיהיה לו סוף - בדמות EOF.
    • n\ סימן להפרדה בין רשומות (או ״שורות״)
    • +[t\ ] (כמות כלשהי של טאבים או רווחים) - הפרדה אפשרית בין שדות.

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

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

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

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

    פשטות אמיתית דורשת המון משמעת, כמו שנאמר: ״Simplicity is the ultimate sophistication״.



    סיכום 


    אז מה היא הפילוסופיה של יוניקס, ולמה היא חשובה?

    הפילוסופיה מקדמת, מיישמת, ומדגימה סדרה ארוכה של עקרונות חשובים בהנדסת תוכנה. זה כבר ערך בפני עצמו. קראו את הפסקה הבאה:
    ״Build a prototype as soon as possible. Most users looking for a new piece of software won't know what they really want until they see it, so requirements documents are often misleading about the users' real needs. The Unix design philosophy makes prototyping a central part of the methodology: give the user something, anything, up-front to criticise, and work from there.״
    אתם מאמינים שהיא נכתבה במיליניום הקודם? אז מי המציא את ה Lean-Startup? אריק ריס או מפתחי היוניקס?!

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

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

    לפני כעשור ועוד עבדתי עם מודלים אחרים של רכיבי UI, בעיקר Java Portlets או כל מיני תקנים של widgets ו gadgets אחרים. הממשק היה כמעט תמיד מורכב בהרבה - והקשה מאוד על קהילה רחבה לתרום למודלים הללו. זה לא היה פשוט.

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

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


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


    ----

    [א] הערת אגב: עם הכבוד הרב שאני רוחש לפילוסופיה של יוניקס - אני עדיין מאמין ששמות מאוד קצרים הם טעות גדולה של יוניקס שמחירה מודגם שוב ושוב. שמות מאוד קצרים קשה יותר לזכור, וקל מאוד לבלבל בינהם / לפספס את המשמעות.
    יוניקס הייתה טיפה מוצלחת יותר אם ל cat היו קוראים concat, ול wc היו קוראים wordcount (או פשוט count - מכיוון שיש לה הרבה אופציות ספירה שונות), ול man היו קוראים manual. הקנאות לקיצור הרגה את הקריאות ביוניקס.


    ----

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

    סיכום החוקים של הפילוסופיה של יוניקס. אפשר לקרוא ולהנות.

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


    2020-04-15

    תכנון נכון של API

    תכנון API הוא מלאכה עתיקה ולא-מוסדרת. כל מהנדסי-התוכנה מתכננים (או פשוט מיישמים) APIs. מחתימה של פונקציה, עד ל Public APIs בפרופיל גבוה ("Public APIs, like diamonds, are forever״).

    אם הייתי קורא כזה פוסט, הייתי רוצה שלא יעסוק ב:
    • כללי ה REST. דיי נמאס! אחרי עשור ויותר, אפשר להניח שכל מפתח מכיר אותם היטב, או לפחות יש מספיק חומר סביר בווב (כולל הבלוג הזה) בכדי לכסות את הנושא לעייפה.
      • במקום העבודה הנוכחי שלי, ירדנו מ REST - לטובת Json over HTTP. זה היה לי קצת מוזר בהתחלה - אבל היום זה נראה לי כמו צעד נבון. אפרט קצת בסוף הפוסט.
    • GraphQL או Falcor = עוד באזז / טכניקה. כמו REST יש כאן שורה של כלים וכללים שאפשר ללמוד אותם - אבל האם זה באמת החלק החשוב ב APIs טובים יותר?!
    • כללים גנריים ובסיסיים ״צרו תעוד ל API״ , ״בדקו את ה API״, ״בחרו שמות טובים ל API״. אני מניח שאתם לא צריכים את הבלוג הזה בכדי למצוא את כללי היסוד של ההיגיון הבריא.

    אז זהו. לא אעסוק בכל הנ״ל. הרשת גדולה - ואני אשאיר לאחרים לדוש בנושאים הנ״ל. עם כל החומר על ה API שיש ברשת (בעיקר: Rest, Rest, ו GraphQL) - נשארנו עם הרבה טכניקה, ומעט נשמה.

    אם אתם גיקים אמיתיים - אתם בוודאי מאמינים בלב שלם שהטכניקה מספיקה. ש < שם של סגנון טכני של APIs [א] > הוא הפתרון השלם והטוב ביותר. אם תקפידו על הכללים הטכניים - יהיה לכם API מצוין! אולי אפילו תריצו כלי Lint שייתן לכם ציון 100. מצוין!

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


    A Developer in the process of integrating a 3rd Party API -- Caravaggio, 1594


    איך מתכננים API טוב?


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

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



    API טוב מתוכנן מנקודת המבט של הלקוח - לא של היצרן

    טעות ראשונה שאני רואה שחוזרת על עצמה היא API שעולם המונחים שלו משרת את היצרן (System A) - ולא את הלקוח.

    בואו נראה צמד פעולות לדוגמה:

    SimulatePurchaseWithoutSaving(...) --> simulationId
    ApplyAndSave(simulationId, ...) 

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

    מנקודת המבט של הלקוח כנראה שעדיף

    PurchaseABC(...) --> purchaseId
    ConfirmPurchase(purchaseId, ...)

    חשוב מאוד שה API ישקף את האינטרס של הלקוח. מדוע הוא קורא ל API הזה בכלל? מה הוא רוצה להשיג?
    חשוב להשתמש במונחים שרלוונטיים אליו, ולהימנע מכל מה שלא (למשל: האם אנחנו שומרים משהו או לא = אינו רלוונטי ללקוח).
    מה יותר הגיוני? API בשם receiveEmailAndPassword או API בשם login?

    כלל חשוב לזכור:
    FOCUSING ON HOW THINGS WORK LEADS TO COMPLICATED INTERFACES

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

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



    Leaking Abstractions


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

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

    כאן גם הבעיה. העולם משתנה, הביזנס משתנה --> ולכן גם המערכת שלנו צריכה להשתנות.
    שינויים רבים הם extensions - להוסיף עוד למערכת, שינויים שלא ״שוברים״ APIs.

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

    אבל מה עם API פנימי? האם גם שם צריך להיזהר? בוודאי שכן!

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

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

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

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

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

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

    טכנולוגיות מגניבות כמו GraphQL לעתים מקלות על זליגת ההפשטות. המותג החזק ("GraphQL", ווהאו! פייסבוק! גוגל! זום!) מפחית את ההגנות שלנו בפני מה שעשוי להתהוות של ״סטטוס קוו״ שלא נצליח לעולם לשנות אותו.

    מערכת שלא מתפתחת, ולא משתנה - היא מערכת Legacy. היא ״עושה את העבודה״, אבל לאט לאט היא לא מצליחה לעמוד בתחרות מול גישות ומגמות חדשות.


    הבה נתייחס לתסריט הייחוס הבא:


    המערכת (או מיקרו-שירות) שלנו היא מערכת A, ואנו חושפים את API a ללקוח כלשהו.
    על מנת לספק את הבקשה, עלינו לפנות ל API b של מערכת B.

    • אל תחשפו ב API a רכיבים / אובייקטים מ API b. אתם קושרים את הלקוחות של Service A גם ל Service B - מה שיקשה מאוד על Service B להשתנות לאורך הזמן.
      • שכפלו אובייקטים. אובייקט Customer של API a יכול להיות זהה לחלוטין לאובייקט Customer של API b - וגם לדרוש העתקה. זו תקורה - אבל היא משתלמת לאורך זמן. כאשר API b ירצה להשתנות - הוא יכול, ורק יהיה צריך לשנות את לוגיקת ההעתקה בין האובייקטים.
    • אל תחשפו אובייקטים שלמים / עשירים מדי. יש משהו מאוד נוח, אך הרסני, בחשיפת API של קריאה / עדכון של אובייקטים שלמים של המערכת. האחריות של המערכת על האובייקטים שלה - פשוט אובדת.
      כאשר המערכת שלכם תצטרך לשנות את האובייקטים הללו בכדי לתאר התפתחות במערכת - זה יהיה קשה מאוד, ואולי בלתי אפשרי: שימושים שונים ותלויות מול האובייקטים הללו התפתחו בשאר המערכת - סוג של ״עבודה לא מתוכננת״, ואולי מאוד משמעותית - שנוספה לשינוי פשוט של API.
      • מדוע גוף האדם לא חושף את האיברים הפנימיים לעולם החיצון, שלא דרך מנגנונים מבוקרים? אולי אפשר ללמוד משהו מהטבע על תכנון מערכות מוצלחות.
      • צרו אובייקט נתונים עבור ה API (מה שנקרא גם DTO) ובצעו העתקה פשוטה בין האובייקט הפנימי (שיוכל להשתנות) לזה שאתם כובלים את עצמכם אליו לזמן בלתי-נשלט. זו השקעה טובה לטווח ארוך.
        • העתקה גם חשובה לצורך Immutability. במיוחד ב API של קוד באותה המכונה - אתם לא רוצים שמישהו יקבל אובייקט פנימי ואז ישנה לכם אותו.
      • חשפו באובייקט של ה API רק מה שהלקוח צריך. אל תהיו ״נדיבים מדיי״. צריך בכלל הזה גם לא להגזים:
        • אפשר לשלוח אובייקט עם 6 שדות - גם אם הלקוח זקוק רק ל 2, כל עוד אלו 4 שדות שהיה הגיוני לשלוח, לו הלקוח היה מבקש.
        • אפשר לשתף אובייקטים בין APIs שונים בתוך Service A. פיצול אובייקטים בתוך אותו שירות - הוא לא שינוי קשה מדי.
        • הגזמה ברמת הדיוק של ״לשלוח בדיוק מה שהלקוח צריך״ - תגרום לעיכובים בהתפתחות המערכת, דווקא מתוך התגוננות יתר. גם זה לא מצב טוב.
    • זכרו ש API הוא חוזה מחייב -- אבל זה לא חוזה שמכסה את כל הפרטים. ה compiler יצעק עלינו אם נשנה טיפוס או נסיר שדה מה API. הוא לא יצעק אם נזרוק Exception במקום שלא זרקנו בעבר או נחזיר מרחב ערכים שונה (גדול?) מזה שהחזרנו בעבר. כלומר: יש שדה מסוג String - אבל התחלנו להחזיר ערכים חדשים שהלקוחות לא יודעים להתמודד איתם.
      • כדי לוודא שה API לא משתנה ופוגע בלקוחות שלכם - צרו Automated Tests לבדוק את האלמנטים ב״חוזה״ שהקומפיילר לא יודע לתפוס.
      • התאימו את כמות הבדיקות והיסודיות שלהם - לכמות הלקוחות / חשיבות ה API. בדיקה שלעולם לא תכשל - היא בזבוז זמן לכתיבה. אנו עוסקים בניהול סיכונים.



    כמה דילמות נפוצות


    API אחד המחזיר היררכיה גדולה של אובייקטים - מול API לכל אובייקט קטן בהיררכיה?

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

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

    אם מדובר ב API בין Front-End ל Back-End ואתם מאחדים לאובייקטים גדולים כדי לחסוך latency של קריאות ברשת - אז עשו את החיבור ברמה של API Gateway - ובטח לא ברמת ה API של ה Back-End.



    ״למתוח״ API כדי להתאימו לצרכים, מול יצירה של גרסה חדשה?

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


    מתי לזרוק Exception מ API? מתי להחזיר ״אובייקט כישלון״?

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


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

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

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

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


    למה ב Next-Insurance בחרנו לא להשתמש ב REST?

    ב Next-Insurance ניסינו (כמו רבים אחרים) להיצמד לכללי ה REST בכדי ליצור אחידות ב APIs הפנימיים, ולהפוך אותם לצפויים יותר לשימוש. ל REST יש כמה בעיות ידועות כמו המגבלה להעביר payload גדול על קריאת get, או ההגדרות הלא מדויקות והניתנות לפרשנות של REST כרעיון (מעולם לא היה תקן מסודר, ומעולם לא היו פיתוחים מוסכמים ל REST מעבר למסמך הראשוני). למשל: קשה מאוד להתיישר על סכמת URLs עקבית בקבוצה גדולה של אנשים. לאנשים רבים יש פרשנויות רבות כיצד URL שהוא RESTful צריך להיראות.

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

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

    מפה לשם, עברנו ל JSON over HTTP בתצורה מסוימת. תמיד משתמשים ב HTTP POST ותמיד ה API מגדיר אובייקט (DTO) בקשה ואובייקט תשובה שעליו ישבו הפרמטרים. ה URL הוא רצף מילים שקשור לפעולה, לפעמים RESTFul - אבל לא בהכרח.

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

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


    עוד כמה קלישאות (נכונות):
    • API צריך להיות קל לשימוש, וקשה לשימוש לא-נכון.
    • בכדי לעצב API לא צריך ניירת או תהליכי חשיבה ארוכים. צרו טיוטא מהירה של ה API וכתבו קוד שמשתמש ב API הזה. זו הדרך הטובה לחשוב וללטש את ה API.
    • צייתו ל Principle Of Least Astonishment (בקיצור: POLA). 
      • ה API לא צריך להפתיע את המשתמש. ככל שהמשתמש של ה API רחוק מכם יותר - הכלל הופך לחשוב אפילו יותר.
    • השתמשו ב APIs בתבניות (Format) הנוח ללקוח, ולא למערכת. יש מין טעות כזו ש API צריך להיות נוח ליצרן ולא ללקוח.
      • אולי אתם מייצגים זמן ב Java Epoch, אבל ללקוח יהיה הרבה יותר קל לעבוד בתאריכים קריאים, קרי 2020-04-19.
    • API הוא רכיב קריטי באבטחת המערכת. זה זמן טוב להזכיר שיש OWASP Top 10 ל APIs.


    סיכום


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

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


    ----

    [א] סגנונות API נפוצים הם Falcor, gRPC, SOAP, RPC, GraphQL, REST או סתם JSON over HTTP.

    ----

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

    Public APIs, like diamonds, are forever


    2020-03-14

    עבודה מרחוק (וירוסים, קדמה, או סיבות אחרות)

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

    השאלה הראשונה שעולה היא ״איך מתמקדים בעבודה ולא ׳זולגים׳ פעם אחר פעם לפייסבוק או קאנדי קראש (או מה שפופולארי עכשיו)?״

    השאלה השנייה היא - ״איך לעזאזל אני יכול להתרכז בעבודה עם ילדים בבית?״


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

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

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

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


    מה שונה בעצם בעבודה מבוזרת?


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

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

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

    מה זה אומר, ״לעבוד יעיל״ מרחוק?


    כלים

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

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

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


    טריגרים

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

    אם התשובה לשאלה הראשונה היא ״במשרד״, ההקשר המיידי הוא ״אנחנו בעבודה. בואו נחשוב מה עלינו לעשות שקשור לעבודה״.

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





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

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

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

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

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


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



    גבולות

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

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

    איזון

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

    כשהעבודה מהבית מצליחה להיות יעילה - שבחו את עצמכם. זה הישג, וזה לא מובן מאליו!


    תקשורת 

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

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


    הרבו בתקשורת בפורום קטן (למשל, צוות), מעטו תקשורת בפורום הכללי.

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

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

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

    שפרו תקשורת טכנית

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

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

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

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

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


    ניהול אנשים מרחוק


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

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


    שעות עבודה

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

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

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

    יותר מזה: נסו לכבות את ה "online indicators״ בכלים בהם אתם עובדים, אולי תגלו שעדיף בלעדיהם.


    השקעה מול תפוקה

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

    אם אתם עובדים בארגון של CI, אז יש לכם כלל חשוב שאומר: ״כל מפתח מבצע לפחות commit ל master כל יום״. בעבודה מרחוק אני חושב שרלוונטי אפילו יותר לוודא שהכלל הזה עובד. מעורבות שלכם בקוד ומתן הערות - יעזרו לשמר אווירת עבודה. אם מישהו לא ביצע commit כבר יומיים - זה אולי מקום להעיר לו, ולשפר את הפרקטיקה:
    • סגנון פחות מוצלח: ״לא עשית commit היום! איך אני יודע שאתה עובד?״
    • סגנון יותר מוצלח: ״עבודה ב batches קטנים היא יעילה יותר בכלל, אבל היא גם עוזרת להישאר מחובר לארגון שלנו ולקצב העבודה. בוא נעשה מאמץ לשמר את הכלי הזה״.


    מוטיבציה

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

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

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

    Batches קצרים (ימים!, לא שבועות), הגדרת הפיצ׳רים בצורה מדידה, חיבור המפתח ללקוחות שלו (לקוחות קצה, או המפתח הבא שישתמש בפיצ׳ר), וכו׳ - הם כלים חשובים אפילו יותר בעבודה מרוחקת.


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

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


    פערי זמן

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

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

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

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

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

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


    סיכום


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

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




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

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

    ״תקועים בבית?״ - סט פעילויות איכותי לילדים של מכון דוידסון