להכיר את גריידל (Gradle)

Gradle (מקור השם: עריסה, Cradle – כאשר האות הראשונה שונתה ל G עבור Groovy) הוא כלי Build נפוץ בעולם הג’אווה, וכלי ברירת-המחדל לפיתוח באנדרואיד.

Gradle הוא כלי Build מודרני, מלא פיצ’רים ואופטימיזציות – שנמצא דור או שניים לפנים מהחלופה העיקרית שלו: Maven. גריידל יודע לבצע Caching ו Incremental Build ברמות הפשטה שונות – ומסוגל לשפר מאוד את זמני ה Build של פרויקטים גדולים.
 
מצד שני, Gradle מורכב יותר לשימוש, וכנראה לפרויקטים פשוטים – מייבן הוא כנראה עדיין כלי עדיף, בשל הפשטות שלו.
 
בניגוד למייבן המשתמש ב XML להגדיר את ה buildscript – בגריידל משתמשים ב DSL מבוסס שפת-תכנות. גרדייל תומכת ב Groovy-DSL ו Kotlin-DSL, כאשר בשנתיים האחרונות היא עושה מעבר לכיוון קוטלין, מכיוון שזו הולכת והופכת לנפוצה יותר ויותר (בניגוד ל Groovy – שקצת “נתקעה” במקום).
 
לו היו נותנים שם היום לפרויקט, נראה ש Gradle היה נקרא Kradle.


לגריידל אין מערכת Repositories משלה, והיא משתמשת בזו של מייבן, של ivy, או פשוט בתיקיה של מערכת הקבצים המקומית. זה יתרון גדול, מכיוון שכך אין תחרות בין “Maven Repositories” ל “Gradle Repositories”.
 
 

מה גריידל יכולה להציע מול מייבן?

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

 

הדבר הראשון, וכנראה החשוב ביותר הוא ביצועים:

  • בהרצה ראשונה, גריידל ומייבן יהיו דיי דומים. אולי גריידל תרוץ טיפה יותר מהר.
  • בהרצה השנייה והלאה, ייכנסו לשימוש מנגנונים ייחודיים ל Gradle:
    • Incremental Build – גריידל עוקבת אחר מערכת הקבצים ומקמפלת רק קבצים שהשתנו, או קבצים שתלויים בהם.
    • Config Cache ו Build Cache – שימוש חוזר בתוצרים (ברמות שונות) מהפעולות בילד קודמות.
      • תאורטית גם מייבן עושה זאת – אך בצורה משמעותית פחות יעילה.
    • Gradle Daemon – גרדייל מחזיקה תהליך (process) של מערכת ההפעלה שממשיך לחיות ברקע, להחזיק caches מיידיים בזכרון ולהנות מאופטימיזציות של Java JIT compilation.
גריידל מספקת יותר גמישות:

  • למייבן יש מחזור-חיים קבוע וקשיח, validate > compile > test > package > install, שלא ניתן לסטות ממנו, אלא ב”תרגילים”. בגרדייל יש עץ של Tasks (כמו Compile או Test) שניתן לקנפג וקל הרבה יותר להתאים את שלבי הריצה לצרכים שלכם.
    • למשל: בכדי לדלג על שלב הבדיקות או הקומפילציה ב Maven יש לעשות “תרגילים” שלא תמיד מצליחים. בגרדייל דילוג על שלבים זו אופציה מובנית.
    • קל להגדיר Custom Tasks בגריידל – וזו גמישות רבת-עוצמה. המקבילה במייבן היא למצוא Plugin שמתאים בדיוק לצרכים, או לכתוב Plugin בעצמכם – שזה הרבה יותר מסובך
  • גריידל מספקת ניהול תלויות עשיר וחכם הרבה יותר ממייבן – מה שמשמעותי בפרויקטים גדולים ו/או מורכבים.
    • למשל: במייבן תלות במודול יגרור קבלת כל התלויות של אותה ספריה (propograted dependencies, שלעתים נקרא בטעות transitive dependencies). הדבר לא מאפשר לעקוב ולנהל במדויק תלויות של מודולים.
      בגריידל אפשר לבחור או בגישה זהה למייבן, או בגישה מדויקת ונשלטת יותר.
  • גריידל מממשת את העיקרון של Conventions over Configuration, ואין צורך באמת להשתמש בכל הכלים המתקדמים יותר שלה. קושי נפוץ של newcomers הוא להבחין אלו מנגנונים הם פשוטים ו straightforward, ואלו מנגנונים הם רבי-עוצמה, אך דורשים גם הבנה מעמיקה יותר.
גריידל היא מודרנית יותר:
  • גריידל זוכה לתמיכה טובה יותר, ועדכונים תכופים יותר. למשל: כבר שנה וחצי כשיש בעיה בהרצה של JUnit 5 ב Failsafe של מייבן בצורה מקבילית – אך בגריידל הכל עובד כשורה מהגרסה הראשונה של Junit 5.
  • לגריידל יש כלים תומכים משמעותיים וטובים יותר:
    • Build Scan עוזר לנתח ולהבין בדיוק מה קרה ב Build. האם הגדרה מסוימת שרצינו אכן פעלה? לא צריך לנחש מתוך הלוגים – אפשר לבדוק בצורה ישירה.
      • גריידל מספקת Build Scan רזה יותר גם למייבן – בעיקר בכדי לתמוך במעבר ולוודא שה Build בגריידל מכסה את כל מה שקרה במייבן.
    • Continuous Build – גרדייל יכול להאזין למערכת הקבצים ולקמפל את הקוד תוך כדי שאתם עובדים.
    • Gradle Profiler – שעוזר למצוא bottlenecks בבילד ולשפר אותם. ניתן לגשת לתוצאות שלו בתוך ה Build Scan.
    • Gradle Build Debugger – בגלל שה build Script הוא שפת תכנות – אפשר ממש לדבג את תהליך הבילד כדי לנתח תקלות קשות-להבנה.
    • Gradle Enterprise – הם סט של יכולות נוספות שחברת Gradle מספקת בתשלום – כמו Central build Cache (שימוש משותף בתוצרים: מפתח אחד קימפל מודול, כל השאר יכולים להשתמש בתוצר), או כלי Diagnostic ו Analytics משופרים לבילד ולהרצת הבדיקות.
  • נטפליקס, היא תורמת גדולה של Gradle Plugins. רבים מהם היו הבסיס לפיצ’רים שהיום הם סטנדרטיים בגריידל.
  • Gradle Wrapper (שמירת תאימות מדויקת של גרסת גריידל בין מפתחים) הוא כלי פופולארי בגריידל, אך שווה לציין שהוא קיים גם במייבן (אם כי שם הוא פחות נפוץ בשימוש).
התייחסות מהירה לבאזל
ב 2015 שחררה גוגל, את כלי ה Build שלה כפרויקט קוד פתוח, ולאחרונה הוא הפך ל GA.
  • Bazel ו Gradle דומות זו לזו, יותר משהן דומות ל Maven או Ant.
  • גריידל מספקת גמישות רבה יותר, באזל היא יותר מובנה.
  • באזל בנויה יותר מסביב לניהול מרכזי (למשל: ניהול גרסאות של תלויות) בעוד גריידל לא לוקחת הנחות כאלו, ותומכת טוב יותר במציאות מבוזרת של שליטה.
  • לגרדייל יש קהילה גדולה יותר, ובגרות גדולה יותר – במיוחד בעולם ה JVM. סיכוי טוב שקהילות כמו Go ו ++C יזכו לתמיכה טובה יותר בבאזל.
  • היכולת להשתמש ב Cache מרכזי ומשותף היא יכולת ליבה של Bazel (שעליה מתבססים במידה הביצועים הטובים של הספריה) בעוד ב Gradle זו יכולת פרמיום בתשלום (Gradle Enterprise).
  • בסה”כ באופן דיי עקבי (מסקירת מאמרים ומבחנים) Gradle מהירה יותר מ Bazel – גם כאשר משתמשים ב Build Cache מרכזי.
    • מבחני ביצועים לא מעטים משווים את שתי התצורות בגרסה החינמית שלהן – ואז ל Bazel יש יתרון משמעותי על יכולת שב Gradle היא בתשלום (Central Build Cache).
  • הנה מאמר מ 2015 של יוצרי גריידל שמנתחים את באזל.
