2021-03-20

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

פעמים רבות בחיי השתתפתי בשיחה שהחלה בערך כך:

"אז למה שלא נשתמש ב GraphQL / בסיס נתונים משותף / נעבור מ p2p ל broadcast / נסיר שכבת הפשטה מהתוכנה? - זה יעזור לנו לכתוב תוכנה מהר יותר!".

"אבל מה עם המחירים?"

"איזה מחירים? מה יותר טוב מלכתוב קוד מהר יותר? למה לא?"


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

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


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

זה ויכוח שמתרחש בעולם התוכנה יום וליל, מסביב לגלובס. 

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

במבט-על הוא נראה כמו ה Game of Life בו "שטחים" נכבשים ומשתחררים:


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


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

לופ שלא נגמר.


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


הנה כמה התכתשויות כאלו, שהתרחשו בקנה-מידה עולמי:

--- ביבשת "מבנה התוכנה" ---

Design Patterns נגד ... מה שהיה קודם

YAGNI מול Design Patterns

S.O.L.I.D מול YAGNI

--- ביבשת ה"תקשורת" ---

SOA מול RPC

REST מול SOA

newer RPC (Thrift/gRPC) מול REST

GraphQL מול newer RPC


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





אז מה קורה שם?


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

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

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

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

האם זו בעיה כ"כ סבוכה? NP-Complete? אי אפשר כבר להציב מחשב שיפתור אותה?!

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

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


ה Tradeoff בעולם התוכנה, הוא דיי דומה:

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

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

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

אז מצד אחד אפשרנו - זזנו מהר, מהרגע הראשון.

מצד שני - בטווח הבינוני או הארוך - אנחנו משלמים מחיר שמאט אותנו.

מה עדיף?


הפתרון

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

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

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

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

שפת ג'אווה (1995), למשל, הלכה צעד הלאה וקבעה נורמה של שַׁלְפנים (Getter/Setters) על האובייקטים: הקצנה של הלקח של "אסור לאפשר משתנים גלובאליים" - על scope מצומצם בהרבה, הרי הוא האובייקט. אינספור מפתחים בזבזו במצטבר שנות חיים בכתיבה של getter/setter גם למשתנים שלעולם הגישה אליהם לא תשתנה, ולעולם לא יעשה בהם שימוש לרעה.

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

הנה לנו עוד מחזור.

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

אבל:

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

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


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

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

בכל זאת, הסיכון הוא לא לגמרי סימטרי:

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

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

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


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


תסביר שוב: מה הנזק מאפשור-יתר / ריסון-יתר? אז מה עושים?


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

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

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

האם זה רעיון טוב או לא? זה תלוי בהקשר. 

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

במערכת אפליקטיבית בה:

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

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

דוגמאות:
  • השימוש ב private על members בפרדיגמת ה OO - הוא ריסון ברמת המיקרו. למעבד אין בעיה לגשת לכתובת הזו בזיכרון - אבל אנחנו מורים לו לא לעשות זאת (ומשלמים תקורה בביצועי התוכנה / זמן כתיבת הקוד).
  • כלים לניהול תלויות בין מודולים / מיקרו-שירותים או נהלים להגבלת ספריות ה open source שנכנסות למערכת: אין למתכנת בעיה להוריד כל ספריה ולהתשמש בה - אבל הארגון רוצה לבדוק את הספרייה מבחינת אמינות / תמיכה / כפילות / רשיונות / היבטי אבטחה - לפני שזה נעשה.
  • קונבנציות של קוד - הן ריסון. הקומפיילר יקבל סגנונות שונים ומשונים - אבל הארגון מחליט שבנקודות מסוימות הוא מקבל סגנון רק מסוים.
  • לפעמים גם בחירה של שפת-תכנות היא ריסון. שפת Go מחייבת מבנה אחיד ופשוט הרבה יותר משפה משופעת באפשרויות כמו רובי. מעבר מרובי ל Go - הוא ריסון ניכר.

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


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

ייעצתי פעם לארגון שעבד עם מודל של 6 שכבות סגורות. המערכת לא הייתה עשירה כ"כ ב business logic ורובה ביצעה אינטגרציה בין מערכות.
מידע רב עבר בין שכבה 2 לשכבה 6 - ורוב הקוד בשכבות 3, 4, ו 5 פשוט תרגום שוב ושוב קריאות, הלוך ושוב, למבנים שקולים - אך שונים. חשיפת נתונים בין שכבה 2 לשכבה 6 דרשה כמות נכבדת של קוד? על מה?!

אני בטוח שמישהו הגיע עם כוונה טובה. הוא קרא מאמר או שמע הרצאה על מערכת שעבדה ללא סדר / שכבות - והפכה לסיוט לתחזוקה. אני מדמיין שהוא החליט לא ליפול לפח ולעשות את "הטוב ביותר". לא רק 3 שכבות - אלא 6! לא רק שכבות - אלא שכבות סגורות. Crème de la Crème!

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

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



סיכום


אז מה אפשר לקחת מכל הסיפור הזה?

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

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

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

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

