על המגבלות של REST – בשירות מערכות ווב בנות-זמננו

כבר כתבתי על REST בבלוג: ב 2011 (בהרבה התלהבות) וגם ב 2016 (במתינות) – מה ששיקף תהליך אישי של התלהבות רבה מ REST, והתפכחות לאורך הזמן.

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

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

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

על אלו מגבלות אנחנו מדברים? הרי REST הוא כמעט-מושלם, לא?

למי שלא זוכר / לא היה בתעשייה בשנות ה-2000 אזכיר בקצרה את ההיסטוריה:
בתחילת שנות ה-2000, כאשר התברר לתעשיית התוכנה שמערכות תוכנה הולכות ונעשות מורכבות יותר, ויותר – ולכן רבות מהן הופכות למערכות מבוזרות (יותר משרת אחד) – ומכאן צמח רעיון ה Service-Oriented-Architecture (בקיצור: SOA) לארגון של מערכות מבוזרות שכאלו. מייקרוסופט הציעה את פרוטוקול ה SOAP (לשעבר XML-RPC) כבסיס לתקשורת בסוג הארכיטקטורה הזו, מה שהתקבל במהרה ע"י יבמ, ושאר חברותיה.

החברות שהובילו אז את התעשייה (IBM, HPE, Microsoft, וכו') קידמו את רעיונות ה-SOA לכדי מציאות, ועבדו על Suite של פרוטוקולים בשם *-WS שיפתרו את כל הבעיות התקשורת והאינטגרציה של מערכות Enterprise (מה שהיה מעניין באותה תקופה).

סט הפרוטוקולים המרכיבים את *-WS

בחבילת הפרוטוקולים של *-WS היה כמעט הכל, לקחו בחשבון כמעט כל צורך של Enterprise Software, מלבד אחד חשוב מאוד: פשטות.

לא כולם אהבו את SOAP ו *-WS, אחד מהם היה רוי פילדינג אחד ממגדירי התקן של HTTP. בעיניו – HTTP היה "הפרוטוקול של האינטרנט" ועל אף ש HTTP נועד להגשת "דפי ווב", הוא חשב שפרוטוקול אפליקטיבי צריך להשתלב בצורה הרמונית (אולי "טבעית") עם HTTP וה Web Standards הקיימים, ולא להתעלם ולהחליף אותם. זו הייתה מן גישה מוקדמת של "קיומיות וובית" – שהייתה חדשה ומרעננת באותה התקופה. היום קוראים לזה "Web-native".

פילדינג פרסם באותה תקופה עבודת דוקטורט, שבה פרק מס' 5 (המפורסם!) הציג סגנון ארכיטקטוני בשם Representational State Transfer (בקיצור: REST) למערכות ווב, ארכיטקטורה שמשתלבת באופן מאוד טבעי עם ה World Wide Web ו HTTP.

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

תוצר לוואי של "ארכיטקטורת ה REST", כפי שהוגדרה בעבודת הדוקטורט של פילדינג, היה צורת התקשורת בין חלקי המערכת, מה שנקרא כיום RESTful APIs. כלומר: צורת תקשורת של העברת הודעות JSON (במקור: XML) על גבי HTTP תוך השתלבות הרמונית באופיו והתנהגותו של HTTP והווב. ל HTTP יש מנגנונים כגון Caches, ו resource naming (להלן ה URL) הנכונים גם לתקשורת אפליקטיבית – שאם משתמשים ב HTTP, לא צריך לפתח מחדש. העולם מלא בכלים (למשל: דפדפן, Firewalls, Postman, swagger) שעובדים כבר עם HTTP, והמבנים של HTTP (כלומר: URL, Status Codes, Methods, Headers, Cookies) – מוכרים היטב* בתעשייה, ומקלים על אימוץ הטכנולוגיה.


* האמירה ש"כולם מכירים HTTP" היא סופר-מקובלת בתעשייה, אבל פה אני צריך להשתעל קצת – ולהתוודות שהיא לא לגמרי נכונה. גם כיום, בעידן הידע, ה Geektime, ושנים לאחר ש RESTful APIs הפכו לסטנדרט הלא-מעורער של התעשייה – אני נתקל בחוסרים גדולים של מהנדסי תוכנה בהבנה בסיסית של פרוטוקול ה HTTP. נכון יותר לומר ש HTTP מתועד היטב ויש עליו אינסוף חומר ו References – ולכן הוא נגיש יותר מפרוטוקולים proprietary אחרים.

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

להיכן ממשיכים מכאן?

REST איננו תקן (אלא פרק בעבודת דוקטורט) והפרשנות ל RESTFul APIs אף יותר מזה – היא פרשנות, שכל אחד יכול לקחת למקום שונה. עם הזמן צצה הביקורת על "גנבי-הדעת" שפשוט מעבירים XML על גבי HTTP וקוראים למה שעשו "RESTful API" – מבלי באמת לכבד את פרוטוקול ה HTTP ו/או להשתלב בעקרונות הווב המקובלים (resources, openess, linking). מודל הביקורת שתפס יותר מכל להערכת "יישום RESTful APIs" הוא Richardson's Maturity Model (בקיצור RMM):

הפסים שאתם רואים בשכבה הנמוכה הם בוץ, רפש – שדובקים בכל מי שמסתפק ב "XML/JSON over HTTP" ועוד קורא לזה REST.
גם אני, כשהייתי עוד REST Evangelist – כעסתי על כל מי שנוהג כך. מה, אין כבוד?

ע"פ מודל ה RMM, לשלוח XML או JSON על גבי HTTP הוא נקודות האפס הבסיסית ביותר (והמוערכת הכי פחות). משם אפשר להתקדם לעיצוב "נכון" של URLs, שימוש "נכון" ב HTTP Verbs, ועד הגביע הקדוש של Hypermedia transformations. השתלבות המערכת עם "טבע ה HTTP והווב".

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

שאלה דומה היא שאלת ההשתלבות ב HTTP/Web ומידת ההצמדות לרעיון ה REST: יישום של RESTful APIs ברמה 3 לפי ה RMM אולי תעניק לכם חיים בעולם הבא בקרב "קהילת נאמני ה REST" – אך כנראה גם תתברר כעבודה הנדסית בינונית עד איומה, ברוב המקרים. למשל: רמה 3 טוענת שכל קריאה לשרת צריכה לבוא מתוך "גלישה טבעית בווב". באתר ווב אני מתחיל מאתר הבית – ובסדרה של קישורים מגיע לדף בו אני מעוניין. באופן דומה, הטענה היא ששרתים שמדברים זה מזה – צריכים להתקדם למטרה בצעדים. לא לשאול: "כמה כסף יש בחשבון של לקוח X?" אלא תמיד יש להתחיל בשאלה "מי אתה? אלו לקוחות יש לך? איזה מידע יש לכל לקוח? האא… ורק אז לשאול: אז כמה כסף יש בחשבון של לקוח X?".

אם יש לנו שרתים "קרובים" (אותה מערכת) שמתקשרים הרבה, ההבדל בין 4 קריאות (3 "נימוסים" + 1 תכל'ס) על כל בקשה מול קריאה בודדת (רק תכל'ס) – היא משמעותית. רק במקום עבודה אחד בחיים ראיתי יישום של Hypermedia transformations – ואולי עשינו HATEOAS, אבל סיבכנו מאוד את המערכת. ממש ברמת העוול / הטיפשות.

מכאן עולה השאלה המתבקשת: "כמה RESTFulness" כדאי לעשות? ואיך יודעים לאמוד מתי ההצמדות ל RESTfulness היא תורמת, ומתי היא כבר מזיקה?

אז מהן המגבלות העיקריות של RESTFul APIs?

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

Hypermedia Transformations / HATEOAS – ברוב המקרים, מבחינה הנדסית – זה פשוט טירוף לשמו. יש להימנע – וחבל להמשיך ולעסוק בעניין.

HTTP Verbs הם שפה מגוונת ועשירה למערכות פורומים / Wikis – אך דלה ומוגבלת עבור מערכות ווב מודרניות ומורכבות. הנה ההגדרות מתוך וויקיפדיה:

והנה כמה מגבלות יום-יומיות ,שכנראה שכולנו נתקלים בהן:

  • קריאת GET איננה כוללת Body. כאשר אנחנו רוצים לעשות קריאה שהיא safe (לא משנה את state המערכת), אך רוצים להעביר פרטים מגוונים של הבקשה – אנחנו חסומים לשימוש ב URL לבדו. זו נשמעת מגבלה קטנה, כי על URL אפשר גם לשים 6,000 ויותר תווים בדפדפנים של ימנו – אבל זה לא כ"כ מעשי:
    • Query String הוא נחמד, וקל להשתמש בו בהפשטה של מילון (<Map<String, String) – אל זו עדיין צורה מגבילה להעברת מידע. אין היררכיה, וקשה לתאר מבנים מורכבים יותר. בעיה.
    • על זה נוסיף את הצורך ב URL encoding, כי יש תווים שאסור להציב על ה URL. למשל: רווח (להלן ה %20 שאתם רואים ב URLs). מהר מאוד ה URL הופך ללא קריא, ולכן פחות שימושי.
    • אפשר לקודד JSON (מבנה גמיש והיררכי) על ה URL – אבל זה מקרה קיצוני יותר מהאייטם הקודם. זה כבר לא פשוט, לא שקוף, ולא Web native. פספסנו לגמרי את הרעיון של שימוש ב HTTP בגלל "קריאות ופשטות". כבר כבר יותר RPC.
    • אותה בעיה – קיימת גם עבור פעולות Delete (לכאורה Body הוא optional – אבל כלים רבים יחסמו אותו).
    • הפתרון הנפוץ הוא לבצע פעולות POST עבור קריאות שהיו אמורות להיות GET. ב POST אפשר להעביר body – אבל בעצם השימוש ב POST התרחקנו מההקפדה על הסמנטיקה של HTTP – שזה כל העניין. לא ניתן להבחין כבר בין POST שהוא safe לכזה שלא, ללא מידע נוסף. ראיתי מגוון גישות להתמודד עם החריגה הזו (POST as GET) – כל גישה, וה tradeoffs שלה.
  • חוסר בהירות בין POST ל PUT
    • פעולת PUT ב HTTP משמשת להחלפה של משאב שנמצא ב URL בתוכן הנשלח ב Body, וזו פעולה Idempotent – ניתן לבצע את אותה הפעולה מספר פעמים, מבלי שהתוצאה תהיה שונה מביצוע יחיד של הפעולה.
    • פעולת POST ב HTTP מעדכנת / שולחת מידע למשאב שנמצא ב URL – שזו הגדרה כללית הרבה יותר. הפעולה בהגדרה איננה Idempotent (כלומר: חלק מהפעמים היא עשויה להיות – אך אסור להסתמך על זה).
    • מכאן ועד תרגום של ה Verbs של PUT ו POST ל Create/Update/פעולה אחרת – יש מגוון של פרשנויות, לפעמים פרשנויות סותרות המתבססות על דקויות נכונות מתוך התקן של HTTP. במערכת Wiki, קביעת גבולות ברורים בין PUT ל POST היא דבר קל – במערכת מוצר מורכבת ומסועפת, תקן ה HTTP משאיר אותנו "חשופים" לדילמות, פרשנויות, והתלבטויות.
    • אם אתם לא מכירים את הדיונים הרבים, הנה מאמר תמציתי אחד שמסביר מדוע POST ו PUT הם לא פשוט Create ו Update.
  • בלי להכביר במילים, חוסר בהירות דומה קיימת גם בין PUT ו PATCH. הנה מאמר של המחבר הנ"ל לגבי הדילמה הזו. יש גם מאמר על PUT vs. PATCH vs. JSON-PATCH, ועוד אחד, ועוד אחד, ועוד אחד – כל אחד עם טענה מעט שונה.
הנה פרשנות אחת (ומקובלת) מתי להשתמש ב PUT ומתי ב POST ליצירת אובייקט. יש עוד כמה פרשנויות סבירות והגיוניות.
  • אולי המגבלה הכי קשה באימוץ "REST על מלא-מלא" בהיבט ה Verbs הוא הדלות ואי-העדכניות של ה Verbs המקוריים של HTTP לצרכים ועושר-הפעולות של מערכות תוכנה מודרניות. REST גרס שלא צריך להמציא "שפה חדש" – ואפשר להשתמש ב HTTP, אבל בשפה הזו יש רק 9 פעלים (עוד כ 20 נרשמו כהצעות) – אך אנו זקוקים ל 300 פעלים בכדי לקיים שיחה אינטליגנטית בדומיין העסקי שלנו? דומיין שהוא הרבה יותר מ CRUD?
    • אולי עבור מערכת וויקי, 9 פעלים מספיקים: עמוד יכול להיווצר / להיכתב מחדש (PUT), אפשר לכתוב עליו הערות (POST), ניתן לעשות בו תיקונים קטנים (PATCH) ואפשר למחוק אותו (DELETE) – הנה הסתדרנו!
    • במערכת של חברת ביטוח (למשל), בה על פוליסת ביטוח ניתן לבצע מגוון של פעולות:
      • לחתום על הפוליסה
      • להתחיל את הפוליסה
      • להקפיא / להפשיר את הפוליסה.
      • להוסיף מוטבים.
      • להוריד עותק של המסמך
      • לשלוח את המסמך לצד שלישי
      • לשלוח אישורים על המסמך לצד שלישי
      • לעדכן פרטים של בעל הפוליסה
      • לעדכן פרטים לגבי תוכן הפוליסה
      • לשנות כיסויים בפוליסה
      • לבדוק את הכיסויים בפוליסה
      • לבדוק סימולציה של מקרה – האם מכוסה ע"י הפוליסה
      • לבצע ביקורת על הפוליסה (Audit)
      • ועוד פעולות רבות…
      • הפוליסה מתוארת בצורה RESTFul למהדרין, כ URL כמו customers/{customer_id}/policies/{policy_id}/ אבל אין לי סיכוי לתאר את מגוון הפעולות הנ"ל בעזרת POST/PUT/PATCH בלבד. כל הרעיון ש "נראה את ה verb בלוגים השונים – ונבין מה התרחש" – מאבד ערך אם עבור כל הפעולות הנ"ל אני משתמש ב POST verb (פתרון מקובל אחד). יתרה מכך: אני צריך להשלים את הסמנטיקה שמבדילה בין הפעולות השונות איפשהו (על ה URL? על ה body? כ Header? כ Query Param) – אין מקום מוגדר וברור לעשות זאת. מגוון אפשרויות, עם tradeoffs וחריגות שונות מתקן ה HTTP והכוונות מאחוריו.
  • גם ברמת ה URI, אנו נתקל במגבלות: תיאור של URL היררכי לכל אובייקט במערכת – הוא לא דבר חד-משמעי ופשוט כפי שהיה במערכות פשוטות פעם (שוב: וויקי/מערכת פורומים). אקצר מאוד כדי לא להאריך את הפוסט אבל בעיקר:
    • לא תמיד יש היררכיה בין אובייקטים. לפעמים יש אובייקטים שהם שכנים "Siblings" – ואין דרך טובה לתאר את הקשר בהיררכיה (על ה Path).
    • לפעמים פרטי הזהות של אובייקט הם מורכבים / ארוכים מדי בכדי להיכנס ל URL.
    • ב REST/HTTP אין סמנטיקה לתאר Bulk operation – פעולה על מגוון אובייקטים. ישנן workarounds אך הם שונים ומגוונים, ולכל אחד – המגבלות שלו.
  • ב REST/HTTP אין דרך מוסכמת לתאר גרסאות ועתיות של APIs. באופן אישי אני משוכנע שהשתתפתי בעשרות שעות של דיונים בנושאים הללו, בארגונים שונים ועם אנשים שונים – כי אין תשובה פשוטה של REST שניתן לגשת ולהציג אותה. הנה סדרה של גישות ודיונים בנושא, למי שרוצה לצלול… הנה גם תקציר על 4 גישות מקובלות.
מישהו ריכז כאן דוגמאות וגישות ל versioning ב REST (והיד עוד נטויה). רק להדגים שהנושא אינו "סגור בטון" ומקובל על כולם באותו האופן.
  • עוד "שפה" שהייתה טובה / עשירה בזמנה – אך היום היא מוגבלת מדי היא ה HTTP Status codes. קודים כגון OK 200 או 401 (הקוד נקרא "Unauthorized" אך הכוונה היא בעצם ל Unauthenticated) – טובים ומתאימים לשכבת התשתית, אך מזמן כבר דלים מכדי לתאר את שכבת האפליקציה. להזכיר: HTTP הוגדר עבור ניהול דפי וויב ("documents" או "resources") ולא לתיאור של אפליקציות עסקיות מורכבות. למשל:
    • האם 404 מתאר endpoint שלא קיים, אובייקט שלא נמצא, או פריט מידע לפעולה שלא נמצא? איך מבדילים בין המקרים אם חזר רק הקוד "404"? דיון. לא פעם מפתח אחר מתכוון לדבר אחד, ומפתח אחר – מבין דבר אחר.
    • עוד דוגמה קלאסית היא המשמעות של 400 (הקרוי Bad Request).
      • ע"פ התקן – השרת לא יכול או לא יטפל בבקשה מכיוון שלא הוגשה בקשה נכונה מצד הלקוח (פורמט שגוי, שליחה ליעד הלא נכון)
      • השימוש הנפוץ הוא הרחבה של הקונספט "משהו לא טוב בבקשה" (ולא רק בפורמט/יעד) למשל: נשלח id שלא קיים של אובייקט. אבל…
        • אם נשלחו בבקשה כמה Ids – אז איזה מהם?
        • או אולי, אי אפשר לבצע את הפעולה מכיוון שעבר התאריך.
        • או אולי, לא ניתן לעשות פעולה בסכום נכון, כי החשבון מוקפא, או כי אלו פרטים אחרים אינם תואמים?
      • בקיצור: שום קוד סביר לא בצד הלקוח לא יכול להסתמך על קוד HTTP 400 להחלטה משמעותית של שינוי ב Flow ללא פרטים נוספים. נדרשים קודים מדויקים למגוון גדול של תקלות אפשריות, אז מה החשיבות להחזיר גם קוד HTTP 400? ראיתי שנים אנשים שהקפידו ותיקנו שוב ושוב קוד שהחזיר HTTP 500 להחזיר HTTP 400 – אך מעולם לא נתקלתי בערך שצץ מהפעולה הזו… פשוט עבודה לחינם.
  • עוד נושאים שאפשר לציין ש REST/HTTP לא נותנים להם מענה:
    • תקשורת אסינכרונית
    • Notifications – התקשורת של HTTP היא בקשה/תשובה. אם השרת המרוחק רוצה להודיע לי משהו ביוזמתו – כיצד הוא יעשה זאת?

אלו צרכים בסיסיים, שכנראה רוב מערכות הווב של ימנו זקוקות להם.
חשוב לציין ש HTTP/2 הוא כבר פרוטוקול בינארי, עם יכולות notifications, ואסינכרוניות (Pipeline/streams) – אך עדיין לא נתקלתי ב RESTful APIs שמשתלב ביכולות הללו בצורה הרמונית וטבעית.

סיכום

חזרנו והתבוננו ב REST בראייה מפוכחת, לא רק "REST זה טוב, SOA זה רע" – פזמון הפאנק של אמצע שנות ה-2000.

אני לא ממליץ לאף אחד לחזור ל *-WS או SOAP חלילה, הם כבר עתיקים ולא רלוונטיים. ייתכן ו RESTFul APIs זו הגדרה מספיק טובה לסט מצומצם של Public APIs של חברה (והרי ב Public API יש יתרון גדול בשימוש בתמות מוכרות), אך דיי ברור שלצורכי התקשורת הפנימיים של מערכת מורכבת / מיקרו-שירותים, RESTFul APIs היא גישה מוגבלת מדי ודלה בסמנטיקה – שחייבת הרחבה.

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

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

יש ניסיונות כנים ומשמעותיים לנסות ו"לתקן" את REST (בצד התקשורת; צד הארכיטקטורה הוא מאוד ספציפי ומתאים רק למיעוט שבמיעוט שבמערכות) למשל JSON API או להיצמד ל Guidelines של מישהו שעשה עבודה משמעותית, למשל ה Microsoft RESTFul API Guidelines. פעם מישהו הציע לי לאמץ בארגון את JSON API ושללתי את זה על הסף ("כל ארגון יגדיר את מה שמתאים לו"). היום הייתי מתייחס לאופציה הזו ברצינות גדולה יותר. לא כ "תורה מסיני שתפתור הכל", אלא כדי לא להתחיל את תהליך ההגדרה הארגוני מאפס.

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

תנועות כגון Forget HTTP + הרצאה או HTTP Hell-no אולי מביעות הרבה תסכול מה"אכזבה" של REST בפועל – אך מנסות להציע גם חלופות ותיקון.

טכניקות כגון Polling, Long-Polling ו Webhooks הן דוגמאות פשוטות להרחבות טכניות פשוטות – המאפשרות עוד הרבה מרחב תמרון במקומות ש HTTP/REST מוגבל בהם ("client קורא ל server", וזהו). יש לי הסברים מפורטים על הטכניקות הללו – אניח לרגע שכל הקוראים מבינים אותן. כן גם משמרות את האופי של HTTP/REST כמעט ולחלוטין – זו רק הרחבה.

הפתיחות לאמץ אלמנטים של RPC בצורת העבודה של הארגון (להתגמש ב Resource modeling, להוסיף קודים של הארגון לכל תשובה, ו/או מבנה סטנדרטי של בקשה/תשובה לכלל המערכת) עשויים לשרת אתכם היטב, גם אם "קהילת נאמני ה REST" – ידיחו אתכם מחברות בארגון / חיי נצח / ההבטחה ל 70 מהנדסות תוכנה (טובות!) בעולם הבא.

(אם מישהו ישאל, JSON-RPC הוא פשטני ונאיבי מדי לטעמי, וגם אותו תאלצו מהר מאוד להרחיב ולהגדיר בעצמכם. RCP בינארי כמו Thrift או gRPC הוא אטקרטיבי לשיפור ביצועים / אמינות התקשורת – אך מהלך כבד מדי אם כל מה שאתם מחפשים הוא סמנטיקה וכללי עבודה טובים לבעיות מידול ה Endpoints במערכת שאינה very high scale, הפשטות הרי חשובה).

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

אם אתם עובדים ברמה של HTTP בצורה ניכרת (או ב RESTFul APIs או ב RPC כלשהו, למשל home-made) – חשוב ללמוד את התקן הפשוט והחשוב הזה, ולהבין אותו. אני רוצה להאמין שזה מאמץ קטן ומשתלם. יש את הפוסטים שלי (HTTP Basics + מבנה ה URL) אלו ואלו, יש את הרפרנס הנחמד הזה של for-get-HTTP – HTTP References שמצאתי במהלך כתיבת הפוסט – ונראה לי שאשתמש בו עוד בעתיד.

מחשבות, הערות, תוספות – יתקבלו בברכה!

ארכיטקטורת-נתונים במערכות מוצר

יש המון שיח על ארכיטקטורות נתונים בשנים האחרונות. Data Lakes, Lambda Architecture ו Delta Lake וכו'.

כמי שעובד במערכת מוצר (מיד אגדיר) – רוב הדיונים הללו עוברים מעל הראש:

  • כמות הנתונים שמתעסקים איתה היא לא כ"כ גדולה – ובטח לא עצומה.
    • למשל: בסיס נתונים המכיל "רק" 2TB של נתונים – ועוד כמה events או מסמכים התופסים יותר מקום – אך מאוכסנים ב S3 (שירות אכסון הנתונים של אמזון, בעל ממשק דומה למערכת קבצים).
  • את רוב העבודה יכולים, וגם רוצים – לעשות בבסיס הנתונים רלציוני.
    • אולי חלק מהמידע הוא Document-Based (הרי PostgreSQL ו MySQL תומכים בניהול מסמכי JSON) אולי יש עוד בסיס נתונים אחד או שניים NoSQL – אך הם משתמשים לתהליכים מאוד ספציפיים.
  • אין עיבודי מידע גדולים / מורכבים בלב המערכת – שבסיס נתונים רלציוני לא יכול להם.
    • אולי יש כמה תהליכי אצווה שמעבדים הרבה נתונים – ואז סיכומים שלהם הופכים לדוחות או חוזרים כסיכום למערכת – אך לא באופן שישנה את הארכיטקטורה הבסיסית של המערכת.
  • המערכת היא אחידה, ולא מורכבת מתתי מערכות שונות ומשונות (למשל: שנבעו מסדרה של רכישות).

יש לנו Lambda Architecture וגם Data Warehouse וגם Data Lake (ועוד אחרים) – אך בעיות הדאטה הגדולות שלנו לא נמצאות שם. 

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

מה הן "מערכות-מוצר", ומה בעיות הנתונים הנפוצות שלהן?

מערכת-מוצר היא מערכת שמשרתת לקוחות קצה (אנשים פרטים, עסקים קטנים או גדולים – אך מערכות אחרות) ורוב האתגר בה הוא ניהול המידע וה Flow העסקיים. למשל: LinkedIn, Moday, Gett, Next-Insurance, ועוד רבים.

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

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

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

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

  • המערכת משתמשת בכאלף טבלאות בבסיס-הנתונים (יש גם טבלאות טכניות. 500-700 בעלות נתונים עסקיים בעלי-משמעות). זה בערך 10 טבלאות לכל מפתח – מדד שיכול להצביע על העומק / מורכבות של המודל העסקי המטופל.
    • אציין שיש כ 30 מיני-שירותים, ואני סופר את הטבלאות של כולם ביחד.
  • שינויי סכמה בטבלאות קיימות מתרחשים כל שבוע. כלומר – המודל דינאמי למדי.
      • עבודה ב Continous Deployment הופך את הבעיה לקשה יותר: כל שינוי – מוחל מיד על הנתונים הקיימים וישפיע על כל צרכני-הנתונים.
  • ישנם כ 20 אנליסטים (והמספר גדל) שאמורים להתמודד עם כל המגוון הזה של הנתונים – ולהסיק ממנו מסקנות מדויקות, וחד משמעיות – מסקנות שיובילו להחלטות עסקיות, למשל: מה ההשפעה של שינוי מסוים במערכת.
  • דיוק הנתונים עשוי להיות בעל חשיבות עליונה: טעות של 1 למיליון בנתונים כספיים או בנתונים לגבי כיסויים ביטוחיים – היא כבר בעיה שיש לטפל בה (בשונה ממערכות עיבוד נתונים רבות, המוכנות לספוג איבוד/אי-דיוק נתונים גדול בהרבה. לדוגמה מערכת שאיבוד / טעות בעד 0.02% מהנתונים, 1 ל 5,000 – לא נחשב בעיה)
    • כמובן שגם במערכות מוצר יש מידע חשוב יותר וחשוב פחות – ויש סובלנות לאיבוד/אי-דיוק מידע באזורים מסוימים.
  •  טווח העבודה העיקרי עם הנתונים הוא שנה עסקית, כלומר 12 חודשים לאחור. אם היה באג בנתונים מלפני 3 חודשים – חשוב לחזור ולתקן אותם, ואת כל ההשפעות שנבעו מהשינוי => מה שאולי גורר עוד ועוד תיקוני נתונים, ברקורסיה.

 

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

  • תהליך ה ETL (העברת הנתונים בסיס הנתונים של המערכת למשטח עבודת-נתונים "נוח יותר" כמו Data Lake או Data Warehouse) – צריך להתמודד עם שינויים יומיומיים בסכמה.
    • עם שינויים כגון הוספת טבלה חדשה – קל להתמודד. זו יכולת מובנה ברוב כלי ה ETL.
    • שינויים כגון שינוי סכמה או תיקון היסטורי של נתונים (Backfill) – כבר דורשים טיפול מיוחד, במיוחד כדי לא להוציא את הנתונים ב"משטחי העבודה של הנתונים" מעקביות (Consistency).
  • תקשור מודל הנתונים: כיצד אנליסט אמור להתמודד עם מגוון של מאות טבלאות שמתווספות ומשתנות כל הזמן?
    • מה הסיכוי לחוסר הבנה לגבי משמעות הנתונים, שיגררו ניתוח לא מדויק או אפילו שגוי לגמרי? (רמז – לא קטן בכלל)
  • כאשר ה Data Engineers (האחראים על תהליך ה ETL) והאנליסטים "סובלים" – ההשפעה מחלחלת בחזרה גם למהנדסים.
    • "לחץ" להאטה בקצב / עומק השינויים. כאשר דוחות / ניתוחים מורכבים מתבססים על מבנה נתונים מסוים – שינוי המבנה עשוי לגרור עבודת עדכון של שבועות ואף חודשים. הברירה השנייה: להורות למפתחים לא לשנות את מבנה הנתונים "ולהסתדר" עם מבנה הנתונים הקיים (מה שעשוי ליצור בעיה גדולה למפתחים).
    • דיונים ושאילתות חוזרות על משמעות הנתונים – מה שגורר זמן עבודה משמעותי בין מפתחים ואנשי-נתונים לגבי משמעות הנתונים.
      • תסריט שמי שחי בעולמות הללו בטח מכיר: מדד עסקי מראה ירידה בדוחות, ועכשיו צריך לחקור: האם הבעיה בדוחות, בשינויי מודל הנתונים, או באג בקוד? המנכ"ל או מי מטעמו מגיע למפתחים בבקשה "להוכיח שזה לא באג בקוד"… 
    • כל זה גורר לאיבוד אמון בין הקבוצות, מה שרק שעלול לגרום להגביר את הבעיות, ואז שוב לפגוע באמון – וחוזר חלילה. מחזור של הסלמה…
  • ככל שהמודל העסקי מורכב ומגוון – כך קשה גם יותר למפתחים להבין אותו, ולשמור עליו עקבי בלי שיצוצו "כפילויות" או "סתירות" במודל בין המפתחים, שיחזרו ויסבכו את על העניין.
  • כיצד מנתחים נתונים היסטוריים? החברה קיימת 10 שנים, ומודל הנתונים בה משתנה תדיר. איך מנתחים מגמות לאורך השונים על מודלים משתנים.
    • גישה אפשרית אחת: כל פעם שמשנים מודל עסקי – עושים migration של כל מידע העבר למודל המעודכן.
      • תהליך migration הוא תהליך קשה ויקר (בשעות עבודה). נדרשים לא פעם "להשלים/להמציא" נתונים שלא היו בעבר – מה שמקטין את האמינות של הנתונים לאורך זמן.
    • גישה אפשרית אחרת: הניתוחים העסקיים יידרשו להכיר את כל הווריאציות של המודלים העסקיים לדורותיהם – מה שיהפוך אותם למורכבים הרבה יותר לביצוע.

 

ארכיטקטורת-נתונים טיפוסית

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

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

הנה המתודולוגיות העיקריות שאני מכיר:

הברירה הטבעית

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

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

על זה נאמר: לארגון יש מדיניות חוץ – אך אין לו מדיניות פנים.

Long Release Cycle

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

  • היה כלל שלא משנים Schema של בסיס נתונים בגרסה שאינה major.
  • גרסת major יצאה אחת לכמה שנים.

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

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

 Event Log / Event Streaming

המודל המקובל ביותר, By Far, בעניינים של שיתוף נתונים בין המערכת האופרטיבית (מפתחים) – למערכות הנתונים (אנשי-דאטה מסוגים שונים) הוא על בסיס Events:

"אירוע: משתמש חדש נרשם במערכת… הנה כל הפרטים"

"אירוע: משתמש שינה את תמונת הפרופיל שלו…. הנה כל הפרטים"

"אירוע: משתמש על Accept לאחר 5 שניות מרגע שהופיע המסך… הנה כל הפרטים".

בואו נעשה כמה הבחנות:

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

ה Events לרוב מיוצרים בקוד של המערכת האופרטיבית (מיקרו-שירותים) ועוברים על גבי Event Streaming Infrasturcture (כגון Kafka, Pulsar, Kinesis) ל Data Lake. משם הם יעברו ל DWH (או Data Lake אחר) שם "יסכמו את האירועים" לצורה של אובייקטים המציגים את המצב הקיים, או שיעשו עליהם ניתוחים ברמת ה Events.

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

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

ישנן עוד כמה בעיות מובנות במודל ה Events:

  • בסיס נתונים הוא אמין יותר מ Event Stream Infra: הודעות עלולות להיאבד או להישלח פעמיים + Events הם עיבוד הנתונים – ולא מקור הנתונים. לכאורה יש כאן ירידה מ"מערכות נתונים שצופות ישר בבסיס הנתונים, the source of truth".
    • לכל אלו שקופצים עם "Kafka supports Exactly-once message delivery semantics" אני אזכיר שתקלות יכולות להתרחש גם לפני / אחרי Kafka.
    • בסופו של דבר, יהיה לנו כנראה תהליך Scheduled של Eventual Consistency – שיאתר פערים במידע, וישלים אותם.
  • תיקוני נתונים הם קשים הרבה יותר ב Events (יחסית לבסיס נתונים). נניח גילינו שחייבנו 15K לקוחות ביותר מדי – נרצה לחזור ולעדכן אותם. שתי הגישות העיקריות לתיקון נתונים הם:
    • הוספת אירוע מתקן (או סדרה של אירועים מתקנים), עם Effective Date של עבר – כך שמי שמרכיב את האירועים ידע להרכיב אותם נכון.
      • קושי עיקרי כאן הוא לייצר Delta "נכונה". כלל שהלוגיקה העסקית מורכבת יותר, והאירוע הוא ברמת-הפשטה גבוהה יותר, יהיה קשה לייצר את ה Delta נכון – ולוודא שהיא נכונה. קוד המערכת כתוב בכדי לייצור אירועים חדשים, ויצירת של Deltas (נכונות) – עשוי להיות אתגר ממשי.
    • לכל אירוע מוצמד מזהה חזק (GUID), ואירועים יישלחו מחדש – מתוקנים.
      • כאן הקושי הוא לאתר אלו אירועים יש לתקן (אירוע הוא הפשטה מעל מספר טבלאות בסיס נתונים + הם יושבים ב Data Lake – מערכת נוספת שמפתחים צריכים "להתעסק" איתה). גם כאן, כשאין Delta, צריך לדעת איזה רכיב בדיוק במערכת הקוד יש להפעיל – רכיב שאולי לא נבדק במוד הרצה שכזה – וזה אתגר. (רמז: מתחילים בכתיבת Tests לתסריט החדש הזה).
    • תיקון נתונים מתחיל כתהליך, "One-off", ידני – אך מהר מאוד מגלים שזו שגרה, ומשקיעים בתהליכים מסודרים ואוטומטיים לתקן מידע לאחור.
  • הגדרה של תיאור/Contract ברור וחד-משמעי של כל Event הוא לא תמיד דבר פשוט, בטח כשיש עשרות ומאות אירועים במערכת. 
    • כתיבת בדיקות אוטומטית שיאשרו שלא חורגים מהחוזה שהוסכם לכל אירוע. 

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

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

Well-monitored Data Sharing

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

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

הסיבות העיקריות למודל ה Well-monitored data sharing הוא לרוב:

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

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

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

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

סיכום

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

שני המודלים הרלוונטיים הם כנראה ה Event-Steaming ו Well-monitored shared Data. אפשר לעשות בהם mix and match ע"פ הצרכים של כל ארגון / מערכת.

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

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

 

תודה לנדב נוה, ששימש כ Reviwer לפוסט – ועזר לי לדבר יותר לעניין.

 

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

The Log: What every software engineer should know about real-time data's unifying abstraction – מאמר של יוצר Kafka מ 2013, שגם עוסק במבנה הטכני של Event Streams – אבל גם בכל בעיות הדאטה שציינו כאן (LinkedIn היא חברת-מוצר / מערכת-מוצר קלאסית)

דיון: סיווג סוגי תקשורת במערכות ווב

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

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

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

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

אחת ההשלמות הללו היא סביבת מיקרו-שירותים (Microservices) והטכנולוגיות הנובעות מסביבה כזו: היכרות עם HTTP עם REST עם טכנולוגיות ענן (ספציפית: AWS), ומכיוון שמדובר במערכת מבוזרת – ענייני תקשורת, Data Consistency וכו'.

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

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

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

מה יצא?

הנה תוצאת הסיווג שלי לאחר שלושה סיבובים של ארגון מחדש: 

החלוקה הבסיסית היא לתקשורת סינכרונית מול אסינכרונית (זה יחסית ברור).
בחלוקה המשנית, בעיקר בדרכי תקשורת אסינכרוניים – זה כבר היה הרבה יותר קשה. התחלתי בסיווג לפי בין Queue ו Steam/Bus או Other message Broker אבל ההבדלים בין SQS ל RabbitMQ עדיין הרגישו גדולים מדי להתאים לאותה קטגוריה.
כנ"ל רשימת ה "Other" גדלה וכללה כחצי מהטכנולוגיות שרשמתי – עוד סימן לסיווג חסר.

הערות קטנות:

  • Query & Modification Languages הן מצד אחד סוג של RPC (בקשה-תשובה, כאשר הבקשה עשירה ומפורטת) ושקלתי להציב אותן בענף של RPC – מצד שני, הן לא תחליף באמת ל RPC ולכן בסוף סיווגתי אותן כענף נפרד.
  • אולי חסרים לכם WebSocket, Server Push, או Server Side Events וכו' – אלו בעיקר רלוונטיים מול דפדפן, וההתמקדות שלי היא בתקשורת שרת-לשרת. גם TCP ו BGP לא מוזכרים 🙂
  • Thrift הוא בעיקרו בינארי, למרות שיכול גם לעבוד ב JSON ולכן הוא לא יושב "חזק" במקום.
  • JSON:API הוא בחלקו ניסיון לתקנן משהו מאוד דומה ל RESTFul API – אבל גם מעודד ומקל על עבודה שהיא יותר RPC.
  • על הצד האסינכרוני אין לי הערות קטנות – כי הכל שם מרגיש מאוד "בערך"…

אני (חושב שאני) יודע מה אתם אומרים…

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

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

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

 

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

מה קרה לבלוג? POST 301

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

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

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

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

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

  • העברתי את הבלוג לפלטפורמה של WordPress.
    • חידשתי עיצוב – לעיצוב סופר מינימליסטי, ועכשווי (אני מקווה) – אני עדיין מאמין שהתוכן הוא העיקר.
    • הביצועים טובים יותר – לפי מדידות ראשוניות שלי. מקווה שכך יישאר, אין סיבה לחכות 4 שניות לטעינה של דף.
    • יש לי פתרון מובנה יותר ל code snippets או code highlighting. בבלוגר לא היה פתרון מובנה ודחפתי scripts של קוד, כמה ורסיות – ואף פעם זה לא עבד טוב. הדרך הנפוצה בסוף הייתה screenshots מתוך ה IDE.
  • אני אחדש את דרכי התקשורת. כל פוסט יזכה להודעה בערוצים הבאים:
    • רישום במייל – ניתן לעשות ב Side Pane (ב Desktop) או בתחתית העמוד (במובייל). הוספתי את רשימת המנויים הקודמים לרשימת התפוצה כך שמי שנרשם לא יצטרך להרשם מחדש – אבל אני צריך לוודא שזה באמת עובד.
    • דף הפייסבוק של הבלוג – אחריו ניתן לעקוב אם אתם משתמשים בפייסבוק.
    • חשבון טוויטר שיפרסם פוסטים חדשים. טוויטר האמת, זו הפלטפורמה שהחברתית שאני משתמש בה – ומאוד מעריך אותה.
    • ערוץ טלגרם – עוד פלטפורמה שנראית לי שימושית ופופולארית.
    • RSS Feed הישן והטוב עדיין כאן בכתובת: https://softwarearchiblog.com/feed. תודה לאוהד על ההערה.
  • אני רוצה לנסות ולהפוך את הבלוג ליותר קהילתי. יותר תקשורת דו-כיוונית.
    • אני חושב שתקשורת חד כיוונית התאימה לאופי שלי יותר ב 2011, אבל דברים השתנו. וידוי אישי: המחשבה שאציג משהו ואז אתפס בחוסר ידע / טועה / מדבר שטויות – הטרידה אותי שנים. שריטה אישית, אבל עבורי זה היה ממש פחד משתק. השתפרתי מאז – אבל זה עדיין פחד עמוק שקיים בי. אני מניח שזה גרם לי לכתוב פוסטים מושקעים ולבדוק בשנית כמעט כל משפט שאני כותב. היה בזה משהו מלמד (לא פעם הבדיקה העלתה שאני לא יודע נכון / מספיק נכון) – וכך למדתי, אבל אני מניח שגם חסמתי פתח לדיון דו כיווני.
      בשנים האחרונות התחלתי לכתוב בבלוג בצורה יותר משוחררת, יותר דיונים, ויותר על נושאים שלא יכולתי לאמת ממקורות צד-שלישי. התחלתי לקחת סיכונים שאני מפרסם דברים לא נכונים / לא שלמים (לא שזה לא קרה לי גם כאשר ביצעתי בדיקות עומק… תמיד יש פספוסים).
    • אני לא יודע בדיוק איך ליצור תקשורת דו-כיוונית משמעותית יותר, אבל בתור התחלה טלגרם, טוויטר, ופייסבוק כמובן פתוחים לתגובות מכל סוג – וארצה לעודד אנשים לכתוב יותר. אחוז גבוה מהתגובות בבלוג היו ("פוסט טוב!") – שזה נחמד, אבל זה סימן לכך שלא היה מקום לדיון. אני רואה שזה קצת משתנה בשנים האחרונות – וזה עבורי סימן שאני בעיקר כותב בצורה שיותר מעודדת דיון ושיח.
    • כבר מזמן שהתגובתיות שלי לתגובות בבלוג אינה טובה: אני עונה אחרי שבועות, חודשים, וגם יותר. זה נכון גם למיילים, גם מחברים וגם בעבודה. החיים שלי עמוסים – ואני לא מכונה משומנת היטב של multi-tasking. אני עובד כל פעם על משהו אחד, ומתעלם מכל השאר. אולי אכתוב על זה פעם אחת – אבל בחירה מודעת, ולא רק עצלנות גרידא. בכל זאת, אנסה לעשות מאמץ ולהתחיל להגיב בצורה תדירה יותר על הערות בבלוג – לא תהיה תקשורת דו כיוונית אם לא אהיה תגובתי וזמין.
  • כמה בעיות שצפויות בדרך:
    • המעבר מבלוגר הפתיע אותי לטובה בטיב שלו, אבל עדיין יש כמה בעיות – שייקח לי זמן לפתור:
      • המעבר הוסיף escaping על מרכאות בטקסט. \" במקום פשוט ". תיקנתי את 20 הפוסטים האחרונים ידנית – ואמצא דרך לתקן פוסטים היסטוריים.
      • לא העברתי עדיין את כמה ה javascripts שהוספתי לעימוד קוד – וחלק מהקוד בפוסטי עבר פשוט לא ייראה טוב. אשתדל לתקן את זה עם הזמן.
      • קטן: בעבר היה לי script שהוסיף תגיות id לכל הכותרות, כך ששימוש ב fragment (כלומר #) ב URL יכול היה להצביע לכותרת – לפי המספור שלה. למשל הוספה של #4 היה קופץ לכותרת הרביעית. ההתנהגות הזו נשברה וחלק מהקישורים שהצביעו לכותרת – יצביעו לראשית הפוסט. אנסה לתקן גם את זה.
    • בעקבות הבעיות הללו אני אשאיר את הבלוג הישן חי לעוד זמן לא ידוע, תחת הדומיין http://softwarearchiblog.blogspot.com
    • רק טבעי שיהיו רק סדרה של בעיות ונושאים טכניים בעקבות המעבר. בדקתי את דרכי התקשורת, והבלוג בעצמי – אבל בטוח פספסתי דברים. אני אודה לכם ש: א. תשתפו אותי. ב. תגלו סבלנות. תודה מראש!

כמה אנקדוטות:

  • הלוגו של הבלוג היה לוגו לפרוטוקול ה atompub – נושא שהעסיק אותי בתקופה שעבדתי בסאפ ועשו מעבר מסיבי ל ODATA מעל atompub. מאוד מיושן, ולא מעניין אותי מאז.
    הלוגו החדש (והפעם הוא גם בולט) הוא לוגו ל"קשר גורדי" – ביטוי לבעיה קשה שאינה פתירה. עבורי פיצוח הנדסת התוכנה, וההקשרים האנושיים שלה – היא קשר גורדי שאנסה להותיר קמעה בימי חיי, גם בידיעה שלא אגיע לסוף.
    • על פי האגדה, את הקשר עשה איכר בשם גורדיוס שהומלך למלך פריגיה (אזור טורקיה של ימנו) וזה היה קשר ללא קצוות חשופים. הקצוות הוחבאו בתוך הקשר העבות, ונוצרה אגדה שמי שיצליח להותיר אותו – יזכה לשלוט בכל אסיה. רבים הגיעו וניסו להתיר את הקשר – ללא הצלחה. הייתה יראת כבוד, ואף אחד לא "פשפש" מספיק חזק בקשר למצוא את הקצוות הפתוחים. אף אחד עד אלכסנדר הגדול – שפשוט חתך את הקשר בחרבו, ואז התפנה גם לכבוש את אסיה. זהו עוד לקח נחמד, שעצם זה שהבעיה אינה פתירה – לא צריך לשתק ולעצור אותנו. אפשר להתקדם גם ללא פתרון.
  • זהו פוסט מספר 301 בבלוג. למי שלא מקשר, Status Code מספר 301 ב HTTP הוא moved permanently – שזה מה שקרה בעצם לבלוג. הגעה ל 300 פוסטים (יוו!) היה בשבילי עוד טריגר לבוא ולבצע חידוש – ורק אח"כ עשיתי את הקישור למשמעות של 301.

מקווה שנשתמע בקרוב,

ליאור

מי מקבל את ההחלטות הטכנולוגיות בארגון? [דיון]

בפוסט אפשור מול ריסון: קרב האור באופל של ארכיטקטורת התוכנה? התפתח דיון:

  • מי נכון שיקבל את ההחלטות הטכנולוגיות בארגון?
  • איך זהות מקבל ההחלטות משפיעה על היחס בין ריסון לאפשור?
  • ב Code Review – מה מעמדו של ה Reviewer? האם הוא יכול לחייב את כותב הפיצ׳ר לשנות דברים או שהוא רק ממליץ? האם נכון לאפשר לו לחסום הכנסה של קוד ל master?
 
הנה צץ לו נושא אמיתי, שהטריד כמה מקוראי הבלוג – והחלטתי להרים את הכפפה.
 
תייגתי את הפוסט כ [דיון] כי בניגוד לרוב הפוסטים, אין לי מתודולוגיה סדורה שאני מתבסס עליה. זה גם אינו נושא שהפכתי וחשבתי עליו רבות (אם אני כותב פוסט על כזה נושא, לרוב התחבטתי בו כבר שנים). אני כותב את הפוסט כי הנושא נראה לי מעניין, חשוב, ורלוונטי – ובעיקר בעקבות בקשות קוראים. אז בואו ניקח אותו בפרספקטיבה הנכונה.
 
 

טראומות

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

"נושא כאוב נוסף שניתן להתייחס אליו זה code review – מה מעמדו של ה reviewer?…" – עוד תגובה לפוסט

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

אשתף בשתי "טראומות" שלי:

שעבדתי ב SAP עבדנו על מוצר וובי (Web) כלשהו, יום אחד הגיע ארכיטקט בכיר מאוד בארגון ודרש שנשכתב את כל המוצר משפת ג'אווה ל PL/QSL – על גבי בסיס הנתונים החדש ש SAP בנתה, HANA. הוא טען שהביצועים ישתפרו בצורה דרמטית, וזה יועיל למוצר – וגם כדרך אגב SAP תוכל להתנסות יותר בפיתוח משמעותי על גבי HANA, כמו שנאמר: Eat your own dog food.

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

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

המקרה השני התרחש דווקא בחברת סאטראט-אפ בה רצינו, לראשונה, לבנות אפליקציית Desktop למשתמשים חצי-טכניים. ה VP R&D של הארגון דחף באגרסיביות כלי בשם Eclipse-RCP, פלטפורמת ה UI בה משתמשת Eclipse (ומיועדת לכתיבת IDEs או כלים דומים) – על סמך היכרות על הפלטפורמה מפרויקט שניהל בארגון קודם.

בחנו את הטכנולוגיות מול אלטרנטיבות יותר מקובלות (בזמנו): ממשק וובי, Java Swing, ו FORMS.NET.

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

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

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

מה אפשר ללמוד מהמקרים הללו?

(אני מתייחס רק לשני המקרים שתיארתי – שאני מכיר אותם היטב)

  • לעתים ה"אנשים הפשוטים בשטח" מבינים טוב יותר, ויכולים לקבל החלטות טובות יותר ממנהלים בכירים.
  • בכל זאת, קולם של האנשים הבכירים רם יותר – והשפעתם גדולה יותר.
    • במאמר מוסגר אוסיף שזו אחת המוטיבציות של אנשים להתקדם בארגון: להתקדם בעיקר בכדי להיות מסוגלים להשפיע יותר.
  • כשהטיעונים להחלטה לא נראים הגיוניים / מציאותיים – מתרחש תהליך של איבוד אמון, תהליך המלווה בתסכול וכאב, בקרב אלו שלא יכולים להשפיע עליו.
  • בחדרי הישיבות ובדיונים ניתן לומר הכל – אבל מציאות-ברורה היא חזקה יותר.
    • למשל: למרות כוחו הרב של מנהל הפיתוח לקבוע שימוש ב Eclipse RCP בניגוד לכל הדעות האחרות, עבודה קצרה (יחסית) בשטח – הפכה לחלוטין את ההחלטה.
    • כלומר: המנהל יכול היה להכריע שננסה את השימוש ב Eclipse RCP, אבל לא באמת היה לו מספיק כח להכריח את השימוש בו לאורך זמן / ניסיון לא טוב.
 
אני אוסיף כמה תובנות נוספות, מכלל הניסיון שלי:
  • אנשים שונים מבינים את המציאות באופנים שונים, לעתים במידה שכמעט ואינה ניתנת לגישור.
    • לפעמים, התכתשויות על החלטות טכנולוגיות – נעשות באמונה שלמה, של שני הצדדים, שזה הדבר נכון לארגון. זה המקרה הטוב יותר.
    • יש מקרים, לא נדירים, בהם השיקול שמנחה אנשים הוא לא באמת טובת הארגון, אלא טובתם שלהם: חשק, עניין, תחושת ביטחון ("זו הטכנולוגיה שאני מכיר", "נוח לי יותר לעבוד עם הקבוצה הזו", או "זה יקנה לי שקט מול מישהו קולני בארגון"). הרבה פעמים אלו צרכים אישיים ולא "רשעות טהורה" – אבל הגישה הזו לרוב תוביל לתוצאה (וגם אווירה) – טובה פחות. זה המקרה הפחות טוב.
      • אני אתוודה, שאני לא פעם "דחפתי" החלטות טכנולוגיות על בסיס היכרות אישית שלי. רציתי שנעבוד עם כלים שאני בקיא בהם, ויהיה לי יותר מה לתרום, ויותר יכולת השפעה. רק במעט הפעמים – זה היה השיקול הנכון לארגון (כלומר: זה שאני אכיר / ארגיש בנוח עם הטכנולוגיה), ואני מנסה מאוד להימנע ולחזור על הטעות הזו.
  • החלטות טכנולוגיות, על אף המאמץ להפוך אותן "למדע מדויק" – לעולם לא יהיו לגמרי כאלו. תמיד יש בהן אלמנטים של טעם אישי וניסיונות עבר סובייקטיביים, הן יוכרעו במידה על סמך יחסי-הכוחות בארגון, ובלתי-נמנע שחלק מהאנשים לא יהיו מרוצים.
    • אני לא מאמין בניסיון לרצות את כולם – ואני מאמין שהן צריכות להתקבל ולהעשות, גם כשיש חוסר שביעות-רצון. כמובן שככל שחוסר שביעות הרצון גדול יותר, ומאנשים רלוונטיים יותר – נכונות ההחלטה נחלשת.
    • חשוב, לתת משקל משמעותי למי שעומד "לחיות" עם ההחלטה, ולשלם בפועל על טעויות בהחלטה. למשל: אם בניתוח הטכני אופציה א' מקבלת ציון 90 ואופציה ב' ציון 70, אבל הצוות שאמור לממש את הקוד ולחיות איתו מאמין יותר באופציה ב' – סיכוי טוב שנכון יותר לאמץ את אופציה ב', משני טיעונים מאוד ענייניים:
      • א. סיכוי טוב שמישהו בשטח מבין משהו שאתם לא, אפילו אם הוא לא יודע להסביר את זה בצורה טובה. (אם היה מתקשר מעולה, אולי היו מקדמים אותו והוא כבר לא היה בשטח?).
      • ב. מוטיבציה היא הדלק של תעשיית התוכנה. מי שכואב את הבחירה באופציה א', יוכל בלי משים, לממש אותה בדירוג 60, בעוד את אופציה ב' שהוא מאוד מאמין בה, להביא למימוש לדירוג 80.
        זו נשמעת כמו סחטנות או כוחנות, אבל זו המציאות האנושית ככל שאני מצליח להבין אותה: כך הדברים מתגלגלים בשטח ולא חכם "לטבוע בצדקנות". אנשים טובים יעשו עבודה פחות טובה שהם לא מרגישים חלק ממנה, ועבודה יותר טובה כאשר הם כן מרגישים חלק ממנה. לכן זה צריך להיות פאקטור גדול בשיקול.
  • המציאות חזקה יותר מכל טיעון – ולכן לעתים עדיף להתכתש בשטח מאשר באולם הדיונים. כאשר זה אפשרי, יש טעם בפשוט לנסות בשטח, ולשמור אופציות לשינוי כיוון.
    • לא פעם נופתע, שבעצם אופציה שפחות האמנו בה עובדת "טוב מספיק".
    • לא פעם, המציאות בשטח תשנה את דעת המתנגדים – ברוח טובה, ונוכל לפנות לדרך טובה יותר, כקבוצה מגובשת.
    • הכרעה בשטח היא בשום אופן לא הסתמכות על הגורל או "הרמת ידיים". כדי להצליח בה טוב חשוב:
      • לחתור בשטח למגע מוקדם וחד-משמעי, ככל האפשר, עם נקודות המחלקות.
      • תיאום ציפיות לשינוי כיוון, במידה ומדדי הצלחה מסוימים לא יוכרעו.
      • אפשור האופציות הטכנולוגיות (ארכיטקטורה), והפרויקטליות (לוחות זמנים) לשינוי הכיוון. אם יצאנו לניסיון בלי יכולת אמיתית לבצע שינוי כיוון אמיתי מאוחר יותר – יצאנו פשוט טיפשים. סליחה.
  • ניתן אולי להסיק מכאן שעדיף "להפוך את הפירמידה" ולתת למפתחים את מירב שיקול הדעת וההחלטות בנושאים טכנולוגיים – וכך גם להשיג את מירב המוטיבציה וההיכרות עם השטח. זו שאיפה יפה, אבל אני חושב שהיא לא מתרחשת מהסיבות הבאות:
    • לעתים מפתחים בשטח מבינים טוב יותר – אבל גם לפעמים לא.
    • מפתחים נוטים לגלות אהבה רבה לטכנולוגיות חדשות ומדוברות – באופן שמטה יותר מדי החלטות לכיוונים פחות טובים.
    • גם מפתחים לא חפים מאלמנט של קידום האינטרס האישי: "שימוש ב ישפר את מעמדי מול חברי / קו"ח / בטחון עצמי".
    • למפתחים לרוב יש הבנה פחות טובה של הביזנס, אלמנט קריטי בנכונות של ההחלטה.
    • מפתחים לא פעם מפגינים חשיבה קצרת טווח / נאיבית – לגבי החלטות.
    • בקיצור: הבכירים לרוב קונים את מעמדם (וקולם העדיף) בזכות האמון בהם, שהם מסוגלים לקחת החלטות טובות יותר. כמובן שיש כשלים במינויים, ולא פעם הבכיר הוא אדם שמקבל החלטות טכנולוגיות רעות באופן סדרתי.
  • ניסיון וידע הם דבר להתבסס עליו בקבלת החלטות טכנולוגיות – אבל כיצד?
    • אני רואה משקל משמעותי למישהו שכבר היה בסיטואציה דומה. זהו ניסיון קונקרטי.
    • "שנות-ניסיון" הוא לטעמי מדד מטעה: זה חבל, אבל יש אנשים עם 10 ו 20 שנות ניסיון שהידע שלהם פחות יסודי ו/או הם מקבלים החלטות טכנולוגיות פחות טוב מאנשים אחרים עם 5 או אפילו פחות שנות ניסיון. הם עברו הרבה מערכות וחברות – אבל ספגו מזה רק מעט. מאוד הייתי רוצה לאפיין מהי קבלת החלטות טובה וכיצד רוכשים את המיומנות הזו. ניסיתי בכמה הזדמנויות – אבל זה נושא גדול.
    • ברור שהמעמדות (מונח מציק באוזן) בארגון משנים גם הם. לארכיטקט או ראש צוות יהיה משקל גדול יותר – על אף שייתכן שהם לא "יספקו את הסחורה".
      • ראשי צוותים, למשל, הם ה Backbone של הארגון. זה תפקיד קשה, שוחק, ולעתים – כפוי טובה. הארגון "חייב" משהו לאנשים הללו בתמורה, ולעתים זה מתבטא בסלחנות להחלטות פחות טובות שלהם. דינאמיקת ה"קח ותן" הזו נוגעת בכל מי שנותן ערך נוסף לארגון והארגון "חייב" לו. זו דינמיקה חיונית, כנראה – שיש לה צדדים פחות יפים, אך היא חשובה.
 
 

אפשור מול ריסון בהיבט של קבלת החלטות

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

חקר-מקרה: נקסט אינשורנס

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

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

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

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

 
הפילוסופיה של הארגון היא:
  • קבלת החלטות היא העצמה ופיתוח של העובד – ויש רצון לתת למפתחים לקבל החלטות בעצמם, ככל שזה יעבוד טוב.
  • האחריות מוטלת בסופו של דבר על ראשי הצוותים, ראשי הקבוצות, ואף הארכיטקטים – ואחריות באה עם יכולת השפעה.
אלו שני עקרונות סותרים, אבל משרטטים גבול מטושטש כלשהו של קבלת ההחלטות: החלטה מקומית – ברמת המפתח. ככל שההשפעה של ההחלטה גדולה יותר – תתקבל בדרגים גבוהים יותר. הדרגים הגבוהים יכולים וצריכים להשפיע ואפילו במקרים חמורים – להפוך החלטות לא טובות (בהנחה שהם זיהו נכון את המצב, ורוב הפעמים הפיכת ההחלטה תעשה טוב – ולא נזק).
 
החופש של המפתח לקבל החלטות תלויה מאוד בראש הצוות שלו, והאמון שיש למפתח עם ראש הצוות. ראשי צוותים מסוימים יותר נוטים לסמוך על מפתחים ולתת להם את החופש בקבלת החלטות מאשר אחרים. ראשי צוותים נוטים לסמוך ולתת לחברי צוות אחדים יותר חופש על פני אחרים – זה מאוד אינדוודואלי ומקומי. באופן לא לגמרי טריוויאלי, לא תמיד המפתחים מרגישים תרומה אישית יותר אצל ראשי צוותים שנותנים יותר חופש. יש הטוענים שדווקא ראשי הצוותים שמעורבים בפרטים – הם סביבת עבודה עדיפה וטובה יותר (שוב: הסתכלות אישית).
 
צוותים אחראים על מיקרו-שירותים – ולכן ניתן להם חופש בעיצוב המיקרו-שירות. לחופש הזה יש גבולות, ולרוב אני (או הארכיטקטים שאיתי) הם אלו שמגבילים אותו:
  • חשוב לנו ניהול Stack מינימלי של טכנולוגיות – בכדי לפשט את המערכת ולשמר את היכולת של מפתח מצוות X להבין ולשנות קוד של צוות Y. אנחנו נקשה/נאתגר בכל פעם שיהיה רצון להרחיב ולשנות את ה Stack הטכונולוגי, ונגדיר סדרת מבחנים – שיש לעבור בכדי להוסיף טכנולוגיה ל Stacks (יש לנו כמה Stacks שכאלו: Backend, Frontend, ו Data).
  • כנ"ל לגבי מבנים וסגנונות עבודה. יש לנו קווים מנחים / Patterns למבנה של מיקרו-שירות (שכבות, אינטרקציה, דרך לכתוב בדיקות, איך מתבצעת תקשורת בין שירותים, דפוסים לעבודה עם בסיס הנתונים) – ואני והצוות שלי נאתגר את מי שירצה לחרוג או לשנות אותם. צריך להראות ערך / צורך ברור ומעל ספק סביר – בכדי לעשות שינוי. העיקרון המנחה הוא שמערכת אחידה יותר – תהיה מובנה וצפויה יותר לשאר הארגון.
  • יש לנו תהליך של "ניסוי" בו כל אחד, בתיאום ראש הצוות, יכול לנסות טכנולוגיה חדשה / סגנון חדש באזור מוגדר. לאחר כמה חודשים של ניסיון אמור להיות שלב Go/no Go. אם קבוצת ה Reveiw השתכנה שזה שיפור ברור – מאמצים כחלק מהסטנדרט (או לעתים: סטנדרט רק למקרים ספיציפיים ומגודרים היטב.). אם צוות ה Reviewer לא השתכנע שזה מספיק טוב – הניסוי יימחק והקוד יומר לסנטדרט.
    • תהליך יפה, שלא כ"כ מתנהל בפועל. יש שני מקרים ברורים בהם נכנסו כך טכנולוגיות חדשות לרוחב החברה – וגם מספר דחיות, אבל עדיין ממתינים כ 10 ניסיויים באוויר, בלי שאנחנו עושים להם תהליך רביו. כשל אישי שלי.
  • לא מזמן הקמנו קבוצת עבודה להגדרת Guidelines לעבודה: אני מוביל את הקבוצה בעזרת נציג מכל מחלקת פיתוח. אנו מציעים ביחד טיוטה לסטנדרטים (שהוסכם שכארגון אנו רוצים בהם): כיצד להגדיר API, כיצד לעשות Code Review, כיצד להשתמש ב Exceptions. הטיוטה עוברת Community Review – סשנים בהם כל מפתח יכול להצטרף ולהציע שינויים, אבל הוא צריך לבוא עם "שיעורי בית" מוכנים: טיעונים ודוגמאות משכנעים. על השינויים מסכימים ברמת ה Community. לפעמים זה קל, לפעמים בהצבעה – ואחרת אני מכריע (מקרים נדירים שזה נדרש. נדרש כדי לא למרוח החלטות). מאותו שלב אנחנו מפרסמים את ה Guideline ועובדים לפיו.
    • עד כמה ה Guideline תואם למציאות בפועל? לפעמים יותר, ולפעמים פחות. כשיש ויכוח בין שני צדדים – הוא כן מסמך מכריע בהחלטה. כלומר: צוות שיחליט לעבוד אחרת יכול לעשות זאת "מתחת לראדאר" עד אשר יהיה ויכוח פומבי בנושא. גם אז – ננסה להבין אם הבעיה היא חוסר-הגמישות של הצוות, או בעיה ב Guideline שנקבע.
ספציפית Code Review הוא חוזה חשוב במארג היחסים והדינמיקה של החלטות טכניות בארגון. אסכם שוב את הרקע: אנו עובדים במיקרו-שירותים בהם לכל שירות אחראי צוות מוגדר. אנחנו מאפשרים ומעודדים אנשים לשנות קוד בשירותים אחרים – אבל רק בהסכמה של הצוות שאחראי על השירות. אלו עיקרי העקרונות שלפיהם אנחנו עובדים:
  • חייב להיות לפחות Reviewer אחד שמאשר את הקוד. אם מדובר בקוד של צוות אחר – חייב להיות אישור של מישהו מהצוות.
  • Reviewer שלא מרגיש שיש לו משהו משמעותי לתרום ב Review יסיר את עצמו, ויוסיף Reviewer אחר במידת הצורך.
  • ברוב המקרים, ה Reviewer רק מספק הצעות לכותב הקוד. הצעות יכולות להתקבל או להדחות. אנו מעודדים אנשים להיות רגישים אחד לשני, וגם לפרגן על קוד טוב – בכדי לבנות את האמון.
    • Code Review בהגדרה הוא לא כלי להכתיב סגנון מועדף לאנשים אחרים. ה Reviwer נותן עצות, ורצוי שיצליח לתת אותן ממקום חברי ותומך (ולא ממקום נוזף ומתנגד).
  • במידה וה Reviwer מזהה בעיה משמעותית: באג, תכנון (Design) בעייתי, או חריגה משמעותית מה Guidelines הוא מסמן את ה PR כ "Changes Required". מהשלב הזה ה PR לא יוכל להתמזג (merge) ללא הסכמה של אותו Reviewer. כלומר: אנו נותנים ל Reviewer דגל אדום להרים, שיש מאחורי סמכות – אבל הציפיה היא להשתמש בו בזהירות ובאחריות.
    • מי שישתמש בזכות הזו במידה רבה מדי – יזכה להכוונה מחדש מהמנהל שלו.
  • יש לנו גם שורה של עצות מה לבדוק בקוד Review, ועל מה להעיר. זה בעיקר Checklist לבודק.
 
 

סיכום

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