אין ספק שבאזל מכניסה תחרות וגורמת לגריידל לעבוד קשה יותר. בעוד ההשוואה בין גריידל למייבן היא מאוד מחמיאה, ההשוואה של גריידל מול באזל נראית תחרותית הרבה יותר.
הפוסט שלי נכתב על גריידל, שנראה שתמשיך להיות בטווח הנראה לעין הסביבה המתקדמת והמקובלת בעולם ה JVM. בעולמות הללו לגריידל יש עדיין יתרון משמעותי – וקהילות לא מתחלפות כ”כ מהר. חשוב לציין שבאזל היא רענון חשוב בעולם כלי ה Build, ובוודאי היא מעניינת יותר בעולמות ה Go וה ++C כבר עכשיו.

תכל’ס

כשמתחילים לקרוא על גריידל, מגיעים מהר מאוד לחומר על כתיבה של Custom Tasks או Dependency Management – שני נושאים יחסית מתקדמים ומלאי-אפשרויות.
ניתן לנהל דיון מעניין על שוני הגישות / הארכיטקטורות השונות של הכלים בן במידול עולם הבעיה, והן בזמן הריצה שלהן.
אני מניח שבשלב הזה – אתם עדיין לא זקוקים למידע הזה, ויותר מעניין היה לראות כיצד נראה פרויקט גריידל קטן. “לחוש” את הכלי.
אני מניח שאתם באים מרגע של מייבן, או לפחות מכירים אותו.
אפתח בכך שהרבה מונחים ורעיונות משותפים למייבן וגרדייל (גרדייל העתיקה ממייבן שהייתה לפניה), אבל יש גם לא מעט שוני.
סיכמתי בקצרה ובזריזות כמה מונחים שנראה לי שיעזרו להתחיל ולהתמצא. אני רק אניח את זה כאן.

Maven

Gradle

Pom.xml,
Where:

  Properties section
  Modules section     

  DependencyManagement section
  Most other sections

build.gradle.kts
Mapping to:
  gradle.properties file
  settings.gradle.kts file
  dependencies.kts file (a convention)

  java-conventions.gradle.kts (file per language being compiled)

pom.xml file (what happens when we build)

build script (that comprised of multiple files)

Plugin

Task

–  (there is one fixed build flow)

Plugin (describes build flow)

Goal

Lifecycle Task

Module

(sub) project

Dependency scope

Dependency configuration

Profile

Custom Task or Custom Properties.gradle file (depends what the profile does).

“Install” (to maven repo)

“publication” (to whatever repo)

“package”

“assemble”

בואו נראה מבנה של קובץ בילד מינימלי (שם הקובץ הוא: build.gradle.kts. הסיומת kts מציינת שזה kotlin script, ולא Groovy – שמגיע ללא סיומת):
  1. אנו מייבאים את הפלאגין של Java.
    1. בגריידל, Plugin מביא איתו שורה של Tasks ו Lifecycle Tasks (ועוד הגדרות רבות) – ובעצם קובע את השלבים השונים ב build והסדר ביניהם. במייבן ניסו לבנות תהליך אחד גנרי לכל שפות-התכנות, למרות שלשפות שונות (JavaScript, ++C) – יש צרכים שונים. בגריידל לרוב יהיה לנו בפרויקט Plugin אחד שיגדיר את ליבת התהליך ויספק גם את ה Tasks הנדרשים (Compile, Test, Jar, וכו’ – המתאימים לשפה / תהליך)
      בנוסף אולי נרצה להשתמש ב Plugins נוספים כמו: למשל War, PMD, או Reports – ולהרחיב את התהליך.
  2. ה default scope שלנו ברמה הגבוהה ביותר היא אובייקט הפרויקט, וכך אנו קובעים properties מסוימים על הפרויקט.
  3. כאן אנו קובעים באלו Repositories לחפש את ה dependencies שלנו. כמו במייבן, אפשר ומומלץ לקבוע כמה repositories בכדי שיהיה גיבוי (לא עשינו את זה בדוגמה) – והחיפוש יעשה ע”פ הסדר בו נרשמו.
    1. במקום לספק את ה URL ל jCenter, אנו יכולים להשתמש בפונקציה שמסופקת ע”י גריידל ומחזירה אובייקט Repository עם ה URL הנכון (קיימים כאלו ל repositories נפוצים). פחות מקום לטעויות.
  4. כאן אנו נכנסים ל scope של ה Java Plugin (שהגדרנו בתחילת הקובץ) – ומוסיפים לו הגדרות.
    1. כברירת מחדל, גריידל תשתמש ב build בגרסת הג’אווה שמריצה אותה. זה יכול ליצור חוסר עקביות אם במחשבים שונים מריצים את הבילד בגרסאות ג’אווה שונות.
    2. בכדי “ליישר” את תהליך הבילד בצורה מדויקת יותר, אנו יכולים להגדיר לגריידל באזו גרסת ג’אווה להשתמש בתהליך הבילד. ה toolchain עוזר בקלות רבה לקנפג ולטפל בהגדרה של הגרסה שבחרנו. אם לא מצליחים למצוא מקומית את הגרסה המתאימה – ה toolchain יוריד לצורך ה build עותק מקומי של גרסת הגא’ווה שנבחרה.
    3. גם אם אתם מתכנתים בג’אווה 8 (ממגבלות מוכרות), הרצה של תהליך הבילד בגרסה מתקדמת יותר – יכולה להאיץ אותו מעט.
  5. כאן אנו נכנסים ל scope של ה tasks בפרויקט. אמנם אנו רוצים להתייחס ל Tasks שהגיעו מה Java Plugin, אך מרגע שהוספנו את ה Java Plugin והוא רשם את ה Tasks שלו – הם כבר לא משויכים אליו, אלא פשוט רשמים בפרויקט.
    1. ספציפית יש כאן כתיבה מקוצרת בשורה אחת להכנס גם ל scope של ה test plugin.
    2. ה Test Plugin תומך גם ב Junit וגם ב TestNG – ועלינו לציין לו במי להשתמש. הכל עטוף בפונקציות פשוטות ובטוחות לשימוש.
    3. בניגוד ל Maven בו יש שני Plugins: גם Surefire (לבדיקות יחידה) ו Failsafe (לבדיקות אינטגרציה) – בגריידל ה Java Test Tasks מספק את שני הצרכים, וניתן פשוט לקבוע בהגדרות אם לעצור בכשלון ראשון – או לא. אם אחנו רוצים להגדיר שלב של “בדיקות יחידה איטיות” – קל לעשות זאת ע”י שימוש חוזר ב Test Task.
  6. אנו צריכים להגדיר את התלויות לגרסה הספציפית של Junit שבה אנו רוצים להשתמש. לא פינקו אותנו ב wrapper לקונפיגורציה הזו. כמו במייבן – הגדרה של dependency בקובץ הראשי תשפיע על כל תתי-הפרויקטים (במייבן: מודולים) שלו.
    1. ההגדרה הזו מקבילה במייבן לתחביר הבא:

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

    2. מהן הפונקציות הללו,()testImplenentation ו ()testRuntimeOnly?
      נסביר עליהן בהמשך.

The Java Plugin

כפי שציינתי, מרכיב חשוב בגריידל הוא ה Plugin הליבה בו אנחנו משתמשים. הוא מגדיר הרבה דברים חשובים:
  • Tasks – בהם נוכל להשתמש.
  • LifeCycle Tasks (במייבן: “Goals”) – אליהם Plugins שונים יוכלו להתחבר, ולחבר Tasks שונים.
  • מבנה התיקיות של קוד המקור (במקרה זה ה Java Plugin שומר על הקונבנציה המורכת לנו ממייבן)
  • Dependency Management (כללים)  – כללים כיצד תלויות מנוהלות. מכיוון שלסביבות פיתוח שונות (Go, ++C, JVM) יש צרכים שונים – נתנו בגריידל ל Plugin להגדיר את הכללים המדויקים לניהול התלויות.
    גריידל מספקת תשתית/כלים עליהם כל Plugin יכול לבנות את המודל שהוא זקוק לו.
כשאנחנו לומדים לעבוד עם Gradle, חלק מהכללים נובעים מה Plugin הליבה בו אנחנו משתמשים – ולכן חשוב ללמוד ולהבין אותו היטב. במקרה שלנו – זה ה Java Plugin, וחשוב ללמוד אותו.

ל Java Plugin יש כמה הרחבות סטנדרטיות:

  • Java Library Plugin – עבור build script של ספריה המופצת לקהל רחב כספריה.
  • Java Application Plugin – עבור build script של אפליקציה. מוסיף Tasks כגון start או install. הוא מתאים הן לכתיבת שרת או אפליקציה שולחנית.
  • Java Platform Plugin – לכתיבה של סט ספריות קשורות (למשל: Junit 5 מורכב מכמה תתי-פרויקטים, הקשורים זה לזה)
  • גרסאות ספציפיות ל Groovy ו Scala – המרחיבות