אני משוכנע שאין פתרון אחד כולל / נכון-תמיד ל treadeoff שבין אפשור לבין ריסון.

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

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

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


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


---

[א] בשפות שלא תומכת משתנים גלובאליים ניתן לחשוב על משתנה שעל אובייקט שנגיש לכולם.


21 תגובות:

  1. אנונימי21/3/21 18:21

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

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

    השבמחק
    תשובות
    1. היי,

      תודה על התגובה!

      > המערכת יותר נוטה כלפהם למרות שהם תמיד טועים.
      אני מסכים שיש נטייה לאמץ אפשור בקלות רבה יותר מאשר ריסון - אבל הייתי נזהר ולהניח שתמיד טועים. הרבה פעמים ריסון יוצר תקורה שלא שווה את התמורה. למשל: הגנו על מקרה אחד, אבל הבעיה צצה באופנים נוספים / שונים. אולי חששנו מאסון - שלא מתממש, אבל אנחנו ממשיכים לשלם את מחיר ההגנה.
      בקיצור: כדאי ל tradeoffs בראש פתוח, ולהיות פתוחים לכל מסקנה.
      אולי שימוש ב global variables, בקונטסט מסוים - הוא דווקא עדיף?

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

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

      אני מזדהה עם הבעיה.

      מחק
    4. אני ממש אשמח לכתבה בנושא של סמכויות בצוותי פיתוח ואיך מקבלים החלטות

      מחק
    5. נושא כאוב נוסף שניתן להתייחס אליו זה code review - מה מעמדו של ה reviewer? האם הוא יכול לחייב את כותב הפיצ׳ר לשנות דברים או שהוא רק ממליץ? האם נכון לאפשר לו לחסום הכנסה של קוד ל master?

      מחק
    6. היי,

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

      בנקסט אינשורנס, למשל, ממש לאחרונה הסדרנו את יחסי הכוחות בין ה Reviewer ל Author ב Code Reivew - כי באמת היו שם יותר מדי חוסרי הבנות.

      בסופו של דבר הרבה אנשים רוצים "להחליט" / "להכריע" ולא כולם יהיו מרוצים.

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

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

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

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

    השבמחק
  3. אלעד גור26/3/21 19:29

    כתבה מעולה, תודה רבה
    גם התגובות מעניינות ונכונות מאוד

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

    השבמחק
    תשובות
    1. היי,

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

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

      מחק
  5. פוסט מעולה!
    לגבי "בארגונים פטריארכליים-טכנולוגים" - אני מניח שהתכוונת לארגונים הירארכיים-טכנולוגים...

    השבמחק
    תשובות
    1. תודה על ההערה!

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

      למשל: עבדתי בארגון פיתוח שבה ה VP R&D הכתיב את טכנולוגיה ה UI להשתמש בה - למרות שלא היו כמעט (או בכלל?!) תומכים אחרים למהלך. זו ממה הייתה הכתבה טכנולוגית - שהייתה הרבה מעבר ל"היררכיה" במובן המקובל שלה.

      תודה שוב על העלאת הנקודה.

      מחק
  6. ישראל7/4/21 10:45

    אני מאוד נהנה מהבלוג, תודה!

    יש כמה בעיות עם ריסון ששוה לשים לב אליהן:

    1. באופן אידיאלי היה צריך לבחון את הריסון אחרי תקופה ולראות אם יש בו צורך. בפועל זה דורש דיונים ו push-back ולכן מפתחים לרוב מעדיפים לסבול ולהתמקד במשימות השוטפות.
    2. מה שמגדיל את הבעיה זו ״הטיית המוכר״. מפתח שהתרגל במשך תקופה ששינוי מסוג A דורש לשנות שישה קבצים, משתכנע שזה הדבר ״הנכון״ לעשות ומתקשה לשחרר.
    3. דוגמטיותֿֿ. למדתי פעם ש A הוא טוב, אבל אני לא מבין למה הוא טוב ובאילו נסיבות הוא פחות מתאים.
    4. באופן כללי חוסר אינטליגנציה. למשל: ״את זה אמורים לעשות בשכבה A״. בלי להבין ששכבות לא נוחתות מהשמיים ואנחנו בוחרים איך להגדיר אותן.
    5. ענישה עצמית. פעם עשינו A ושברנו פרודקשן, ולכן אף פעם לא נעשה A, בלי חשיבה על האם A הוא באמת רלוונטי.
    6. תחושת חשיבות שנובעת מהגדרת ריסונים. ״פה אנחנו לא עושים דברים כאלה״ בלי דיון אמיתי על פלוסים ומינוסים.

    השבמחק
    תשובות
    1. תודה ישראל!

      אני רואה את השם "ישראל" מגיב הרבה, ואיני יודע אם מדובר באדם אחד, שניים, או יותר :-)

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

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

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

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

      מחק
    2. הי ליאור.

      בנוגע לשם, זאת התגובה הראשונה שלי בבלוג :)

      אני מקבל את מה שאתה אומר על הסימטריה של הטיעונים. תודה על התגובה המאוזנת.

      מחק
  7. הסברת מעולה, תודה

    השבמחק