כיצד לצמצם פוליטיקה ארגונית? (מבלי לעבוד לבד)

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

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

האם ניתן להימנע מפוליטיקה ארגונית?

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

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

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

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

כיצד לתמרץ פוליטיקה ארגונית

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

אין משמרות

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

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

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

הנזק מהחלטה נקודתית ותמימה לכאורה – היה עמוק ומתמשך.

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

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

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

The Chosen

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

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

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

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

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

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

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

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

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

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

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

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

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

לקדם את טוראי ראיין

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

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

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

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

נשמע win-win, לא?

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

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

דוגמאות קצרות אחרות ששווה להזכיר:

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

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

ואם רוצים בכל זאת, דווקא – לצמצם את הפוליטיקה?

שורשי צמיחת הפוליטיקה בארגון, אם כן, הם ב:

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

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

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

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

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

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

Self < Team < Organization

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

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

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

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

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

סיכום

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

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

כמו בסיפור של עוץ לי גוץ לי – החוב סופו להיפרע.  [1]

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

—-

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

נושאים מתקדמים ב MySQL: חלק ב' – Generated columns ו json_each

פוסטים בסדרה:
"תסביר לי" – גרסת ה SQL
לקחת את הביצועים ברצינות, בעזרת MySQL Performance Schema
נושאים מתקדמים ב MySQL: חלק א' – עבודה עם JSON
נושאים מתקדמים ב MySQL: חלק ב' – json_each  ו Generated Columns

בפוסט הקודם דיברנו על שימוש ב json column ב MySQL.

אחת המגבלות הגדולות של שדות json הם מהירות החיפוש בהם:

  • אם השדות שמורים כ json – יש לקרוא את ה json כולו מהדיסק לזיכרון – על מנת לשלוף ערך בודד.
  • אם השדות שמורים כ text column – אזי יש עוד עבודת CPU של פענוח מבנה ה json – זמן לא זניח ב jsons גדולים. להזכיר: בעמודה מטיפוס json הם שמורים כ key-value עם גישה מהירה יותר לפי מפתח.
הפתרון האפליקטיבי המתבקש שבו מפתחים שונים נוקטים הוא לאחסן "עותק" של מספר מצומצם של שדות עליהם יש חיפוש – ב columns מקבילים לזה של ה json. ההשפעה על הביצועים – תהיה לרוב דרמטית.

הנה סכמה כזו לדוגמה:

[ Id (guid/auto-inc), json_data (json), field_x (varchar(100)), field_y (int) ]

את השדות x ו y – נרצה לרוב להחזיק גם בתוך ה josn וגם בצד לצורך גישה מהירה / שימוש באינדקסים.
למה שכפול נתונים?
אם נאחסן אותם רק מחוץ ל json – העבודה עם אובייקט ה json תהיה מסורבלת יותר.
לפעמים השדה שאנו מוציאים הוא גם ערך וגם מיקום באובייקט – למשל: המחיר של ההזמנה המאוחרת ביותר (כאשר יש לנו מערך של גרסאות של הזמנות).

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

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

ALTER TABLE policies
ADD COLUMN state VARCHAR(30) GENERATED ALWAYS
AS (json_unquote(json_extract(`json_data`,'$.address.state'))) STORED
;

אני מוסיף שערכו יהיה הביטוי (expression) שבסוגריים לאחר המילה השמורה AS.

  • חשוב לי להשתמש ב json_unquote על מנת שהעמודה לא תכיל מירכאות – וכך אוכל לבצע חיפוש יעיל מול האינדקס.
  • הביטוי GENERATED ALWAYS הוא רשות – ועוזר להבליט את העובדה שמדובר ב generated column – עבור קוראים עתידיים.

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


WHERE my_state = json_unquote(state)

לא טוב!

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

WHERE json_quote(my_state) = state
אבל הכי טוב זה להכין את האינדקס מראש בצורה הכי "טבעית" לשאילתה שאפשר – וכך לחסוך טעויות מרגיזות.

בגדול יש שני סוגים של generated columns:

  • Virtual – המחושב בזמן הגישה לרשומה.
    • בסיס הנתונים ישמור את הביטוי החישובי (expression) כ metadata על הסכמה, ובכל גישה לרשומה / הפעלת trigger – יתבצע החישוב מחדש. קונספט דומה מאוד ל "calculated field" במערכות BI.
    • אנו חוסכים מקום בדיסק – אבל מכבידים על ה CPU בכל גישה.
    • זהו ערך ברירת המחדל – אם לא ציינתם כלום.
  • Stored – הערכת הביטוי תבוצע בזמן יצירה / עדכון של הרשומה, וישמר לדיסק כמו עמודות אחרות.
    • יש מחיר בנפח אכסון, אך לרוב – הרבה פחות עבודת CPU.
    • זו הגישה הטבעית בעבודה עם json.

לצורך העניין generated column יכול לשמש לצרכים נוספים מלבד json.

למשל:

CREATE TABLE periods
id VARCHAR(32),
start_date_millis INT, # WARN: https://en.wikipedia.org/wiki/Year_2038_problem 
end_date_millis INT,   # WARN: https://en.wikipedia.org/wiki/Year_2038_problem 
start_date_sec AS (state_date_millis * 1000) VIRTUAL
;

יש כמה מגבלות על שימוש ב generated columns שכדאי להכיר. בביטוי של עמודה מחוללת לא ניתן להשתמש ב:

  • פונקציות לא דטרמיניסטיות – כאלו שיציגו ערכים שונים אם הופעלו פעם שניה. למשל: ()now או ()current_user.
  • sub-queries
  • Parameters / Variables או User Defined Functions.
  • עמודת AUTO_GENERATED או תכונת AUTO_INCREMENT.
  • שדה generated יכול להיות מבוסס רק על שדות generated המופיעים לפניו.
  • לא ניתן להשתמש על ה stored generated column באילוצים של FK מסוגי ON_UPDATE / ON_DELETE