ייתכן והיה נכון יותר לקרוא לו “JVM Plugin”.
אתם יכולים לעבוד עם ה Java Plugin ישירות, או כל אחת מההרחבות שלו שיכולות להקל על המקרה הספציפי. בכל מקרה, רוב ההתנהגויות בכל הוריאציות – נובעות מה Java Plugin עצמו.
התיעוד הוא כלי חשוב, ובוודאי תמצאו את עצמכם לא פעם ניגשים לתיעוד של ה Java Plugin ישירות. במסגרת הפוסט, אני אתמקד בהסבר של שני רעיונות שמעט שונים ממייבן: Lifecycle Tree, וניהול תלויות.

מחזור החיים של בילד ב Java Plugin בגריידל

נתחיל עם מקור ההשראה: מייבן.
 
בניגוד ל make, ant, וכלים אחרים שהיו מקובלים קודם לכן והיו חסרי-מבנה סטנדרטי – מייבן הגדירה מבנה סטנדרטי – שעזר להשריש best practices בתהליכי build, ולהפוך אותם לסטנדרטיים ומאורגנים יותר.
 
מייבן הגדירה שלושה Lifecycles (נקרא להם build, clean, site), שבכל Lifecycle יש שורה של צעדים קבועים (להלן: “Goals”). כל Plugin (המספקים יכולות) מגדיר באלו צעדים הוא יכול להשתתף (למשל: Fail-Safe יכול להתחבר ל verify או integration-test) ואז המפתח ראשי לחבר אותו לאחד או יותר מהצעדים הנתמכים.

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

 

המבנה בגריידל הוא דומה, אך גמיש יותר. במקום שרשרת טורית של צעדים – ישנו עץ. העץ מורכב ממשימות (Tasks) כאשר כל משימה תגרום להרצה של המשימות האחרות בהן היא תלויה.
למשל, כאשר אנו מריצים את המשימה classes (המקבילה ל compile במייבן), המשימה תגרום להרצה של המשימות compileJava ו processsResources – ורק אז תרוץ בעצמה.
כאשר מריצים פרויקט המורכב מכמה תתי-פרויקטים בגרדייל, גריידל יכול להריץ במקביל משימות שונות בפרויקטים שונים על מנת להתקדם מהר יותר. למשל: פרויקט X תלוי בפרויקטים a ו b. גריידל יריץ את שניהם במקביל. אם פרויקט a הוא קטן יותר, גריידל עשוי להתקדם בפרויקט a לשלב הבדיקות על אף שפרויקט b עדיין מתקמפל.
כפי שאתם יכולים לראות בתרשים, משימות בגריידל מסווגות למשימות רגילות (עושות משהו ; בכתום) ומשימות Lifecycle (באדום), הנועדו לשמש כעוגן / מבנה לתהליך ה build.
למשל, המשימות assemble, clean, build ו check (באדום מודגש) הן משימות Lifecycle של ה base plugin בגריידל. כלומר: הן צפויות להיות נוכחות בכל מחזור חיים כלשהו. כמפתח Task אני יכול להסתמך על כך שהן יהיו נוכחות – ולבקש שהן ירשמו ל Task שלי כתלות.
לדוגמה, ה CheckStyle Plugin (כלי לבדיקות קוד סטטיות בג’אווה) רושם למשימה Check תלות בכל ה Tasks של ה Plugin – כך שהרצה של המשימה Check תפעיל אותו. אם לפני הרישום המשימות Check ו Test עשו אותו הדבר, לאחר הרישום – יש ביניהן הבדל.
משימות ה Lifecycle מייצרות סטנדרטיזציה ומבנה כדי שה Builds יהיו פשוטים ומובנים יותר.
כאשר מדובר ב Multi-project build (המקבילה של modules במייבן), כל הרצה של משימה על הפרויקט הראשי – תריץ את אותה המשימה על כל ה sub-projects (כמו במייבן).

Dependency Configurations

זוכרים את התלויות שהגדרנו ל JUnit5 ב build script שהצגנו למעלה?
השתמשנו בפונקציות ()testImplenentation ו ()testRuntimeOnly – על מנת להגדיר תלויות.
אנו נוטים לחשוב על גרף התלויות בפרויקט כמבנה קבוע, אך בעצם גרף התלויות הוא תלוי-הקשר:
אנו רוצים למשל שקבצים וספריות מסוימות (למשל: ספריות Mocking) יהיו זמינות רק כאשר מריצים בדיקות, בעוד אנו לא מעוניינים שהקוד בפרודקשיין יהיה תלוי בהן, או יארוז אותן.
היכולת להפריד בין קוד “לבדיקות” לקוד “פרודקטיבי” מתבטאת בגריידל בשני גרפי תלויות:
גרף התלויות של הבדיקות (“testImplementation”) יורש את כל התלויות שהוגדרו בגרף של הקוד הפרודקטיבי (“implementation”) – ויכול להוסיף עליהן תלויות נוספות.
הפונקציות ()testImplenentation ו ()testRuntimeOnly – פשוט רושמות תלות בגרף תלויות. עדיין לא הצגנו את גרף התלויות של testRuntimeOnly.
בגריידל התלות ברירת-המחדל / המומלצת היא “implementation”. יש תלות בסיסי נוספת לקוד פרודקטיבי הנקראת “api” – והיא מדמה את ההתנהגות ברירת-המחדל של מייבן (מה שנקרא במייבן “compile scope”):
נניח שאני כותב ספריה (להלן “My Library”) שאפליקציה מסויימת משתמשת בה.
כאשר אני יוצר תלות מסוג “api” בספרייה Jackson, משמע שאני הופך אותה לחלק מה API שלי, ובעצם מעביר (propogate) לאפליקציה את התלות כאילו היא שלה. מעכשיו קוד באפליקציה יכולה להשתמש ב Jackson כאילו ייבאה אותה בעצמה.
כאשר אני יוצר תלות מסוג “implementation” ספריה Gson, משמע שאני משתמש בתלות לצורך המימוש שלי, אבל התלות לא מועברת הלאה. אם האפליקציה רוצה להשתמש ב Gson יהיה עליה להוסיף תלות בעצמה או להסתמך על פונציונליות שהספריה שלי מספקת, שמתשמשת מאחורי הקלעים ב Gson.
לשימוש ב api יש תופעה שלילית שנקראת Dependency Pollution:
  • קוד האפליקציה יכול להשתמש בקוד מספריות שלא הייתה כוונה להשתמש בהן.
    • המקרה הזה בעייתי במיוחד בקוד פנימי שלנו, שאנו רוצים במפורש להימנע מהשימוש בו – אך מפתחים עשויים לא לשים לב (כי ה package name תואמים).
  • בשל האופי הטרנזיטיבי של התלויות, מרחב הקוד שאני שחשוף לשימוש ע”י קוד האפליקציה עשוי להיות גדול מאוד: האפליקציה תלויה ישירות ב 3 ספריות, אך ב 50 ספריות בצורה טרנזיטיבית – הוא תסריט נפוץ.
  • יש עבודה מיותרת לתהליך ה build – בהבאת כל הספריות, טרנזיטיבית, ל classpath בזמן קומפילציה.
  • יש עבודה מיותרת לתהליך ה build – בכך שכל שינוי קוד בספריה שהובאה טרנזיבית, מעלה ספק אולי צריך לקמפל את הספריות שתלויות בו (טרנזיטיבית) – וכך קשה לבסס build cache יעיל.
בקיצור: ההעדפה בתלות מסוג “implementation” חשובה הן מבחינת הנדסת-תוכנה, והן משיקולי ביצועים של ה build.
אם אתם רגילים לעבוד במייבן “הסלחנית” במובן של תלויות – תתחילו להתרגל.
בטווח הבינוני – ארוך, בהחלט משתלם להתרגל להגדרות המדויקות יותר של התלויות כ “implementation”. בבאזל, למשל, הגדרת התלויות דורשות דיוק רב אף יותר.
בגריידל יש מנגנון נוסף, המתבטא ב Dependency Configuration בשם “runtimeOnly” ו “compileOnly” הקבילים ל scopes במייבן בשם runtime ו provided – בהתאמה.
התלויות הללו מאפשרות לנו להיות תלויים בזמן הקומפילציה ב API בלבד (לא לבלבל עם ה “api dependency configuration”), ובזמן ריצה להביא מימוש ספציפי של אותו ה API – תוך כדי שאנו מבטיחים שאנו לא יוצרים תלות במימוש הספציפי.
למשל: ספריית SLF4J, מספקת API לקומפילציה בלבד וגם מימושים הכוללים את ה API + יישום ספציפי (למשל LogBack או log4J12).
בכדי להבטיח חוסר תלות ביישום ספציפי – אנו רוצים לא לכלול את המימוש הנוכחי שבחרנו בזמן הקומפיציה – אלא רק בזמן ריצה. אם כך עלינו להוסיף את ה SLF4J API ב “compileOnly” ואת המימוש העכשוי – ב “runtimeOnly”.
נראה שאנחנו יכולים להסביר עכשיו את התלויות שראינו בדוגמה למעלה:
ספריית JUnit5 הפרידה את ה API לספריה אחת (להלן “testImplementation”, אנו רוצים אותו זמין רק לבדיקות) ואת מנוע הבדיקות – שיהיה זמין רק בעת הרצת הבדיקות (“testRuntimeOnly”).
כלומר: המקרה של JUnit 5 מעט שונה מזה של SLF4J – אבל קיימות גם וריאציות נוספות.
יצרתי סיכום של ה Dependencies Configurations הזמינים לנו בגריידל + Java Plugin:

הורשה משמע שכל תלות שהוספנו לאב – זמינה גם לבן. הקוביות הצבעוניות מתארות מה עושים עם כל גרף תלויות בפועל. אציין שוב ש “api” הן התלויות הכלליות ביותר – ושמומלץ להימנע משימוש בה עד כמה שאפשר.

סיכום

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

שיהיה בהצלחה!
—–
קישורים רלוונטיים:

המדריך המהיר לזום ברצינות

זום (Zoom) היא תוכנה שנפלה לחיינו כך פתאום, והפכה לאחת התוכנות שאנו מבלים במחיצתה הכי הרבה זמן.

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

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

קביעת פגישות: קישור קבוע או קישור משתנה?

קביעת פגישה בזום נעשית על החשבון (Account) של מי שהזמין אותה.
לכל חשבון יש Meeting Id אחד קבוע – שייחודי רק לו.
אני יכול לבחור אילו פגישות ייקבעו על ה Meeting Id הקבוע, ואלו על Meeting Id זמני.
  • Meeting Id קבוע – אנשים יכולים לשמור את הקישור או אפילו לזכור (בעזרת Alias – אפרט בהמשך). מספיק לומר בסלאק למישהו ״בוא ניפגש בזום״ – והצד השני יכול להתחבר מבלי לקבל מייל / לקבוע פגישה דרך זום.
    • יותר חשוב: אתם יודעים תמיד להיכן להתחבר אם זו פגישה שאתם קבעתם. ה Meeting Id הקבוע יהיה תמיד בזיכרון של אפליקציית הזום שלכם.
    • שימו לב שבארגונים, ה Admin יכול לחסום את השימוש ב Meeting Id קבוע, משיקולי אבטחה (לא שאני תומך בזה, לארגון שאינו ״חשאי״).
  • Meeting Id זמני – הוא טוב בכדי למנוע ״כניסות לא מתוכננות״ לפגישה. למשל: מישהו מהפגישה הבאה ביומן. לפעמים זה לא נוח ולא מתאים.
    • מקרה דמיוני לחלוטין: אמא שלכם מצטרפת באמצע פגישה רבת משתתפים…
    • עוד יתרון של Meeting Id זמני – אתם יכולים לעזוב לפגישה הבאה – ושאר המשתתפים ימשיכו בפגישה (ניתן למנות מארח אחר). זה בלתי אפשרי אם זו פגישה על ה Meeting Id הקבוע שלכם.
מה עושים? הכי חשוב להכיר את ה Tradeoff ולהחליט מה נוח לכם. אני משתמש כמעט תמיד ב Meeting Id הקבוע – כי יש לי עליו +5 פגישות ביום, ונוח לי כך להיכנס אליהן.
את ה Meeting Id שלכם אתם יכולים למצוא בהגדרות שבווב. אפליקציות הזום השונות כוללות בתוכן מספר הגדרות (אפליקציית המובייל – מעט הגדרות, אפליקציה למחשב – יותר הגדרות), אך עדיין חלק גדול מההגדרות נמצא רק בווב. ניתן להגיע אליהן ישירות בלינק או באפליקציה של זום ע״י Settings / General / View More settings.
הנה ההגדרות: כאן אתם יכולים למצוא מה ה Meeting Id שלכם, לקבוע Alias (קישור ה ״Customize״), או לקבוע אם פגישות מיידיות (שלא נקבעו מראש לתאריך) יהיו על גבי ה Meeting Id הקבוע, או לא.
שווה לציין, שאם קבעתם Person Link עם Alias טקסטואלי, באפליקציות מובייל יהיה על המשתמש ללחוץ על ״Join with a personal link name״ לפני שיוכל להקליד את ה Alias.

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

הקלטת פגישות לצורך תיעוד / שיתוף

אחד הפיצ׳רים השימושיים בזום, שמבינים לאחר זמן מה – הוא הקלטה של פגישות.
כאשר אתם מקיימים פגישה, ומישהו לא הצליח להצטרף – אתם יכולים להקליט עבורו את מהלך הפגישה.
כל פעם שיש דיון חשוב (במיוחד רב משתתפים) – אני מקליט את הפגישה. אנשים לעתים חוזרים לפגישות הללו, ולא תמיד מישהו שחשבתם עליו בזמן הפגישה.
הקלטה של הפגישה יכולה להיעשות רק ע״י ה Host (ניתן גם למנות Co-Hosts עם הרשאות דומות ל Host) ורק ממחשב. ברגע שההקלטה החלה, תהיה אינדיקציה ברורה לכל המשתתפים – בדמות עיגול אדום בפינה של המסך.
ניתן להקליט את הפגישה מקומית למחשב או לענן של זום (האופציה הזו זמינה רק למשתמשים בתשלום).
הענן של זום שומר מעין ״פורטל״ של ההקלטות של הארגון – אבל כרגע הוא מאוד מאוד בסיסי. ישנן אינטרגציות לחברות שמתמחות בניהול וידאו (כמו קלטורה הישראלית, Panpoto, Knowmia, ועוד). מיד כשהוידאו מוכן – הוא יעבור לפלטפורמת ניהול התוכן של הצד השלישי ובעצם ינוהל שם.
מבחינת איכות, ההקלטה של זום היא בעלת דחיסה גבוה מאוד, המתבססת על הנחות שתוכנת דחיסה “גנרית” לא תניח אותן (ערוץ אחד של audio – מונו, הגדרות שמתאימות לתזוזה מעטה, מה שלא טיפוסי בוידאו, וכו׳). ההקלטה היא עדיין ברזולוציה של HD כך שמסך מחשב שמשותף יהיה חד וברור.
בהגדרות של Recording (חלקן רק בווב), ניתן לקבוע הגדרות שונות לגבי ההקלטה, למשל: תמלול של ההקלטה (אל תנסו עם מבטא ישראלי). 2 הגדרות נפוצות הם אפשור של HD Video ו Group HD (ברגע שיש יותר משני משתתפים בפגישה, זום מוריד את איכות הוידאו המועבר של המשתתפים, הגדרה זו תשאיר את הדובר, בכל רגע נתון, באיכות HD).

שיתוף מסך בזריזות, ומבלי לפגוע בפרטיות

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

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

פגישת עבודה שוטפת (שלא נצמדת למצגת מוכנה-מראש) תדרוש שיתופים קצרים שונים מאנשים שונים.
אני אישית משתף מסך בעזרת קיצור מקשים (מסתבר שיש כאלו בזום), וספציפית Cmd+^+S במק.
אליה וקוץ בה: קיצור מקשים יפעל רק כאשר החלון של זום הוא הפעיל בשולחן העבודה – וזה העיכוב הראשון שפתחנו בו.
לשמחתנו, הגדרה של צירוף מקשים כ Global יהפוך אותו לזמין גם כאשר החלון של זום איננו בפוקוס.
אלטרנטיבה נוספת: לגשת לפעולות שונות מתוך ה Tray Icon של זום (לי היה פחות נוח).
את שורת הפקדים של זום (Mute, שיתוף, צ’ט, וכו – שלפעמים מתחבאת) ניתן לקבע כך שתמיד תופיע (ואז תוכלו מהר יותר לגשת לכפתורים השימושיים). בהגדרות: Settings/Accessibility/Always show meeting controls.
מומלץ מאוד, לפחות במקומות עבודה, לאפשר בהגדרות הפגישה בווב – לכל משתתף להתחיל להציג גם כאשר מישהו אחר כבר משתף מסך. לי זה חוסך במצטבר כמה דקות ביום.