עוד פרט מעניין: ניתן להשתמש באינדקס (משני) גם על virtual generated column מעל innoDB. הוא יהיה מסוג BTree בלבד (כלומר: לא FULLTEXT או GIS).

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

קצת יותר על השימוש בפונקציות ה JSON של MySQL

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

רקע: אני רוצה לבצע מיגרציה לשם של אלמנט בתוך מבנה json שאנו עושים בו שימוש. שם האלמנט היום הוא breakdown אבל השם לא כ"כ נכון – ואני רוצה לשנות אותו ל amounts. הנה דוגמה פשוטה למבנה ה json הקיים לפני השינוי:

[{"policyId":"policy_id","lob":"GL","breakdown":{"PREMIUM":{"amount":423.17}}}]

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

[{"policyId":"policy_id","lob":"GL","amounts":{"PREMIUM":{"amount":423.17}}}]
איך לעזאזל ניגשים למיגרציה "עמוקה" בתוך שדה json? האם זה חייב להיות פרויקט מורכב?
ברור שלא.
אז הנה אני אעשה את השינוי בכמה שלבים פשוטים:
ראשית, אני רוצה ליצור שדות כפולים: גם breakdown וגם amounts – כי באופן טבעי בזמן deployment ירוצו 2 גרסאות של הקוד (גרסה חדשה שמחפשת אחר amounts וגרסה ישנה שמחפשת אחר breakdown). אני צריך להתכונן לכפילות הזו.
אני דואג לכך שבזמן ה deploy (כמה דקות) – לא יווצרו רשומות חדשות (במקרים אחרים ניתן למצוא אותן בעזרת זמן יצירה, ולתקן ידנית אח״כ).
בניית שאילתה של SQL היא עניין של ניסוי וטעיה, והדבר הזה נכון גם בעבודה עם  json.

אני מתחיל בשאילתה פשוטה של SELECT על מנת לראות אם קלעתי נכון ב query.
בחרתי לי רשומה שהמפתח שלה הוא '009277a371b8c3def40996a754085030' על מנת לבצע את הניסויים ב scale קטן.

SELECT Json_insert(financial_attribution, '$[0].foo', 2)
FROM   `payments`
WHERE  id = '009277a371b8c3def40996a754085030';
במבט ראשון זה קצת מבלבל שאני משתמש ב ()JSON_INSERT בפקודת SELECT.
מה קורה כאן?
אני שולף שדה json בשם `financial_attribution` ואז מבצע עליו מניפולציה בזיכרון. המניפולציה שבחרתי היא הכנסה של ערך. מפתח מוזר בשם foo עם ערך של 2. רק לצורך הבדיקה.
הנה התוצאה:
[{"foo": 2, "lob": "GL", "policyId": "policy_id", "breakdown": {"PREMIUM": {"amount": 423.17}}}]
השדה נוסף בהצלחה (לי לקח ניסיון או שניים עד שזה עבד) – אך שום מידע לא השתנה בבסיס הנתונים.
עכשיו ננסה משהו יותר אמיתי:
SELECT Json_insert(financial_attribution, '$[0].amounts',                    financial_attribution -> '$[0].breakdown')
FROM   `payments`
WHERE  id = '009277a371b8c3def40996a754085030';
לקחתי מתוך ה json את אובייקט ה breakdown – והכנסתי אותו בחזרה כ amounts:
[{"lob": "GL", "amounts": {"PREMIUM": {"amount": 423.17}}, "policyId": "policy_id", "breakdown": {"PREMIUM": {"amount": 423.17}}}]
אחרי שאני רואה שזה מצליח אני יכול להסיר את תנאי ה where ולראות את התוצאה על מגוון ערכים. מוודא שהכל תקין.
אנסה בצד דוגמה שגם שאילתת ה update תקינה:
UPDATE `payments`
SET    `financial_attribution` = Json_insert(`financial_attribution`, '$[0].amounts',
financial_attribution -> '$[0].breakdown')
;
ואז הוסיף אותה ל db migrations של השינוי.
אחרי שכל המיגרציה הסתיימה (בהצלחה), אני יכול למחוק את אובייקט ה breakdown מתוך ה json בעזרת פקודת  ()JSON_REMOVE. 
אפשרות אחרת היא פשוט להשאיר את הנתונים העודפים – אם הם לא מפריעים לנו.

עוד דרך מהירה (ולעתים יותר יעילה) לבצע תיקונים ב jsons היא בעזרת ()REPLACE פשוט על טקסט – אבל חשוב מאוד להיזהר מהחלפות לא-צפויות.

השלמות ליכולות ה json של MySQL 5.7

אם אתם זוכרים את הפוסט הקודם – הבטחתי לכם workarounds למחסור של MySQL 5.7 ב-2 פונקציות שימושיות בעבודה עם json.

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

קריאת הערך האחרון במערך שבתוך json

אני רוצה לקבל את השדה האחרון במערך שבתוך json:

SELECT JSON_EXTRACT(`from`,CONCAT("$[",JSON_LENGTH(`from`)-1,"]")) FROM `table`;

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

{ from: ["a","b","c"], "to": [ "d", "e" ] }

התוצאה תהיה ״c״.

הנה דוגמה ב DB Fiddle שאפשר קצת ״לשחק״ איתה:

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

גרסה מאולתרת ל json_each – טיפול בכל איבר במערך שבתוך json

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

הנה דוגמה לשאילתה כזו:

select  n,
JSON_EXTRACT(`data`, concat('$.items[', n – 1, '].price')) as price
from `my_table`
join numbers on (n <= JSON_LENGTH(`data`->'$.items') and n > 0)
;