פרטיות
יופי! התחלנו לשתף מסך בזריזות – איך אנחנו מוודאים שלא בטעות שיתפנו אימייל פתוח שלא כולם צריכים לקרוא? אולי בזמן שיתוף המסך מישהו שולח לי הודעה פרטית / רגישה בסלאק / Whatsapp – ותחילת ההודעה נקלטת ומוקלטת, כחלק מהפגישה? 😱
לי התקלות הללו קרו מספר פעמים. לא נעים!
חשוב להבין שזום היא סביבה בעלת סיכונים לפרטיות המשתתפים. לדוגמה, פעם היה פיצ׳ר שעזר למארח לזהות מי מהמשתתפים לא בקשב – אך הפיצ׳ר בוטל, משיקולי פרטיות מובנים.
בגדול ישנן 2 גישות לשיתוף בזום:
  • שיתוף כל ה Desktop עם כל מה שכלול בו. 
    • יתרון: אפשר לעבור בין אפליקציות במהירות – והכל משותף.
    • חיסרון: כל מה שפתוח – ניתן לצפות בו. למשל: הלינקים שלכם בדפדפן. שולחן העבודה, וכו’.
  • שיתוף חלון ספציפי, בכל פעם.
    • יתרון: שליטה גבוהה במה משותף (אך גם כאן ייתכנו ״זליגות״ של מידע פרטי. שימו לב).
    • חיסרון: מעבר אטי בשיתוף מסכים מאפליקציות שונות (IDE, ואז Github, ואז Command Line – למשל).
זהו Tradeoff אמיתי, אישי לאדם ולסיטואציה – ואין באמת פתרון שטוב לכל המקרים.
הנה כמה עצות איך לעשות את השיתופים הללו קלים ובטוחים יותר:
  • שיתוף כל ה Desktop:
    • במידה ויש לכם מסך שני – אתם יכולים לרוקן אותו לפני שאתם משתפים – ואז לשתף אותו ולשלוט ביתר קלות / זהירות מה יופיע בו.
      • לי היו קיצור מקשים להעברת כל החלונות לDesktop הראשי + קיצור להעביר חלון ל Desktop ספציפי.
      • לצערי: מאז הקורונה, ריבוי ילדים בזום הגביר את הדרישה למסכים במשפחתנו. אני כרגע משתמש במסך יחיד.
    •  ההגדרה הבאה פישטה את חיי כליל. אני חושב שהיום זו הגדרת ברירת-המחדל, אך אולי למשתמשים ותיקים יותר – היא לא פעילה. חשוב!:
    • בכל רגע ניתן “להקפיא” את שיתוף המסך (קיצור מקשים במק Cmd+^+T). כאשר אתם לרגע, למשל, מחפשים במייל או בסלאק – זה הזמן ״להקפיא״ לרגע את השידור. שאר המשתתפים יראו את התמונה שהוצגה על המסך ברגע שלפני ההקפאה – ולא ידעו שבינתיים אתם רואים משהו אחר. עוד לחיצה על הקיצור – תחזור לשדר את התוכן העדכני.
  • שיתוף חלון ספציפי במערכת ההפעלה:
    • כאשר אתם רוצים לעבור אפליקציה ולהמשיך לשתף, עליכם להפסיק את השיתוף הנוכחי – ולהתחיל שיתוף חדש.
    • צירוף מקשים הוא ה״מלך״ כאן. אם אתם משתמשים בקיצור-מקשים תוכלו לבצע מעברים כאלו בזריזות ואלגנטיות. אם לא – ההתנהלות תהיה מסורבלת ואטית.

טיפול ברעשים

הנה אחד העניינים המטרידים בזמן פגישות זום: רעשי רקע מאחד (או יותר) מהמשתתפים. יש מה לעשות – וכדאי להכיר את זה.
כאשר יש הרבה משתתפים (+10) לא תמיד הקריאה ״מי שרועש שיעבור למיוט״ – עובדת.
בעיקרון ניתן לזהות מאיזה משתמשים מגיע אודיו מעל סף מסוים – במסך ה Participant (מסך שימושי לעוד כמה צרכים):
אתם תראו ״אנימציה של גל״ בתוך הצלמית של המיקרופון – לכל מי שממנו מגיע עוצמה מסויימת של אודיו, ובתור Host אתם יכולים להעביר אותו ל Mute.
מטעמי פרטיות המארח לא יכול לעשות Unmute למשתתף – אלא רק המשתתף עצמו (וטוב שכך).
אם הרעש הוא רעש רקע, בזום יש יכולת מובנה להפחתת רעשים. זום בוחר את רמת הפחתת הרעשים באופן אוטומטי – מה שהוא לא עושה היטב. ניתן בהגדרות ה Audio של אפליקציית הזום לקבוע את רמת הפחתת הרעשים ל״High״ מה שבהחלט יעיל. ההגדרה הזו עושה פלאים ויכולה להשתיק כליל רעשי רקע של שיפוץ, גנן, שכנים רועשים, וגם ילדים צורחים בחדר סמוך.
החסרון היחידי: כאשר יש שקט מסביב – ישמעו אתכם פחות טוב, ויהיה כדאי לחזור ל Low או Auto.
בקיצור: קביעת רמת הפחתת הרעשים בצורה אוטומטית ע״י זום – לא עובדת היטב, אך בקביעה ידנית הפיצ׳ר הזה מאוד יעיל.
יש אפליקציה בשם Krsip המיועדת לעשות עבודה טובה יותר. ניתן להשתמש בה כמה שעות חינם בחודש, או לרכוש מנוי ב $3 ומשהו לחודש. כמה אנשים שעובדים איתי ממש מרוצים ממנה – אך אני עדיין לא הצלחתי להבחין בהבדלים בין העבודה שלה ליכולת המובנה של זום (כאשר מכוונת ל High).
בחזרה לפגישות מרובות משתתפים: שווה להזכיר שלמארח יש יכולת להשתיק את כל המשתתפים מלבד זה שמציג (שוב: ממסך ה Participants). כל משתמש שרוצה ״לזרוק מילה״ יכול להשתמש במקש הרווח (Spacebar) ב “Push to Talk״ – ממש כמו מכשיר קשר שצבא.
זה יעיל ושימושי, אם כי יכול להיות שלחלק מהאנשים חסרה ההגדרה. אם מוצא חן בעינכם – פשוט שתפו בארגון.

לסיום: מגניבות לתחילים

(סבים וסבתות יקרים: זה מה שהנכדים שלכם עושים כל הזמן, שאולי קצת מבלבל/משגע אתכם)
ניתן להוסיף רקעים ואפקטים לוידאו שלכם מתוך תפריט ה Start/Stop Video של זום. רוב היכולות זמינות רק לאפליקציה של זום למחשב.
יש המון מקורות לרקעים זמינים ברשת (הנה רשימה של זום, ו Unsplash – עוד אתר פופולארי). אצלנו בחברה מדי פעם אנשים ״מתכתבים״ ברקעים, ומעבירים בעזרתם מסר / בדיחה קבוצתית. למשל: ביום ההולדת אדם צפוי לראות הרבה רקעים של ״יומולדת שמח״ או הקשורים לימי הולדת. יש רקעים של סרטים אהובים, ספורטאים נערצים, וכו׳. נסו להיות מקוריים (רק בבקשה הקפידו על רזולוציה סבירה של תמונה 😊).
שווה לציין שזום, כברירת מחדל עושה Mirroring לוידאו שלכם, ולכן רקע עם כיתוב יראה לכם הפוך (אך שאר המשתתפים יראו אותו בסדר). אפשר לבטל את ה Mirroring בהגדרות הוידאו.
מה שפחות אנשים מכירים, הוא את היכולת להוסיף קובץ mp4. (ברזולוציה סבירה) כרקע דינאמי – כמו הרקעים הדימנמיים המגיעים עם זום. רק חפשו “mp4 background״ בגוגל – ותמצאו אינספור מקורות. חשוב למצוא רקע שלא מושך יותר מדי תשומת לב: ללא תזוזות מהירות, ועדיף בפוקוס-חלקי. אלו רקעים נעימים שלא גוזלים יותר מדי תשומת לב (ורוחב-פס) מהמשתתפים האחרים בפגישה.
לאחרונה נוספו לזום, פילטרים ו Studio Effects שיכולים לשנות בצורה ניכרת את המראה שלכם.

זה משעשע לרגע – אבל לא כל-כך מתאים לסביבת עבודה. אולי יותר לשיחות בזום עם הסבים / סבתות.

אם אתם רוצים אפקטים מגוונים / מושקעים באמת – אזי Snap Camera היא כנראה הכתובת.

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