כאשר התוצאה נראית כך:

n הוא מספר האיבר ברשימה (אינדקס על בסיס 1), ו price הוא… המחיר.

והנתונים נראים כך:

עשינו join עם טבלה של מספרים (0-255 לרוב מספיקה) ואז, עבור כל מספר באורך המערך של ה items – ביצענו פעולת שליפה מתוך ה json על המקום הזה, בהתבסס על ״תרגיל״ ה CONCAT שהשתמשנו בו קודם לכן.

הכי-אלגנטי-בעולם? – לא.
עובד ושימושי – כן!

הנה אתם יכולים לשחק ב fiddle שיצרתי לקוד הזה: https://www.db-fiddle.com/f/dmA8af4CHJ3xkx4fzV99Zw/0

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

CREATE OR REPLACE VIEW generator_16
AS SELECT 0 n UNION ALL SELECT 1  UNION ALL SELECT 2  UNION ALL
SELECT 3   UNION ALL SELECT 4  UNION ALL SELECT 5  UNION ALL
SELECT 6   UNION ALL SELECT 7  UNION ALL SELECT 8  UNION ALL
SELECT 9   UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL
SELECT 12  UNION ALL SELECT 13 UNION ALL SELECT 14 UNION ALL
SELECT 15
;
CREATE OR REPLACE VIEW numbers
AS SELECT ( hi.n * 16 + lo.n ) AS n
FROM generator_16 lo, generator_16 hi
;

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

אפשר למצוא את Fiddle ממקוד של ה generator על מנת ״לשחק״ איתו: https://www.db-fiddle.com/f/jCRetSiTaKqz5SUiQQG8Py/0

סיכום

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

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

נושאים מתקדמים ב MySQL: חלק א' – עבודה עם JSON

פוסטים בסדרה:
"תסביר לי" – גרסת ה SQL
לקחת את הביצועים ברצינות, בעזרת MySQL Performance Schema
נושאים מתקדמים ב MySQL: חלק א' – עבודה עם JSON
נושאים מתקדמים ב MySQL: חלק ב' – json_each  ו Generated Columns

MySQL הוא בסיס-נתונים פשוט.

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

גרסה 8 שיצאה לא מכבר הייתה עשויה להיקרא גרסה 5.8 – היא הוסיפה כמות נאה של תוספות, אבל בוודאי לא מהפיכה. (במיוחד לאחר שכמה שינויים זכו ל down-port לגרסה 5.7). לא ניתן להשוות אותה לחידושים של גרסה 5.

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

מקור: DB-engines.com

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

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

  • "בסיסי-נתונים רלציונים הם העבר"
  • "ל PostgresSQL יש יותר שיטות לבצע join – אז הביצועים שלו טובים יותר"
  • "בכנס חשוב-כלשהו היו 3 הרצאות על PostgreSQL ורק אחת על MySQL"
  • "ל MySQL אין רפליקציה טובה (כמו ל Mongo, לכאורה)". "הוא לא בנוי ל Scale".
  • "ל Postgres יש פי 3 יכולות מאשר ל MySQL".
אלו דוגמאות לטיעונים לא לא עקרוניים. יש הרבה רצון לחדש ולעבוד עם "בסיס נתונים חדש יותר" – אבל גם המוכר והלא buzzy יכול להיות מוצלח מאוד.
נוכחתי לאורך הקריירה בכמה יוזמות אימוץ של "בסיס נתונים מתקדם יותר" – שנגמרו במפח-נפש.
שלא תבינו לא נכון: PostgreSQL ו MongoDB (ועוד אחרים) הם Databases מרשימים וטובים – אבל גם להם יש חסרונות, ואם אתם עושים מעבר – חשוב מאוד שתהינה לכן סיבות עמוקות ומבוססות. חבל להשקיע חודשים במעבר ואז לגלות שחיסרון חדש מעיב על כל המאמץ שהושקע. מעבר של בסיס נתונים במערכת "חיה" הוא שינוי לא-קל. הכלל הזה נכון גם לגבי מעבר ל MySQL – כמובן.
דיאגרמה (לא בהכרח מאלה) של Databases בתחום הרלציוני. מקור: 451 Research.

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

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

    • עבודה עם JSON וה Document Store.
    • Generated columns
    • פיצוי על יכולות חסרות ב MySQL כמו json_each או fist_value/last_value – איך אפשר להסתדר בלעדיהם.
    • מנועי Storage וההבדלים ביניהם: InnoDB ל MyISAM, וכו' (לא חדש בכלל – אך ידע חסר, ממה שנתקלתי).
    • סטטיסטיקות של אינדקסים וטבלאות – ואיך זה משפיע עלינו (גם לא חדש).
    • Full Text indexes
  • Partitioning
  • Large Hadron Migrator- https://github.com/soundcloud/lhm, ביצוע migrations גדולים ללא downtime.
כל הנושאים הנ"ל הם נושאים שלי יצא באופן אישי, או לאנשים מסביבי להשתמש בהם. הם נושאים ישימים ופרקטיים – עד כמה שאני יכול לומר.

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

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

JSON וה MySql Document Store

לפני כעשור, עולם ה Databases התחלק ל-2 קבוצות דומיננטיות של שימוש עיקרי:

  • בסיסי-נתונים רלציוניים
  • בסיסי-נתונים מבוססי-מסמכים (Document-Based)
* נכון, יש גם K/V DB שנמצאים בשימוש נרחב, וגם columnar, wide-column, וגם graph ו time series – אך עדיין בסיסי נתונים רלציוניים ו document-based אחראים למגוון הגדול יותר של הנתונים והשימושים.
ההרכב הנפוץ הוא שארגון מחזיק את רוב האובייקטים בבסיס נתונים רלציוני / מסמכים, והיכן שצריך scale גבוה יותר – פונה לפתרונות יותר ממוקדים לצורך הספציפי.