כמה מחשבות על Hypergrowth

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

על איזה מדד אנחנו מדברים?

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

מתי צמיחה נחשבת ל״חריגה״?

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

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

(בואו נתעלם לרגע מ Bootstraps – שקיימים, וחברות שמגייסות הון – עוד לפני שהוכיחו Product Market-fit – שגם אלו קיימות).

האם צמיחה של 40% בשנה היא צמיחה-חריגה להייטק הישראלי? כלומר ארגון של 40 עובדים המגייס במהלך השנה עוד 16 עובדים?

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

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

אם בשנת 2010 היו כ 20 חדי-קרן בעולם (חברות פרטיות בשווי של מעל מיליארד דולר), ב 2015 כבר היו כ 100 חדי-קרן, ובעת כתיבת הפוסט יש כ 500 (ע״פ CBInsights). יותר כסף זורם לחברות סטארט-אפ => צמיחה מהירה יותר.

המונח ״חד-קרן״ נבחר בכדי לתאר ייצור נדיר וייחודי – והיום כבר מתחילים לדבר על Decacorn (חברה פרטית בשווי 10 מיליארד או יותר) ואפילו Hectocorn (אשאיר לכם לבדוק…) – על מנת לבדל את הייחודי ויוצא-דופן.

זווית נוספת:

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

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

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

לקבל פי 2 Traffic בשנה – זה לרוב לא אתגר כל-כך גדול.

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

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

חשבו על עיירה ההופכת למטרופולין (״גוש דן״) תוך 6-7 שנים: יש כאן אתגר ארגוני-ניהולי-חברתי-טכנולוגי ממשי ומשמעותי!

מה ״הבעיה״ בצמיחה-חריגה?

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

אז מה הבעיה בצמיחה-חריגה? למה לא רק לחגוג אותה?

בכל פעם שאני שומע על צמיחה-חריגה אני נזכר במשפט ״Success Killed The Punk״ (נדמה לי שהוא מהסרט The Filth and the Fury): הפאנק, הזרם החתרני כל-כך הצליח – שהוא הפך למיינסטרים, וכבר לא היה מקום לחתרנים אמיתיים.

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

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

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

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

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

  • רוב מהעובדים בחברה הם עובדים חדשים, עד הודעה חדשה!
    • בהנחה שעובד הוא ״חדש״ בשנה-שנה וחצי הראשונה שלו בחברה, עד שהוא מכיר היטב את הארגון והמערכת – אנו הולכים לחוות תקופה בה רוב העובדים הם חדשים, וזה לא עתיד להשתנות עד קצת אחרי שקצב הצמיחה יתמתן.
    • עובדים חדשים = פחות היכרות עם המערכת, הארגון, וההיסטוריה.
      • עובד חדש מכיר פחות, ולכן הוא צריך יותר עזרה ויותר זמן בכדי להגיע לתוצאות דומות.
      • לעובד חדש יש אינטואיציה פחות מפותחת מה מסוכן ו/או מה הגיוני, הוא מועד יותר לטעויות ופספוסים.
    • כאשר הארגון מלא בעובדים חדשים, במי יתייעץ העובד שהגיע לפני שבוע? בעובד שהגיע לפני חודשיים, או בעובד שכבר נמצא ארבע חודשים?
      • בסופו של דברים, עובדים חדשים יתייעצו עם עובדים חדשים אחרים – שהרבה פעמים לא יספקו תשובות מספיק טובות.
      • הידע הממוצע במערכת / ביזנס / ארגון – ימשיך ויפחת ככל שהצמיחה החריגה ממשיכה. פחות ידע = הנדסה פחות טובה.
  • טשטוש התרבות הארגונית (ו/או Engineering Culture)
    • תרבות ארגונית היא נרכשת – ויכולה להתקיים בלי מייסדיה (כפי שניסוי חמשת הקופים מדגים).
    • כאשר קצב ההצטרפות גדל – ההקניה נפגעת:
      • כאשר עובד חדש מצטרף – הוא מגיע עם ״שק של הרגלים״. למשל, אם הוא ״לא מאמין בבדיקות יחידה״ – אך התרבות היא להקפיד על בדיקות יחידה – הוא יתיישר מהר מאוד. אם כולם עושים זאת – גם הוא יעשה.
      • כאשר הרבה עובדים חדשים מצטרפים בזמן קצר – היישור הוא כבר פחות אוטומטי. אם קבוצה של עובדים הגיעה עם הרגל שנוגד את התרבות – גדלים הסיכויים שהם יצליחו לערער את העיקרון התרבותי.
      • עכשיו: שינוי בתרבות הוא לא בהכרח רע. ייתכן והתרבות כוללת כמה הרגלים מזיקים. למשל: ארגון שלא עבד עם בדיקות יחידה – ועובדים חדשים שמגיעים עם ״שק הרגלים״ ומשנים את התרבות – הם כנראה דבר טוב. אבל:
        • הנטייה של עובד חדש היא להיצמד ל״שק ההרגלים״ שלו כפי שהוא, ללא הבנת הצרכים הייחודים של הארגון שאליו הוא יצטרף. הסיכוי שההתנגדויות יהיו במקומות הנכונים – קטנים ככל שהארגון עובד היטב.
        • יש יתרון גדול לתרבות ארגונית משותפת/אחידה. האחידות בטכנולוגיות / שיטות הרבה פעמים עדיפה על חצי-מעבר לטכנולוגיה / שיטה טובה יותר.
  • האצת וריבוי תהליכי-שינוי
    • אנחנו יודעים שמה ש״עובד״ עבור 10 עובדים עלול כבר לא לעבוד עבור 20-30 עובדים, ואז לא להתאים כבר ל 50-60 עובדים וכן הלאה: בעקבות צמיחה מספר העובדים – יש לשנות תהליכים והרגלים.
    • כאשר הארגון גדל מהר – גם השינויים צריכים להעשות מהר יותר.
    • שינוי כולל מאמץ וסיכון, אך צמיחה-חריגה לא מספקת הנחות*: את השינויים יש לעשות, וכל טעות – תהיה כואבת ומזיקה באותה המידה לו לא הייתה צמיחה-חריגה.
    • * לעיתים ארגונים בצמיחה-חריגה מדלגים על שלבים: במקום להיערך למצב של 100 עובדים – מתכוננים כבר מיד למצב של 300 עובדים.
      • ה Tradeoff: חוסכים איטרציה של שינוי – אך מתפקדים זמן מה במודל ״גדול/כבד״ יותר מהנדרש. הרבה פעמים ה Tradeoff הזה משתלם.
    • אפשר לחשוב על צמיחה-חריגה כ״מגבר״ לשינויים ארגוניים:
      • כאשר/היכן שהתרבות הארגונית / קבלת ההחלטות שלכם היא טובה – היא תשרת אתכם היטב בצמיחה-חריגה.
      • כאשר/היכן שהתרבות הארגונית / קבלת ההחלטות שלכם לקויה – היא תזיק לכם שוב ושוב בצמיחה-חריגה.
      • יצא לי באופן אישי, לחוות כניסה לצמיחה-חריגה בארגון פיתוח אחד עם יסודות הנדסיים רעועים (אין בדיקות אוטומטיות, אין לוגים, אין תרבות של שיפור קוד תמידי) ואחד עם יסודות יציבים (בדיקות אוטומטיות הן דבר מובן מאליו, יש כלי ניטור טובים, יש תרבות של שיפור קוד) – וההבדלים בתוצאות בין שני המצבים היה דרמטי. אני מתאפק שלא לומר: ״הבדלים של שמייים וארץ״.
  • מעט סובלנות לקושי ב Scalability ארגוני
    • כאשר שוררים תנאים עסקיים (מודל עסקי/שוק/הזדמנויות) לצמחה מהירה – המשקיעים => ה Board => המנכ״ל => המנהלים הבכירים => המנהלים הזוטרים ילחצו לאפשר אותה. זו הדרך להצליח – וזה תפקידם.
    • הסובלנות לדחיית הצמיחה תהיה נמוכה, ומה שצריך לזוז בכדי לאפשר את המשך הצמיחה המהירה – יזוז:
      • מנהלים יאלצו להאציל ולפזר סמכויות – גם כאשר הקצב מהיר מדי לטעמם.
      • אם מחלקת הפיתוח מתקשה לגייס עובדים בקצב של מחלקת המכירות – היא תאלץ לגייס מהר יותר, ולעשות את הפשרות הנחוצות.
      • תהליכים ידניים – יאלצו לעבור אוטומציה, גם אם כרוכות בכך פשרות באיכות.
    • כל ״ניצחון״ (איכותי, צודק, נכון) שיגביל את הצמיחה – יצור לחץ הולך וגובר לאפשר חזרה את הצמיחה בחזרה. לא סביר שקבוצה קטנה של אנשים בארגון תחסום את הארגון מצמיחה-חריגה: הלחץ לצמיחה מהירה בסוף ינצח כל שיקול/טיעון. אם הצלחתם לעכב את הצמיחה – דעו שזה רק עניין של זמן, עד שתאלצו לסור מהדרך (לא משנה כמה הוגנת וטובה התרבות הארגונית).
    • ארגון תוכנה – הוא מורכב יותר לצמיחה מארגון מכירות (אני מאמין). מערכת תוכנה – הולכת ומסתבכת עם הזמן – ולכן צריכה יותר עבודה על כל שינוי ככל שהזמן עובר. כל זה לא משנה – כל עוד ארגון התוכנה הוא צוואר בקבוק לצמיחת החברה (וכנראה שפעמים רבות זה יהיה המצב) -יהיה עליו לצמוח. אם הגדילה לא תעשה אורגנית – היא יכולה להיעשות ברכישה של ארגון תוכנה נוסף (ולא בהכרח הכי טובה). ארגון התוכנה הוא לא זה שיעצור את הצמיחה-החריגה של החברה.

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

מקור: https://lethain.com/productivity-in-the-age-of-hypergrowth

מה הדרכים להתמודד עם צמיחה-חריגה?

טוב. אם הייתי יודע מה הדרך הטובה ביותר – כבר הייתי כנראה עובד (בביקוש ושכר מטורף) כיועץ לארגונים בצמיחה-חריגה.

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

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

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

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

רשימה לא מלאה:

מיקרו-שירותים

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

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

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

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

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

Companies

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

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

וריאציה שראיתי פעם היא Companies בעלי בסיס קוד קדמון משותף. בחברת Nice שבה עבדתי מזמן, לקחו מוצר שעליו עבדו כ 50-60 מהנדסים (מערכת להקלטה של תכנים) ופיצלו אותה ל2 חטיבות עצמאיות: הקלטת וידאו והקלטת אודיו. עשו פשוט Fork לקוד, ושכפלו את המחלה ל-2 מחלקות שעבדו על בסיס אותו קוד שהיה עד כה.

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

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

Lean Startup

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

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

שמירה על מיקוד / WIP

עוד עיקרון מדובר הוא שמירה על מיקוד-חד, והגבלת ה Work In Process (בקיצר: WIP).

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

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

טעות נפוצה, היא להתרשם ממספר האנשים (Head Count) ולהשתמש בהם להתחיל יוזמות נוספות / חדשות. תמיד יש רעיונות לכל מיני דברים ״חיוביים״.

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

התוצאה של ההתפזרות הזו היא: ״סתם״. יוזמות רבות, הגוזלות תשומת-לב מיוזמות חשובות יותר, מייצרות תחושה משמחת של ״עשייה״ אך ללא משמעות אמיתית, ללא Impact.

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

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

עדיף להציב עובדים חדשים ביוזמות חשובות, גם כאשר אינם יעילים – מאשר לשלוח אותם לנסות יוזמות שוליות / יוזמות חשובית שהסיכוי שלהם לעשות Impact אמיתי הוא שולי.

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

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

וריאציה נוספת: ״The key to scaling – is to say no״.

ערכים ומדיניות

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

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

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

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

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

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

  • Dare to Simplify (ערך של Next-Insurance) – הוא ערך שאני מאוד אוהב. המילה החזקה היא ״Dare״: ״קח סיכון על מנת לפשט, זה מספיק חשוב!״. עצם הצבת הערך הזה ברמת החברה – עזר למקד דיונים ולשכנע את המשתתפים לחתור לפשוטת, גם כאשר זה לא היה קל.
  • Don’t just identify a problem – fix it (מתוך מאמר על AirBnb) – במיוחד בארגון בצמיחה-חריגה – דברים יתקלקלו כל הזמן. חשוב לנצל את מאגר הכוחות/מוחות/תשומת-הלב כדי לשפר ולתקן כל הזמן תקלות. לתקן בעיות שלא אני גרמתי (כמובן) ולתקן בעיות שמפריעות לאחרים יותר מאשר לי (גם זה).
  • Everything changes all the time. Get over it – זו יותר מדיניות מאשר ערך. אם לאנשים משתבשות שוב ושוב תוכניות, והם מתרכזים בדיוק על ״אסור להזיז לנו דברים – זה הורס את התוכניות״, התמודדות נגד היא להגדיר את המדיניות הזו. לחדד לאנשים שיהיה עליהם להמשיך ולהתמודד עם שינוי מהיר-תמידי. זה מה שמצופה מהעובדים, למרות שזה לא קל.
    • הערה אישית: אני מקווה שזה בא עם הכרה כנה בקשיים. מנהלת HR שמצהירה ״אלו כאבי גדילה – זה טבעי״, מניסיוני, לא מספיק עזר. אני רוצה להאמין שמסר כמו – ״שמע, זה מזופת. זה יכול פעמים לשגע אותך – אבל זו המציאות שלנו. נסה לקחת את זה כאתגר – ולא להתייאש, כולנו עוברים את זה״ – היה עובד טוב יותר.
On-Boarding and Education
בחברת Gett (לשעבר GetTaxi) חוויתי לראשונה צמיחה-חריגה אמיתית.
בסאפ פעם הוספו לנו לפרויקט מהיום-למחר כמה עשרות עובדים, אבל הכרנו חלק מהם, והם הכירו היטב את הארגון. היו לנו כבר הרגלים משותפים. זה, יחסית, היה ״בקטנה״.
קליטה לארגון ב Gett היה תהליך קשה:
עובדים חדשים היו צריכים להכיר ביזנס חדש (מוניות, On-Demand Transportation), טכנולוגיה חדש (רובי, Go), שוק חדש (Consumer), רבים היו חדשים ל SaaS, טיפול בפרוקדשיין ו AWS ואפילו רבים היו חדשים למק. כל זה עוד לפני שהגענו למערכת חדשה ומורכבת, שעברה הרבה שינויים מהירים וגם היה בה הרבה Legacy להיזהר ממנו, ארגון שפועל ב – 4 מדינות, כל אחת עם כללים וצרכים משלה. ארגון וצוותים, בעלי תפקידים שונים ומשונים.
פלא שזו לא הסתגלות קלה?
מה עשינו לעזור לעובדים?
בהתחלה – את הדברים הרגילים: הצמדנו לכל עובד חדש Buddy (עובד אחר) שילווה אותו בכמה שבועות הראשונים (freestyle), ועשינו כמה סשנים להכרת המערכת.
הייתה תקופה שהזמנו קורס חיצוני של שבוע לשפת רובי, שלמרות ניסיונות שיפור, לא השיג שביעות רצון גבוהה – ולא הרגשנו שלאחריו אנשים יודעים ממש את השפה.
זה לא היה מספיק טוב. ההרגשה הכללית הייתה שעובדים שנמצאים כמה חודשים בחברה עדיין חסרים המון – ואינם עצמאים כמעט בשום משימה משמעותית. הם הרבו לתקן באגים קטנים או לכתוב שירותים צדדים – שלא נוגעים בליבת המערכת.
בהמשך לקחנו את היוזמה, והשקענו פנימית בהכנת בתכנים ממוקדים יותר לגבי רובי, ו Go אך גם AWS ו SQL. יותר מזה – סשנים יותר מבוקרים ומוקפדים על הכרת המערכת.
זה היה תהליך: בהתחלה זה צלע – אך אם הזמן היה יותר ויותר טוב.
עצם היותו תהליך פנימי – יכולנו להתאים תכנים בדיוק לארגון. למשל: לדבר על הספריות המשותפות הפנימיות של הקוד. על הבעיות הנפוצות שצצו אצלנו.
בסופו של דבר, הצלחנו לעשות את המעבר, ולחבר עובדים חדשים לטכנולוגיה והסביבה שלנו בצורה יעילה – כך שלאחר כמה חודשים, גם העובדים החדשים, וגם המנהלים בארגון – הרגישו הרבה יותר טוב לגבי היכולת של עובדים חדשים להתמצא במערכת. תהליך ה On-Boarding היה אחד הצעדים היותר פוריים שעשינו להשתלט על הבלאגן בקליטת כמות משמעותית של עובדים.
היום ב Next-Insurance יש לנו תהליך On-Boarding של הימים הראשונים, של השבועות הראשונים, ושל החודשים הראשונים. משם והלאה יש מבחר של סשנים (מוקלטים) במגוון נושאים רלוונטים – זמינים לרגע שבו העובד יזדקק להם. יש גם StackOverflow פנימי ווויקי – מהם אפשר להמשיך ללמוד.
תהליך ה On-Boarding מתחבר באופן טבעי לתיעוד וחומר לימודי להמשך תקופת העבודה. לפעמים עובד לא נתקל בנושא במערכת גם במשך שנתיים-שלוש. טוב שכאשר הוא נתקל בנושא – יש לו מקור יעיל להשלים לגביו ידע.
עוד גישה שיש לגבי קליטת עובדים במצב של צמיחה-חריגה היא לעשות ״תורנות״ בין הצוותים בגיוס העובדים. במקום לגייס לכל הצוותים כל הזמן, יש כל פרק זמן (נניח: רבעון) צוותים שמגייסים – וצוותים ש״מתאוששים״ מגיוס.
ההנחה היא שבניגוד למרתון (או התמודדות שוודית עם קורונה) בו שומרים על קצב קבוע כל הזמן, בקליטת עובדים יש הרבה הפרעה לצוות בביצוע ראיונות וקליטת עובדים חדשים.
לכן עדיף שתקופה הצוות יעסוק בגיוס, ותקופה הצוות יעסוק בקליטה ו״גידול״ העובדים החדשים – ולא לנסות למקד צוות בשני המאמצים בו-זמנית.
צמיחה-חריגה, בה רוב העובדים הם עובדים חדשים.