בסיסי הנתונים מבוססי המסמכים (כמו CouchDb, MongoDB) הציגו חזון מסעיר וחדשני, יחסית לבסיסי-הנתונים הרלציוניים – והיה נדמה שהם עומדים לכבוש את עולם בסיסי-הנתונים בסערה. הנה פוסט עתיק שלי על MongoDB (שלום, מונגו!)
המהפכה הזו לא קרתה כפי שחזו – אך היא בהחלט השפיעה על עולם בסיס הנתונים.
אנשי תוכנה רבים, החלו ליישם עקרונות של בסיסי-נתונים מבוססי-מסמכים על בסיסי-נתונים רלציוניים (הנה פוסט ישן נוסף, המתאר כיצד עושים זאת: עשה זאת בעצמך: NoSQL).
בסיסי הנתונים הרלציוניים, החלו לספק גם יכולות של ניהול מסמכים (או JSON snippets, לפחות. ה"מסמכים" הכי שימושיים), והיום יש יכולות Document כאלו ואחרות ברוב בסיסי-הנתונים הרלציוניים המוכרים. השילוב הזה – מאוד מוצלח, לטעמי.
מאז MySQL גרסה 5.7.12 (אמצע 2016, בעזרת plugin) יש ל MySQL ממשק עבודה שדומה מאוד לעבודה מול בסיס-נתונים מבוסס מסמכים, מה שנקרא The MySQL Document Store:
  • "מסמכים" (כלומר: JSON), מאוחסנים ב Collections.
    • מאחורי הקלעים, לאכסון collection של מסמכים, נוצרות טבלאות בנות שתי-עמודות id_ ו doc (כמו שהיינו עושים פעם, בעצמנו…)
  • בעזרת API (או ה shell החדש, mysqlsh) ניתן לגשת ל"מסמכים" ב API המוכר מבסיסי-נתונים מבוססי-מסמכים. למשל:
    • ("db.product.find('_id = "iPhone XI
    • (…)db.createCollection
    • (…)add(…), sort(…), modify, וכו'
  • את המסמכים ניתן לאנקס
    • מאחורי הקלעים MySQL יוצר generated columns – נושא שארצה לכסות בהרחבה.
  • ל API יש clients זמינים ל JavaScript ול Python – אם כי כמה פעולות, תחזוקה וטיפול בעיקר, עדיין יש לעשות ב SQL.
אף פעם לא "נפלתי" מהממשק של ה Documents Stores ולכן מעולם משך אותי לנסות ולהשתמש ב MySQL Document Store.
אני אישית מעדיף בהרבה לעבוד בסגנון מעורב (רלציוני-Document).

הייתי שמח מאוד להיות מסוגל לעשות מניפולציות על json ב js או פייטון המקונן בתוך שאילתת SQL – אך לצערי לא נראה שהשוק הולך לשם…
עדכון: תודה לנדב נווה שעדכון אותי שכן יש plugin ל User Defined Functions ב js עבור MySQL. מעניין!

עדיין, לא נראה שה plugin הזה נתמך ע"י AWS RDS. חבל…

JSON ב MySQL דרך SQL

column מטיפוס JSON הוסף ב MySQL גרסה 5.7.8 (אוג' 2015), אם כי ניתן להשתמש ביכולות ה JSON שנוספו לבסיס הנתונים גם על גבי עמודות מסוג text, varchar, BLOB וכו'. עמודות טקסטואליות.

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

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

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

  • יש ב MySQL תחביר המאפשר לאמוד אם שדה x בתוך אובייקט o שבתוך ה JSON כחלק מפקודת WHERE.
    כמו שנראה בהמשך, כשמבנה ה json הוא מורכב יותר – זה הולך והופך להיות קשה יותר.
  • ביצועים: כאשר אנו רוצים להשוות שדה אחד מתוך אובייקט עם 50 שדות – עלינו לטעון לזיכרון את כל 50 השדות בכל פעם, שזה הרבה I/O מיותר (מדד חשוב מאוד בביצועים של בסיסי-נתונים).
    הגישה המקובלת להתמודד עם בעיית הביצועים היא להוציא לעמודות מקבילות לעמודת ה JSON "שכפול" של שדות אותן נרצה לתשאל בצורה תדירה (ולכן גם לאנדקס).
    בהמשך נראה כיצד MySQL יכול לסייע להפוך לעשות את התהליך הזה לפשוט יותר בעזרת Generated Columns.
טיפוס ה json ב MySQL שונה מ text בשתי תכונות עיקריות:

  1. בהכנסת ערך לעמודה מסוג json – בסיס הנתונים יוודא את תקינות ה format של ה json.
  2. בעמודה מסוג json ולא text – בסיס הנתונים ידחוס את ה json לפורמט בינארי דחוס יותר, בו המפתחות ממוינים (בדומה לפורמט bson שנעשה בו שימוש ב MongoDB).

json תקין הוא כמובן אובייקט ({}), מערך ([]), מחרוזת (""), או null.

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

טיפוס ה json של mySQL הוא optimized לקריאות, כך שאם אנחנו הולכים לכתוב יותר (למשל: audit) – יכול להיות שיהיה עדיף, מבחינת ביצועים, להשתמש בעמודה מסוג text.

הפקודה הבסיסית בעבודה עם json ב MySQL היא JSON_EXTRACT:

SELECT c, JSON_EXTRACT(c, "$.id"), g
FROM some_table
WHERE JSON_EXTRACT(c, "$.id") > 1
ORDER BY JSON_EXTRACT(c, "$.name");
++++| c | c>"$.id"| g |++++| {"id": "3", "name": "Barney"} |"3"| 3 || {"id": "4", "name": "Betty"} |"4"| 4 || {"id": "2", "name": "Wilma"} |"2"| 2 |++++

יש גם תחביר מקוצר:

SELECT c, c->>'$.id', g
FROM some_table
WHERE c->"$.id" > 1
ORDER BY c->'$.name';
++++| c | c>"$.id"| g |++++| {"id": "3", "name": "Barney"} | 3 | 3 || {"id": "4", "name": "Betty"} | 4 | 4 || {"id": "2", "name": "Wilma"} | 2 | 2 |++++

כאשר <<- הוא תחליף ל  ((JSON_UNQUOTE( JSON_EXTRACT(column, path. הפונקציה JSON_UNQUOTE מסירה את ה quotes – אם קיימים.

ניתן להשתמש בביטויים מורכבים יותר כמו 'column->'$[2].person.pets[1].name
  • את כל הביטוי יש לעטוף במירכאות בודדות או כפולות – כי זו מחרוזת ב SQL.
  • יש לציין את ה $ – המתאר את ה root של ה json (לפי תקן ה json path – ה $ נקרא "context").
  • כאשר יש שמות של keys המשתמשים בסימנים מסוימים – יש לעטוף אותם ב quotes, למשל:
    'column->'$[2].person."my-pets"[1].name
  • ניתן להשתמש ב * בכמה מצבים:
    • [*]$ – יחזיר את כל האיברים במערך (או null אם הפעלתם על אובייקט או מחרוזת)
    • price.*.$ יחזיר מערך של כל שדות ה price בכל האובייקטים שבתוך העמודה.
    • price.**.$ יחזיר מערך של כל שדות ה price בכל האובייקטים, או תתי-האובייקטים, שבתוך העמודה.
  • יש פונקציות כגון ()JSON_KEYS ו ()JSON_SEARCH – שיחזירו בהתאמה את רשימת ה keys באובייקט, או רשימת האובייקטים המכילים ערכים מסוימים.
יש פעולות שלא ניתן להשיג בעזרת ה path כפי שמתאפשר היום ב MySQL 5.7.x. דוגמה נפוצה בשימוש: בחירת האיבר האחרון מתוך רשימה, או פעולות מיון / סינון על מפתחות מסוימים.
תמיד ניתן לעשות את הניתוח ברמה האפליקטיבית, שם ה json הוא "כחומר ביד היוצר" אם כי עבור שאילתות ניתוח /ואו כלי BI – עדיין יהיה שימושי מאוד להיות מסוגלים לעשות את כל הניתוחים בשפת SQL.
יכולות ה JSON של PostgreSQL הן מתקדמות יותר משל MySQL – אך נראה ש PostgreSQL הוא פשוט פחות סטנדרטי. מקור/2016.
ישנן עוד סדרה של פונקציות המאפשרות פעולות על json ב MySQL – אני רק אזכיר אותן בקצרה, בידיעה שתמיד אפשר לפנות לתיעוד (שהוא ברמה טובה):
  • יצירה של אובייקטי json כחלק משאילתה, בעזרת הפונקציות ()JSON_ARRAY(), JSON_OBJECT ו ()JSON_MERGE_PRESERVE.
  • שינוי של ה json מתוך SQL בעזרת הפונקציות:
    JSON_APPEND(), JSON_ARRAY_APPEND() JSON_ARRAY_INSERT(), JSON_INSERT(), JSON_REMOVE(), JSON_REPLACE(), JSON_SET.
  • פונקציות עזר שימושיות הן:
    ()JSON_UNQUOTE(), JSON_QUOTE(), JSON_DEPTH(), JSON_PRETTY(), JSON_LENGTH(), JSON_TYPE ו ()JSON_VALID
פונקציה שלי מאוד חסרה ב MySQL אך קיימת ב PostgreSQL היא json_each ההופכת מערך או זוגות מתוך עמודת json לרשומות רלציוניות עליהן ניתן לבצע פעולות ב SQL שונות.
בפוסט המשך אני אראה "תרגיל" ב SQL בו אני משתמש בכדי לעשות זאת גם על MySQL.

הערה: יש פתרון לשליפת האיבר האחרון במערך ב MySQL 8 בצורת:

JSON_EXTRACT(JsonData, '$[last]')
או שליפת האיבר לפני האחרון בעזרת last-1.
אני אראה גם "תרגיל" איך ניתן לעשות זאת גם בגרסה 5.7, וללא התמיכה של operator ה last.

סיכום

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

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

גם "Data Science בשקל" – יכול להיות שווה הרבה! (על Tableau)

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

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

למשל:

  • למצוא קשרים לא-צפויים בין נתונים, למשל: הידע שכרטיסי אשראי עם מאפיינים מסוימים אחראים לפי-19 הונאות משימוש בכרטיסים אחרים – הוא ידע שניתן להפוך אותו ליתרון עסקי.
  • היכולת לזהות שתקלה או מצב עומד להתרחש בעזרת סדרה של נתונים מקדימים.
  • היכולת לזהות שמקרה קצה מסוים לא מתרחש או כמעט ולא מתרחש – הוא הזדמנות לקחת החלטה במערכת ולא לתמוך במקרה הזה / לבצע אופטימיזציה עסקית או של ביצועי המערכת.
הדרך להשיג ידע שכזה היא לא קלה, ולרבות מההצלחות להשיג תובנה משמעותית – קודמים כמות ניסיונות כושלים.
בעקבות הטרנדים החמים היום של "Big Data" ושל "AI/ML" – מפתחים רבים מחליטים להשקיע ולהעשיר את הידע שלהם בכיוונים של Data Science.
לפעמים זה ידע תאורטי, לפעמים זו התנסות בסיסית ביצירת רשת ניורונים או Random forest.
בעזרת הטכנולוגיות הללו, נעשים בעולם דברים מדהימים – ואותם אנשי-תוכנה מקווים להגיע להישגים באזורים שלהם.
אני חושב שזו טעות טקטית נפוצה:

  • Data Science, בעיקרML ובמיוחד Deep Learning – הם תחומים עם עקומת למידה תלולה למדי, עדיין.
    • איש תוכנה יכול להשקיע עשרות ומאות שעות בלמידה ופיתוח skill – שעדיין יהיה בסיסי מאוד, יחסית למי שעוסק בתחום במשרה מלאה. לא יהיה לאיש התוכנה יתרון יחסי ברור מול איש-מקצוע ב Data Science, במיוחד לא כזה עם ניסיון לא-מבוטל.
    • אני מעריך שככל שהזמן יעבור – יהיה קל יותר ללמוד וליישם פתרונות Data Science, כך שייתכן ש 100 שעות למידה היום – יהפכו ל 20 שעות למידה בעוד 5 שנים. חלקים רבים מהידע שנלמד היום – יהפכו לכמעט-לא-חשובים, עבור מגוון נפוץ של יישומים / בעיות.
  • דווקא שיטות "פחות-מתוחכמות" של Data Science עשויות להניב לאיש התוכנה יתרון יחסי: שיטות כגון שאילתות SQL, סקריפטים שמעבדים ומנתחים נתונים, או כלי ויזואליזציה.
    • התחומים / שיטות הללו מפותחים כבר מאוד – קל ללמוד אותם מהר, ויש מגוון רחב מאוד של כלים ופרקטיקות שתומכים בהם.
    • יש כאן יתרון יחסי ברור של איש תוכנה המכיר את המערכת מקרוב:
      • הוא מבין את הנתונים (או לפחות חלקים מהם) – בצורה עמוקה.
      • נתון שאינו מכיר – הוא יכול למצוא את הקוד וללמוד בדיוק כיצד הוא מתנהג.
      • הוא יכול להוסיף נתונים ולטייב נתונים, ולהבין בצורה מהירה מה המורכבות של שיפור / טיוב נתונים שכאלו.
        • מה הבעיה ללכת לקוד ולבצע עוד כמה בדיקות / להזיז מקום את הקוד שאוסף נתונים – כך שיהיה מדויק יותר? – לאיש Data Science זוהי מלאכה קשה מאוד.
ארצה להציג דוגמה לשימוש בכלי Data Science "פשוט", שאינו קשור ללמידת מכונה או "Big Data". ספציפית, אסקור כלי בשם Tableau שאני משתמש בו לאחרונה.
Workbook לדוגמה מ Tableau Public
מקור: https://public.tableau.com/en-us/s/gallery/books-made-movies

למה טאבלו (Tableau)?

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

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

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

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

כלים דיי ידועים הם MyDBR או Redash (הישראלי / של יוצא GetTaxi) – שהם טובים ופשוטים, וקל מאוד להתחיל לעבוד איתם בזמן קצר.

אני אכתוב על Tableau שהוא "כלי BI", כלומר שהוא יקר יותר (תשלום ע"פ מספר משתמשים, 30-70 דולר בחודש למשתמש), וההטמעה שלו היא מורכבת יותר.

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

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

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

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

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

ב Tableau Public אתם יכולים להגביל את הגישה של משתמשים אחרים לנתונים / לקוד המקור (ה Workbook) – אם כי משתמשים רבים מתירים את ההורדה.

בכל מקרה, זו בהחלט לא סביבה מתאימה להעלות מידע רגיש עסקית – כי בעקבות תקלה מישהו יוכל לגשת למידע הזה, ורמת האבטחה – לא מובטחת.

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

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

Undo הוא חברכם הטוב 

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

להבין את ההבדל בין Measures ל Dimension

זה קצת מבלבל בהתחלה:

  • Measure הוא נתון שאנו רוצים להציג אותו, או בד"כ – Aggregation שלו (כמו SUM, AVG, אחוזון מסוים, וכו'). מכירות, אחוז הצלחה, וזמן ריצה – הם measures קלאסיים.
  • Dimension הוא נתון שלפיו אנחנו רוצים לפלח את הנתונים ולהציג אותם כשורה / עמודה / אזור בגרף.
    למשל: תאריך (שנה / חודש / יום), מיקום גאוגרפי, קטגוריה, סטטוס (הצלחה / כישלון) וכו' – הם dimension קלאסיים.
איך יודעים מה זה מה? – זה לא כ"כ חד משמעי.

טאבלו ינחש בצורה "תבונית" מה הוא מה – ויקטלג לכם אותם ב Data pane:
טאבלו יטעה מדי פעם – ויהיה עליכם לתקן אותו, ע"י פעולות ה"Convert to Measure" או "Convert to Dimension".
Measures יהיו בד"כ מספרים – עליהם באמת אפשר לבצע Aggregations.
Dimension יהיו בד"כ מחרוזות ותאריכים.
אבל מה אם אני רוצה להשתמש בנתון מספרי טהור, כמו זמן ריצה – כ dimension? לדומה להציג תהליכים מהירים ואטיים בנפרד?
במקרה הזה עליכם ליצור Bins (בתפריט של פריט המידע: …create/bins), שהוא בעצם שדה חדש המקטלג טווחים של הנתון (הרציף, עם אינספור ערכים) שבחרתם.
בטאבלו, כחצי מהזמן שמשקיעים בויזואליזציה יהיה בארגון הנתונים בצורה שטאבלו ידע לעבוד איתם בצורה נכונה. זה תהליך של ניסוי-וטעיה, שמתרחש תוך כדי בניית הויזואליזציה.

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

להבין את ההבדל בין Columns, Rows, ל Marks

גם זה מאוד בסיסי, אם כי מעט מבלבל בהתחלה.

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

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

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

הנה הוספתי לטבלה הנ"ל עוד שני מימדים נוספים:

ההפרדה בין עמודות ושורות היא פחות חשובה, ההפרדה החשובה היא בין מימדים ל Marks, שלרוב יהיו גם מימדים ו measures.

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

Customer הוא אחד ה Segments, ומתחתיו ניתן לראות את השנים.

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

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

הנה אותה הטבלה בדיוק, כאשר אני מציג כ 3 measures כ marks שונים:

  • סכום העסקאות – כגדול הסימון (עיגול).
  • מספר העסקאות – כטקסט (label). הביטוי CNTD הוא קיצור של Count Distinct.
  • אחוז הרווח – כצבע (gradient), כאשר כחול הוא רווח, וכתום הוא הפסד. כתום גדול = הפסד גדול!

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

עוד Marks שניתן להשתמש בהם הוא סוג הצורה (בשימוש ב Shapes) או tool-tip שמופיע ב popup כאשר מצביעים על האיבר.

Show Me הוא כלי חשוב – לא רק למתחילים!

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

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

אני זורק את ה measure של Sales לאחד המימדים (עמודות או שורות – לא משנה) – טאבלו אוטומטית מנחש שאני רוצה לעשות לו aggregation של Sum.
אח"כ אני לוחץ ב Show Me על גרף ההיסטוגרמה – ומקבל את התוצאה הבאה:

הערה: שיניתי את השנתות של ציר ה Y ל logarithmic scale – אחרת היה קשה להבחין בערכים השונים.

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

מה הצבעים ירוק וכחול אומרים?

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

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

למשל: אם ציר ה X שלכם הוא חודש בשנה, ומופיעות שנתות לערכים 0 ו 13 – זה בגלל שהתאריך הוא שדה רציף. הפכו אותו לבדיד – וזה יסתדר.

השתמשו ב Calculated Fields

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

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

היה לי קשה יותר לבנות את המימד הזה בדרך אחרת / SQL query.

לטאבלו יש רשימה של פונקציות זמינות, ותחביר שמזכיר כתיבת פונקציות ב SQL – בהם ניתן להשתמש ב calculated fields. שימו לב שחלק מהפונקציות זמין רק מול data sources ספציפיים כמו Hive או Google BigQuery (המספקים את הפונקציות בצורה טבעית)

עבור חישובים מורכבים יותר אפשר להשתמש בשפת R – שפת תכנות לכל דבר ועניין.
כדי לכתוב Calculated Fields בשפת R יש להתקין מנוע חישובי בשם RServe המריץ את R. טאבלו ישלח את הנתונים ל RServe – שיבצע את החישוב של השדה הנתון – ויחזיר את התוצאות.

SCRIPT_STR(`substr(.arg1, regexpr(" ", .arg1) -1 )`, ATTR([Business Name ]))

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

השתמשו ב Filters

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

שימוש נוסף חשוב הוא ב Dashboards, כאשר אני מצרף כמה ויזואליזציות ובמקום אחד יכול לפלטר את כולם באותה הצורה. מה שנחמד שה Filters ב Dashboard מופיעים ב View Mode (אם לא סילקנו אותם משם) – וכך הקהל הרחב של המשתמשים יכול להשתמש בהם, מבלי להכנס לעומק ה Data Model.

הנה דוגמה של Dashboard פשוט שיצרתי מ-2 הויזואליזציות הנ"ל:

הוספתי Filter דרך אחד מהויזואליזציות (תפריט = חץ למטה/filters – מציג לי את כל המימדים / measures שבשימוש ולכן ניתן לפלטר לפיהם).

בשלב הבא, אני משייך את הפילטר (דרך התפריט שלו) – לכל הנתונים על ה Dashboard:

עכשיו אפשר לראות שצמצום השנים בעזרת הפילטר – משפיע על כל הנתונים ב Dashboard. איזה יופי!

סיכום

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

הוא כלי רב-עוצמה, אך לא מורכב כ"כ לשימוש.

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

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

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

הרשו לעצמכם קצת אי-סדר בקוד (דעה)

כשמדברים על סדר ו״ניקיון״ קוד – יש סקאלה של מצבים אפשריים:

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

לכאורה פדנטיות הקוד היא המצב ״הטוב״ ו'בנה ותקן' הוא המצב ״הרע״ ולכן רובנו שואפים לפדנטיות קוד – אבל אף פעם לא מגיעים לשם: מאוד קשה להגיע לשם, ובמיוחד כאשר יש deadlines ו deliveries.

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

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

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

כמו מהירות האור שהיא יעד בלתי-מושג לגוף עם מאסה, כך גם ״סדר קוד מופתי״ הוא יעד בלתי אפשרי לגוף בעל תפיסה-ביקורתית*.

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

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

מדע בידיוני, בינתיים.

מדוע בכלל לחתור ל״סדר מופתי״ בקוד?

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

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

כוונות מול מציאות

מה עושים?ֿֿֿ

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

האם אני מציע לוותר על ״איכות קוד״ כערך עליון?

זו דילמה קשה!

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

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

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

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

אז מה, בכל זאת, עושים?

טוב. אני מקווה שהצלחתי להעביר את הדילמה.
גישה אחת היא להמשיך בדרך המקובלת יותר בתעשייה – הצבת איכות כערך עליון של הארגון.
גישה נוספת שאני רוצה להציע היא ניהול דינאמי של מצב איכות הקוד:
  1. ננהל רשימה "חיה" של היבטים לא אופטימליים בקוד. את הרשימה כדאי לאסוף ממגוון חברים בארגון.
    1. אם תנהלו את הרשימה הזו ברצינות – מהר מאוד תגיעו לעשרות פריטים ברשימה, ויותר.
    2. אם לא הגעתם – סימן שלא חיפשתם מספיק טוב. זה כמו לשאול את עצמכם ״במה אני פחות טוב?״ – ולא למצוא שום דבר.
  2. מתוך הרשימה – מצאו פריטים בעלי Impact: עדיף impact עסקי, אבל גם impact טכנולוגי – פחות בעיות, יתר קלות לקוד שנוסף למערכת, בקרה טובה יותר על המערכת וכו׳.
    1. סביר שייקח לכם כמה סיבובים על מנת להבין היכן באמת נמצא ה Impact – רעיונות עלולים להישמע טוב, אך להיות חסרי impact לחלוטין בפועל.
  3. תזמנו זמן עבודה מוגדר לצורך שיפורים יזומים ופתרון הפריטים החשובים ביותר ברשימה. ה benchmark הבריא שאני מכיר הוא כ 20% מזמן העבודה
    1. פרשנויות שונות מה עושים בזמן הזה (כמו: ״באגים הם ברשימה״) – יכולים להפוך אותו ללא רלוונטי.
  4. שווה לעבוד בצעדים קטנים. אם יש בעיה גדולה, הרשו לעצמכם למצמצם אותה ולראות מה ההשפעה העסקית שנובעת מכך. למשל: תהליך ה deploy אורך 15 דקות? נסו לבצע שיפור (נניח: המקצר אותו ל8 דק') ולראות מה ההשפעה בפועל. זה יותר טוב מלהשקיע פי כמה עבודה בכדי להביא אותו ל 2 דקות – ולגלות שה impact לא כ"כ משמעותי.
  5. חשוב לערב את אנשי הצוות בהחלטות ובעשיה.
    1. זה לא רק עניין של engagement ושותפות-גורל. זה גם עניין של ״חלונות שבורים״: לחדד ולהזכיר לכולם שקוד טוב הוא ערך חשוב – ושאנחנו כן משקיעים בו. ושהשקעה בו נושאת פרי.

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

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

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

הנה כמה פריטים מרשימות כאלו שניהלתי – שאכן עשו impact:

  • פירוק של טבלה גדולה ב DB לכמה טבלאות – ע״פ דפוסי שימוש שונים.
  • העברת נתונים מבסיס הנתונים ל Redis.
  • שינוי הייצוג של הנתונים – למבנה קל יותר לעבודה.
  • פירוק שרת Redis לשני שרתים ע״פ דפוס שימוש: כזה ל cache וכזה לנתונים שחשוב שיישמרו. הפירוק אפשר לנו לנקות את ה caches ביעילות מבלי גרימת נזק.
  • כתיבת מודול או microservice מחדש. צריכות להיות סיבות טובות למדי – לכתיבה מחדש (ופעמים רבות – יש כאלו).
  • שינוי מבני של flow מורכב במערכת.
  • ניקוי קוד ישן / נתונים ישנים מבסיס הנתונים.
  • הוספת כלי ניטור על מצבים חשובים במערכת – שחסרה נראות שלהם (דברים מאוד ספציפיים)
  • Key Security Items
  • Key Performance Items
  • סידור נתונים ל BI
ברור שהיה עדיף למנוע מראש את היווצרות של המצבים הללו. בהינתן הדינמיקה הארגונית / הלחצים / וחוסר ידיעת העתיד – עד כמה זה באמת אפשרי?
ברור שזו רשימה ספציפית בהקשר ספציפי – שלא אוכל להעביר בפוסט.

הנה כמה פריטים שהיו ברשימות שכאלה, ולעולם לא הגיעו לידי מימוש:
  • סידור flows מסוימים בקוד בכדי שיהיו פשוטים וברורים יותר (הרבה מקרים).
  • HTTP being used internally (ולא https)
  • מקרים מסוימים בהם כשל במיקרו-שירות אחד – גורר כשל במיקרו-שירות אחר
  • Schemas שונים בבסיס הנתונים שנמצאים ב encodings שונים: אחד בשוודית והשני ב ISO.
  • ניקוי ה git repository והסרת 25MB מיותרים.
  • Various Security Items
  • Various Performance Items
  • סידור נתונים ל BI
  • וכו׳

האם הפריטים הללו ראויים לרשימה?!

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

סיכום

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

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

אני זוכר את התקופה שעבדתי ב SAP והיינו פותחים Critical Bug (הרמה הגבוהה ביותר) על כל מקרה בקוד בו עשו [3] catch Throwable (מעל ה JVM). היום אני מתעלם ממקרים כאלו – ואפילו כותב catch throwable בעצמי – אם זו הצורה המקובלת לתפוס Exception בבסיס הקוד בו אני עובד.

היה לנו איזה כלי בשם Sonar (ניתוח סטטי של קוד) שניסה לחשב את ה Technical Debt של בסיס-קוד שהוא סרק בצורה מספרית / דולרית. לכל Catch Throwable הוא נתן תג מחיר של  כמה עשרות דולרים (לא זוכר בדיוק). יכולתי לפתוח tickets חסרי impact לחלוטין, ברמת הדחיפות הכי גבוהה – ולהרגיש טוב עם עצמי שאני חוסך כסף לחברה. צעירות!

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

[2] על בסיס מדדים כמו cyclomatic complexity או מספר הפרמטרים המועברים לפונקציה.

[3] למרות שהייתה כוונה ברמת ה JVM יום אחד לעשות שימוש ב Throwable למטרה מעט אחרת – כבר עברו 23 שנה, ולא נעשה בו כל שימוש. כ״כ הרבה מפתחים השתמשו כבר ב Throwable כאילו הוא Exception לכל דבר – כך שכבר לא נראה לי שניתן לייחס לו בגרסה עתידית משמעות אחרת.