גיוס רק אנשים מצוינים

אחת הגישות שהתנסתי בהן היא התמודדות עם צמיחה-חריגה ע״י גיוס של אנשים מצוינים בלבד (על בסיס הספר Scaling Up).
המחשבה הייתה שעובדים ״סבירים״ – רק יעכבו אותנו, וידרשו המון תשומת לב. זו בעיה קשה, כאשר צומחים מאוד מהר (להזכיר: +100% בשנה) ורוב העובדים הם חדשים. במקום זאת, ניסינו להתמקד רק בעובדים ״מעולים״ שהם אלו שיהיו עצמאים הרבה יותר, ידרשו פחות תמיכה, וישפרו כל הזמן תהליכים – במקום רק לצרוך אותם (או להתלונן שהם חסרים).
לצורך העניין נעזרנו בחברת ייעוץ מלונדון (שהתבססה על הספר Who. חלק מאיתנו גם טסו לשם להדרכה) – ולקחנו את העניין בסופר-רצינות. מהמנכ״ל – עד אחרון המראיינים.
ההחלטה הייתה לגייס פחות, לשלם יותר – אבל להביא רק אנשים מצוינים ״A players״. היו חודשים רבים שהקדשנו לנושא הגיוס יותר זמן מכל נושא אחר.
איך זיהינו אנשים מצוינים? אנשים שיצאנו מהראיון איתם ללא ספקות. שהרשימו את כל המראיינים מאוד. לא חששנו לפסול אנשים שיש לגביהם ספקות, והרבה כאלה.
זוכרים את העיקרון של אי-עצירת הצמיחה? היוזמה לגיוס אנשים מצוינים בלבד הגיעה מהמנכ״ל – וכדי לעמוד ביעדי הגיוס היינו צריכים לראיין בלי סוף. 3-5 ראיונות בשבוע היה קצב שגרתי למראיין, ואני זוכר מקרה של מנהל הפיתוח שסיפר שקיים 15 ראיונות בשבוע בודד.
את התוצאה ראינו רק לאחר חודשים – היא לא הייתה טובה. למרות מאמץ אדיר, פשוט אדיר – זה לא עבד כפי שציפינו.
בהבנה לאחור, הייתה תפיסה בארגון (שקדמה לכל התהליך) שחשוב לנו מאוד לגייס אנשים עם ״אש בעיניים״ עם מוטיבציית-שיא. בכדי להשיג מוטיבציית שיא גייסנו אנשים שהתפקיד שהוצע להם – היה עבורם קפיצת מדרגה משמעותית (כלל האצבע היה: ״30% יותר ממה שעשו בתפקיד הקודם״). למשל: מנהל בחברת פרויקטים, שבא לנהל קבוצת פיתוח Consumer/SasS בחברת סאטראט-אפ מבוקשת. בחור מאוד מוכשר – עם טונה של מוטיבציה להצליח. החיסרון שהבנו בדיעבד: לרבים מאלו שגייסנו לא היה ניסיון קודם במה שהם עומדים להתמודד איתו. הם עברו טבילת-אש ראשונה אצלנו, בתנאים לא אופטימליים, בלשון המעטה.
בסיבוב השני (לאחר חודשים), התמקדנו באנשים עם ניסיון ברור במה שהם עומדים לעשות. אנשים שכבר עשו את זה, ועשו את זה טוב. למשל: מפתחים – העדפנו שכבר עבדו בסביבת SaaS ופרודקשיין. ה״אש בעיניים״ כבר הייתה פחות שכיחה.
לאחר חודשים הבנו את התוצאות – והן היו טובות יותר, אבל לא עמדו בציפייה. יחסית למאמץ האדיר שהשקענו – עדיין קיבלנו עובדים שלרבים מהם לקח זמן להסתגל – והם היו זקוקים לכמות נכבדת של תמיכה לאורך זמן.
תאוריה (מרשימה), וניסיון – לחוד. זה הניסיון שלי.
הייתי ממליץ להתמקד באנשים שכבר התמודדו עם סוג האתגרים שעומדים בפניהם, ואולי קצת הלאה – ונמנע מלנסות ו״להצמיח אנשים מוכשרים ומלאי מוטיבציה״ לתפקיד. עדיין – הגיוס נראה לי כשלב הכרחי, אך לא מספיק על מנת להתמודד עם צמיחה-חריגה.

Guidelines and Standardization

הנה משהו מפחיד. רואים את המילים הללו למעלה? אלו מילים של Enterprise, של Coroporate.

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

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

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

אני רוצה להמליץ בחום על כמה עקרונות בניסוח Guidelines שכאלו, בכדי לא לקחת מה “Corporate״ גם את הצדדים השליליים שלו:

  • נסו לקצר כמה שיותר. אם יש ספק – קצרו. מקסימום השלימו אח״כ.
  • נסו להצמיח את ה Guidelines מתוך השטח, בסיוע המפתחים הותיקים, הותיקים למחצה, וגם הצעירים – שמעוניינים בזה. התהליך נועד לתעד את הקיים והמוצלח, אבל גם אפשר לשפר אותו ״על הדרך״.
  • אמצו גישה של ״Fail Open״: במקרים בהם לא ברור מה Guidelines כיצד יש לפעול, אפשרו חופש פעולה. אם המקרה חוזר על עצמו – תקננו את זה. אל תעכבו אף אחד כי ״זה לא מכוסה ע״י ה Guideline״.
את הגישה הזו התחלנו לאחרונה ב Next-Insurance. סה״כ אנשים תומכים בכיוון, ומספר עובדים חדשים הצהירו שזה מה שהם היו מצפים לו. אני מניח שעוד כחצי שנה – אוכל לתת הערכה יותר משמעותית על הגישה הזו, ספציפית, בהתמודדות עם צמיחה-חריגה.

סיכום

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

אלו פרקטיקות ותהליכים המגמה הזו תפתח?

האם ימשיכו לצמוך בקצבים יותר ויותר מהירים?

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

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

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

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

הפעם אני רוצה לדבר קצת על תיאוריה ניהולית, וספציפית על מתן משוב (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) נשמעים נבונים ועניינים. רק ניסיון והזמן – יוכלו לומר עד כמה הם טובים. מה מהם יש לשכוח – ומה יש להמשיך ולפתח.
האם אני אנסה לאמץ את הרעיונות הללו – כן.
האם אני שלם שהגישה הזו לא יכולה להוביל לטיפוח בינוניות? – לא לגמרי. מלווה אותי עדיין מידה מסוימת של חשש.
אתם יותר ממוזמנים להגיב ולשתף מניסיונכם בנושא.
שיהיה בהצלחה!
——-
[א] ציון ״מחקרים״ הוא גם סוג של באזז. מחקרים יש לכל הכיוונים, בעיקר במדעי ההתנהגות. רק ריבוי מחקרים המחזקים זה את זה – הוא מקור מספיק משמעותי להסתמך עליו. המאמר לא ציין את המחקרים – מה שמשאיר את האמירות כהצהרה כללית בלבד / כלי לשכנוע הקורא.

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

תזכורת להשתמש ב 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 על מנת לכתוב קוד פשוט יותר, ואינטואטיבי יותר.
שיהיה בהצלחה.