מחשבות על טופלוגיה של צוותי תוכנה

מודל ה Squads של ספוטיפי

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

הערכים הבולטים של המודל:

  • הרכבת צוותים אוטונומיים (״self-organizing team״), להלן Squads.
    • תקשורת בין צוותים היא תקורה, ולכן נרצה צוות הכולל את כל מגוון הדיסיפלינות (״cross-functional״: בעיקר מהנדסים, אבל גם פרודקט, ניהול פרויקט, אנשי-נתונים, וכו׳) – כך שהצוות יוכל לעבוד עצמאית, ועם מינימום (בשאיפה: אפס) תלויות בצוותים אחרים.
    • הדגש הוא על מהירות. מה יאפשר לנו לנוע מהר יותר? אוטונומיה? אז בואו ניתן הרבה ממנה.
  • לצוות תהיה אחריות קצה לקצה על התוצר. הצוות יעבוד על הדרישות מול אנשי המוצר עד לשחרור לפרודקשיין ותמיכה בתוצר.
  • Guilds ו Chapters, כמנגנון המפצה על חוסר בבסיס משותף ברמה המקצועית הנובעת מהעצמאיות של ה Squads. הגילדה הוא פורום של בעלי עניין (למשל: פיתוח Backend, אבטחה, או UX) שבו מתקיימת הפריה הדדית והעברת ידע בין אנשים עם מומחיות / תחומי עניין דומים. ה Chapter הוא יותר ממוקד (מערכות Payment, או Graph Databases) המשתפים ידע, בין אנשים באותו הלוקיישן / אותו Tribe. כ 10% מהזמן של המהנדסים אמור להיות מושקע ב Chapter ופעילויותיו.
    • בעצם, כל מפתח שייך ל Squad שמוביל פעילות עסקית, וגם ל Chapter שמוביל מומחיות מקצועית ממוקדת, ואולי גם חבר בכמה Guilds.
    • ה Services ותתי המערכות הן באחריות ה Squads (ע״פ ספוטיפי). לפעמים מאמצים את המודל של ספוטיפי אך מנהלים את השירותים / תתי-המערכות ברמת ה Chapter (מה שדומה יותר למודל הבא שאסקור: Product/Platform Teams).

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

  • איזו צלע נכונה שתהיה יותר דומיננטית עבור המפתח? ה Squad (קרי: delivery) או ה Chapter (קרי: מומחיות מקצועית)? על פניו נראה מקריאה, שה Squad הופך להיות הצלע הדומיננטית ברוב הפעמים.
  • איך בעצם מפתחים פיצ׳רים שנוגעים ב services שבאחריות כמה squads? ברור שהאידאל הוא שכל פיצ׳ר יוכל להיתרגם ל service יחיד, או לפחות לאלו שבבעלות squad יחיד, אך במערכות מורכבות – השאיפה הזו לרוב לא מושגת.
  • מה קורה כאשר יש שינוי עדיפויות בארגון, וזקוקים להרבה עבודה באזור ב׳ ולא באזור א׳? מה קורה עם ה squads שעובדים על א׳ – ואיך מחלקים מחדש את האחריויות?

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

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

  • בניית תשתיות מקומיות ומאוד ספציפיות ל use case לו נדרש הסקוואד => מעט שימוש חוזר => תשתיות כפולות => חוסר יכולת להשקיע בתשתיות ארוכות טווח שישתלמו לארגון עם הזמן.
    • כידוע, שימוש חוזר אינו חזות הכל, ולעתים נכון לשכפל קוד ומנגנונים כדי להסיר תלויות בין חלקי המערכת. במבנה הסקוואדים התמריץ הדומיננטי הוא לכיוון עצמאות מרבית (מינימום תלויות) – כך שב Tradeoff הקלאסי בין עצמאות מרבית לשימוש-חוזר מירבי – סביר שנמצא את עצמו בקצה הראשון של הסקאלה, שהוא לעיתים נדירות רק יהיה נכון לארגון לטווח ארוך.
  • חוסר התלות עשוי לחלחל גם ל Technology Stack וארכיטקטורת המערכת, אזורים הקשים מאוד לשינוי. אם וכאשר הארגון ירצה ״ליישר״ את ה Stack או ארכיטקטורה – זו עשויה להיות עבודה גדולה מדי מלהחיל (״too big to happen״).
  • הסכנה המצטברת היא שהארגון יגיע ל״דרך ללא מוצא״ כאשר השקעה גדולה מדי נעשתה בראייה מקומית (קרי: צורכי הסקוואד הבודד), והדרך היחידה הישימה לאחד את המערכת לראיה אחת הוא לכתוב אותה מחדש. לא פעם ארגונים מגיעים לרגע שהשלב הבא בביזנס דורש יישור רוחבי עמוק, שלא ייתכן כאשר המערכת בנויה כמערכת של Silos.

צוותי מוצר ופלטפורמה

מודל ה Product / Platform Teams צמח במקביל למודל ה Squads. הוא דומה לו בכמה אופנים, אבל כולל גם כמה הבדלים משמעותיים.

  • בדומה ל Squads, צוותי המוצר (Product Teams) הם Cross-functional (קרי, מכילים מגוון מומחיויות) ועצמאים במידת האפשר.
    • הם יכולים להיות אחראים על Flow קבוע, לקוח קבוע וכו׳ – או להיות מוקמים ולפעול לצורך משימה ספציפית (פיצ׳ר X).
    • צוותי מוצר אחראים למיקרו-שירותים הקבועים לתחום האחריות שלהם: אפליקציות / UI, ושירותים המנהלים Flows רוחביים במערכת (הרבה פעמים צוות מוצר אחראי על Flow).
  • בניגוד למודל ה Squads, ישנו עוד סוג של צוותים, צוותי התשתית (Platform) המפתחים יכולות רוחביות בארגון, בהם ישתמשו מספר צוותי מוצר. הדוגמאות הקלות הן שירותים תשתיתיים בהגדרה, כגון Authentication/Authorization, שירותי Notification, תשלומים, וכו׳. שירותים נוספים שיהיו אצל צוותי הפלטפורמה הם שירותים ב core business של החברה, שמשמשים למגוון Flows / אפליקציות. למשל: שירות לניהול לקוחות, שירות לניהול הזמנות, שירות המנהל את מוצרי החברה, וכו׳.
    • אפשר לומר שצוותי תשתית, הם צוותי מוצר, כאשר הלקוחות שלהם הם פנימיים: צוותי המוצר. יש אפילו ארגונים המצרפים אנשי מוצר לצוותי תשתית.
    • צוותים כמו צוותי Operations (גם אם נקראים בטעות ״צוות DevOps״), או אבטחה – נופלים לקטגוריה של צוותי תשתיות.

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

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

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

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

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

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

לסיכום, מודל ה Product/Platform Teams מתאים יותר לארגון בטווח הארוך, אך הוא דורש השקעה ותיאומים גדולים הרבה יותר => פחות פריון פר מפתח. אני מדמיין שארגונים שמתחילים במודל ה Squads מגיעים לנקודה בה הם לא יכולים להמשיך לפעול במודל שמעודד ראייה קצרת טווח ונאלצים לעבוד למודל קרוב יותר למודל ה Product/Platform Teams.

סתם צוותי Components

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

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

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

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

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

  • המודל הזה הוא בעצם המודל ההופכי למודל של סופטיפי – המון מומחיות ועומק, אבל מעט מאוד עצמאות של צוותים וקושי גדול לספק Deliveries תדירים. אני מאמין שהרוב המודלים האחרים בפוסט הם תגובה לאכזבה ותסכול מהמודל הזה.
  • אני לא חושב שהמודל בהכרח רע. עם TPM מצויינים, ותרבות ארגונית של שיתוף וחתירה לעזרה – הדברים יכולים לעבוד טוב. כמובן שהמודל מתאים למערכות הכבדות, המסובכות ביותר – ושבהן מוכנים להקריב את את המהירות הכללית – בכדי לשמר מערכת נכונה לאורך זמן.
    • כמובן שבניית טופולוגיה שטוחה של צוותי רכיב (Component) היא לא ערובה למצויינות הנדסית. המצוינות ההנדסית צריכה לנבוע מתרבות ומפעילויות נוספות של הארגון בכדי לבנות ולשמר אותה.
  • בעייה נפוצה של המודל הזה היא התחפרות ב Silos טכנולוגיים: צוותים שמתקשים לעבוד זה עם זה, ושבנו ארכיטקטורה מקומית של השירותים שלהם – שלא ידידותית לשאר הסביבה, כי אין להם מספיק חיבור לתמונה הגדולה, ולהיכן הארגון מתקדם. דרושה הרבה תקשורת יזומה כדי לחדור לכל הצוותים וליישר אותם לכיוון שאליו הארכיטקטורה והביזנס מתקדמים – וכדי לעזור שכולם יתקדמו ביחד לאותו הכיוון.
  • קושי גדול נוסף הוא חוסר גמישות ארגונים לאזן בין משאבים. נניח שבשנה מסוימת הארגון זקוק להרבה יותר פיתוח באזורים A ו B והרבה פחות באזורים C ו D. תהליך הגיוס של צוותים C ו D לעבודה באזורים A ו B – אינו פשוט מכיוון שלצוותם יש זהות חזקה מאוד עם הרכיב הטכנולוגי עליו הם עובדים. הצוותים האחראיים על A ו B יגלו כנראה התנגדות וביקורת למפתחים נוספים שמגיעים ו״משנים להם את הקוד, מבלי שיהיו כאן שנה הבאה להתמודד עם התוצאות ארוכות הטווח של השינויים האלו״.

מודל ה Stream-Aligned Teams

מודל זה חדש יחסית (הוצג בספר Team Topologies: Organizing Business and Technology Teams for Fast Flow, שפורסם ב 2019) אך זוכה לאזכורים רבים. המודל הוא בעצם שילוב בין המודל ספוטיפי למודל ה Product/Platform Teams. האם זהו הפתרון האידאלי? שילוב בין שתי הגישות?

לתחושתי, הספר הנ״ל מציג תאוריה מהונדסת להפליא שמסתדרת יפה מאוד עם עצמה, מקשרת כמה וכמה רעיונות משפיעים בעולם התוכנה (Conway’s Law (ביטוי המופיע בספר 110 פעמים), הספר ״Accelerate״, Cognitive Load Model, מצטטים את דניאל פינק, מיקל ניגארד – ועוד כמה של כוכבים) תוך כדי שהכל ״מתקמפל״ ברמת הסיפור – ונשמע נהדר. בפועל הוא קצת יותר דומה למודל של סופטיפי, גם בדגש שלו על Velocity, וגם בזה שיש לו המון PR בצד אחד – וחורים ושאלות פתוחות גדולות, מצד שני. כמו Black Adam (דוגמה עדכנית ליום כתיבת הפוסט) – בהחלט מדובר ברב-מכר, עם ספקות להיותו קלאסיקה מאריכת ימים. זה טוב מאוד ל Team Topologies Academy (חברת יעוץ) – וספק עד כמה משרת באמת את התעשיה.

  • המודל מציג ארבע סוגים של צוותים בארגון:
    • Stream Aligned Team (להלן צוות רצף-עבודה; בספר מציינים במפורש שנמנעו מלקרוא להם Product Team או Feature Team) – צוות המיושר (Aligned) לשטף מתמשך של עבודה: פיצ׳ר (גדול), רצף של פיצ’רים בעלי אופי מסוים, או סוג משתמש מסוים, כאשר הדגש הוא על רצף מתמשך של עבודה, שלא ידרוש פירוק/הרכבה כאשר הצרכים והעדיפויות של הארגון משתנים. הצוותים האלו (להלן צוותי רצף-עבודה) מהווים את עיקר הצוותים בארגון, והם אוטונומיים ו Cross-Functional, כמו Squads. הם גם בעלי אחריות ארוכת טווח על מיקרו-שירותים שהם מנהלים (מלבד כמה יוצאי דופן). שאר סוגי הצוותים מכוונים לתמוך ולסייע לצוותי רצף-העבודה לעבוד מהר ויעיל יותר.
    • Enabling Team (להלן צוותים מאפשרים) – צוותים המרכזים ידע בתחום מסוים, ומנגישים אותו לצוותי רצף-העבודה, ע״פ הצרכים של צוותים אלו. למשל: צוות שמתמחה ב SQL ובסיסי-נתונים, ויכול לספק לצוותי רצף-העבודה את ההדרכה והעזרה שהם צריכים, תוך כדי שהוא מפתח את הידע בצוות (כדי שצוות רצף העבודה יהיה אוטונומי יותר) – ולא מקבל ממנו משימות ספציפיות. במקרים בהם נדרש מחקר עמוק, פתרון בעיה מסובכת במיוחד בתחום – הצוות המאפשר ייקח את העבודה על עצמו. בקיצור: חכה ולא דגים, מלבד דגים שמנים במיוחד.
    • Complicated Subsystem Teams (להלן: צוותי עומק) – אלו בעצם סוג של צוותי פלטפורמה (ע״פ המודל הקודם) אך הם בודדים ומוגבלים לנושאים המורכבים ביותר, שלא סביר שצוותי רצף-עבודה יכולים לקחת. הדוגמאות כוללות בעיקר צוותי אלגוריתמים / ML / אנליזה עמוקה (מזכירים שאם יש דוקטורים בחברה, הם כנראה יהיו בצוות כזה). מטרת הצוותים היא להוריד עומס קוגניטיבי מצוותי רצף-העבודה, כך שיוכלו להתמקד במשימה העיקרית שלהם. נחזור לנושא זה בהמשך.
      • על פניו, הורדת עומס קוגניטיבי זה לא רק אלגוריתמים, אלא גם לוגיקה עסקית מורכבת – ולעתים יש הרבה כזו בארגון. לא הצלחתי להתחבר שסוג הצוות הזה נדרש רק במקרים ספורים וקיצוניים כל-כך.
    • Platform Teams (להלן צוותי פלטפורמה) – על אף השם הזהה, אין הכוונה לצוותי פלטפורמה בנוסח מודל ה Product/Platform Teams בכך שאלו פחות צוותי תוכנה ויותר צוותי Infrastructure/Operations. למשל: צוותי Cloud Operations/Security/Data Engineering/Devex וכו׳. צוותי הפלטפורמה במודל הם הצוותים שמספקים את הפלטפורמה למערכת, ולא מפתחים את המערכת עצמה (עליה אמונים צוותי רצף-עבודה). מטרתם כמובן היא לשרת את צוותי רצף העבודה, לייעל את עבודתם, ולהוריד מהם עומס קוגניטיבי.
  • רעיונות מרכזיים במודל הם:
    • יישום ה Inverse Conway manoeuvre – קרי, יש לארגן את הצוותים ע״פ הארכיטקטורה הרצויה, ולא לצפות שהצוותים יתאימו את עצמם לארכיטקטורה במבנה ארגוני אקראי. כל רכיב / תת-מערכת בארכיטקטורה – צריכה להתמפות לצוות רצף-עבודה שאחראי עליה, ורכיבים קרובים ברמת הארכיטקטורה צריכים להיות מנוהלים ע״י צוותים קרובים במבנה הארגוני.
    • צמצום ה Cognitive Load על צוותי-רצף העבודה, בכדי שיהיו יעילים. כלי אחד הוא הצוותים התומכים, כלי נוסף הוא מין סקר ששואלים כל פרק זמן את צוותי רצף-העבודה, וממנו מסיקים כיצד להשתפר. כלומר: מנגנון קבוע על מדידה (לא מדויקת, אבל בכל זאת) של העומס הקוגניטיבי (=> יעילות) של צוותי רצף-העבודה, ושיפור מתמיד שלו.
    • צמצום התקשורת בין צוותים (״Fast Flow requires restricting communication between teams״). ״תקשורת היא לא תמיד דבר טוב״ והשאיפה היא להחליף Collaboration (תקשורת עמוקה) בתיעוד, Self-Serve APIs ונוהלים מסודרים איך לפנות לצוות בבקשות. בספר ממש ממליצים להימנע מ Open Space כי לא כולם צריכים לדבר עם כולם, וה Open Space מעודד תקשורת אקראית ולא דרך המנגנונים היעילים יותר. כנ״ל לגבי כלי כמו Slack.

כפי שאמרתי, המודל דומה למודל של ספוטיפי, עם כמה צעדים לכיוון של מודל ה Product/Platform Teams. יש במודל צוותים שאחראים על נושאים מורכבים / עומק / ראייה לטווח-ארוך, אבל ה Guideline הוא שכל הצוותים שאינם צוותי רצף-עבודה ירכיבו ביחד כ 10% מהארגון. הרבה מהשיח במודל הוא על Velocity ברמת הצוות – מה שבאופן טבעי מטה את הארגון לחשיבה קצרת טווח.

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

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

מחשבות

לאחר הקדמה ארוכה, וסקירה של כמה מודלים פופולאריים, אנסה לשתף בכמה מחשבות:

  • בטופולוגיה של צוותי-תוכנה יש כמה Tradeoffs שהם כמו חוקי-טבע, שאין דרך להימנע מהם:
    • חשיבה לטווח קצר (צוותים ממוקדי Delivery) מול חשיבה לטווח ארוך (צוותים ממוקדי רכיבים טכניים – והאחריות עליהם לזמן ארוך).
      • בווריאציה: אוטונומיה מול ריכוזיות.
      • בווריאציה נוספת: יישור למוצר (Product-Alignment) מול יישור למודל המערכת (Architecture-Alignment). כמובן שטוב שהארכיטקטורה תתמפה בצורה ישירה עד כמה שניתן לצרכי המוצר – אך לא תמיד ניתן להשיג זאת.
      • חשוב לי לציין ש Delivery הוא מרכיב חשוב לא רק לביזנס, אלא גם לארכיטקטורה: הצורך לספק משהו מוחשי וספציפי בטווח נראה לעין עוזר לצוותים לבנות ארכיטקטורה מעשית יותר. ברגע שמצמצמים את לחץ ה Delivery מתחת לרף מסוים – הארכיטקטורה והיכולת לטפל בטווח הארוך דווקא יורדים, ולא ממשיכים להעלות.
    • התמחות ועומק מול גמישות להזיז את הכח בין נושאים – ע״פ צורכי הארגון המשתנים.
      • משליך על: האם להשקיע הרבה בתשתיות / כלים / תיעוד / הדרכה – כדי לאפשר למהנדסים לזוז מאזור לאזור? זה עוד Tradeoff בין השקעה בתשתית, מול גמישות.
      • וריאציה: האם זה נכון שיהיו בארגון 30 סוגי מהנדסים (המשקפים עומק והתמחויות שונות, אפילו שכולם הם מהנדסי ג׳אווה) או שהארגון חייב שלא יהיו יותר מ 10 סוגי מהנדסים, והוא מוכן להשקיע רבות בכדי לאפשר זאת?
  • נקודת האופטימום, תשתנה כמובן בין ארגון לארגון, ובתקופות או שלבים שונים של כל ארגון.
    • ארגון שמפתח תריסר אפליקציות מובייל פשוטות ובלתי תלויות – מוטב שיאמץ מודל הדומה למודל של ספוטיפי. אפילו: אם הוא קרוב לשם, כדאי שיתאמץ ויפרק את המערכת שלו למבנה כזה, כדי שיוכל להיות שם.
    • ארגון שמפתח מערכת מורכבת, עם הרבה תלויות פנימיות – מוטב שיאמץ מודל יותר קרוב למודל ה Product/Platform Teams או אפילו מודל ה Component Teams. כמובן שלו היה יכול לחלק את המערכת / לעצב ארכיטקטורה ללא תלויות פנימיות רבות – עדיף היה, אבל לא תמיד זה אפשרי.
    • הניסיון להגדיר מודל יחיד לכל הארגונים, לאורך כל ימי חייהם – הוא שטותי כמובן. אפילו אם יש גמישויות מסוימות במודל (נניח: צורת התקשורת).
  • חשוב שמובילי הארגון יבינו את ה Tradeoffs האלו לעומקם, ויבינו שאין ״מודל קסם״ טוב יותר: השמיכות שבמְצַאי הן כולן קצרות, וההחלטה הנדרשת היא האם להשאיר את הרגליים חשופות, או את הראש – איפה ועד כמה.
    • ארגון בוודאי יכול לומר לעצמו (ברגע של כנות) האם הוא מפתח מערכת מורכבת ואינטגרטיבית, או סדרה של תתי מערכות פשוטות. האם יש לו יכולת לחזות / לתכנן לטווח הארוך היכן ידרשו המהנדסים, או שהוא חייב להיות גמיש ולהיות מסוגל להזיז תדיר מהנדסים ממקום למקום (על אף המחיר הגבוה של זה).
      כמובן שהתשובה הפופולארית היא ״המערכת שלנו היא סופר מורכבת ומאתגרת, והשוק דינאמי – אז אנחנו זקוקים למירב המומחיות ולמקסימום גמישות״, אבל זה לא תמיד המצב, ובחירה בנקודה הזו במודל ה Tradeoffs אומר הרבה תקורה, תקשורת, וגופים מרכזיים בארגון => פחות מהירות.
    • ארגונים משתנים, וכמובן שכל פרק זמן נכון להעריך מחדש היכן נמצא הארגון, ומה הטופולוגיה הארגונית שנכונה לו בשלב זה. שווה להזכיר שטופולוגיה של צוותים היא יותר מקום-מגורים מגרביים – להחליף אותה זה יקר מאוד, ועלול ליצר הרבה After shocks (בניגוד לגרביים).
    • ל Coupling במערכת יש מחיר אסטרטגי, כלומר: ברמה הגבוה ביותר של הארגון. חשוב מאוד לנסות ולפרק את המערכת ואת הארגון, לתתי-מערכות ותתי-ארגונים יותר עצמאיים, גם במחיר מסוים.
      • למשל: כשעבדתי בחברת נייס, שכפלו את חטיבת ההקלטות לשתי חטיבות מקבילות בכדי לתת להן יותר עצמאות: חטיבת הקלטות הקול, וחטיבת הקלטות הוידאו. הקוד שוכפל ומספר המהנדסים כמעט הוכפל – אך בדיעבד נראה שזו הייתה החלטה נכונה.
      • בחברת SAP רצו ליצר הפרדה משמעותית יותר בין ה Core לבין ה UI ברמת ה Backend. הם כל הזמן התערבבו – והמערכת מאוד הסתבכה. החליטו להעביר את כל פיתוח ה UI ל Stack Technology אחר (במקרה: ג׳אווה) בכדי שהחיבור בין הרכיבים יהיה רק דרך API מוגדרים היטב, ולא יאפשר (או לפחות יקשה) על Tight coupling. כמובן שנדרשה כתיבה מחדש של כל ה UI Backend, והעברת מאות (אולי אלפי) מהנדסים ל Stack חדש. חשבו איזו השקעה זו.
  • כמובן שניתן לשחק בפרמטרים וב Tradeoffs השונים:
    • אפשר בהחלט להחליט שחלק מסוים מהארגון / מוצר (אזור) עובד במודל א׳, וחלק אחר במודל ב׳. זה מוסיף בלבול ומורכבות ניהול – אבל היא עשויה להיות שווה זאת, בכדי להקל על היומיום של הצוותים.
  • נושא טופולוגית הצוותים בארגון הוא נושא מורכב, שקל להרים בו ידיים, ולחפש עזרה. עזרה כזו תמיד זמינה (יועצים, מנהלים מקבילים בחברות אחרות שישמחו לעזור) – אך כנראה שהכי טוב שתעשו את זה בעצמכם, מתוך מחויבות עמוקה (מה לעשות: לכם תמיד יהיה אכפת יותר) ומתוך הבנה עמוקה של האפשרויות והקיים. זה לפחות הניסיון שלי.

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

איך לנהל דיונים טכניים (Software Design)?

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

עד כמה הדיונים האלו יעילים?

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

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

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

העקרונות של דיון טכני מוצלח

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

הכנה

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

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

ההכנה אמורה להשתלם. קרי: ישבתי שעתיים בכדי להכין חומר לדיון באורך שעה בו יש ארבעה משתתפים והדיון הסתיים – הוא מוצלח הרבה יותר מ ״נפגשנו ארבעתנו לשעה – אבל העניין לא נסגר*״ ואז ״קבענו לעוד שעה וכמעט סגרנו״ ואז ״אני ומשה נפגשנו לעוד חצי שעה לסגור פרטים אחרונים״.
במספרים: 6 = 1*2+4*1 < 4*2 + 2*2 = 10.

* קול פאסיבי. זה ״העניין״ שלא נסגר – לא שזה אנחנו, או משהו…

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

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

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

מהי ההכנה?

  • הגעה עם העובדות הקריטיות לדיון, או יכולת מלאה לענות עליהן (דוגמה שלילית: ״האא… חשבתי שאחד מכם ידע <שאלה טכנית>. בואו נחפש אולי עכשיו את התשובה ביחד״) – חשוב להבין מראש האם יש שאלות קריטיות לדיון, ודאו מראש שיש לכם תשובות ו/או מי שמגיע לדיון ידע לספק בשלמות את העובדות הנדרשות. קשה לי לספור כמה דיונים ראיתי שנמרחו סתם כי פשוט היה חסר ידע לנהל דיון יעיל. לא פחות חבל: הרבה פעמים יש נטייה לנסות להמשיך למרות שברור שהדיון לא עומד להתקדם בצורה סבירה. הרבה דיונים עדיף לחתוך באמצע – מאשר להמשיך סתם. תהיו רציניים בבקשה, ואל תמשיכו דיון רק כי כמה אנשים התכנסו כבר ביחד.
  • ודאו מראש ששיבוץ האנשים מאפשר להגיע ל “Delivery״ (תוצאה מוצלחת של הדיון).
    דוגמה שלילית: ״אוי… שרון מה זה הייתה תורמת לנו לדיון. חבל שלא הזמנו אותה, אך היא עכשיו בפגישה אחרת״.
    הבינו מי באמת צריך להיות בדיון וודאו שהוא שם. ברוב הארגונים אנשים לא זמינים מהרגע להרגע – ואי הזמנה של אדם יכולה לעכב את הדיון בימים => הארכת ה Lead Time להחלטה.
    • שאלה קצרה ב Slack ״היי… אנחנו רוצים להבין <בעיה טכנית> – אתה יכול לכסות את הנושא, או שאנחנו זקוקים למישהו נוסף?״ – יכולה להכריע בין דיון יעיל לבזבוז זמן.
    • נסו גם לצמצם אנשים לא-רלוונטיים. חבל לעכב דיון רק כי אדם לא-רלוונטי לא מסוגל להגיע. היום בעידן הזום קל הקליט דיונים – וכך לאפשר לאנשים להקשיב לדיון מבלי להופיע.
  • תעדו ופשטו את תיאור הבעיה – בכדי לאפשר דיון יעיל. (דוגמה שלילית: ״לא… בפעם הרביעית: X קורה לפני Y כי ….״). במיוחד כאשר הנושא הוא מורכב / רב בפרטים – הכינו תרשים ו/או רשימת נקודות שתעזור לכולם להתכנס מסביב לנושא. קשה לי להסביר כמה חומר כתוב, ושעבר איטרציה או שתיים של פישוט והבהרה – יכולים לקצר את הדיון.
    • חשבו על החומר שאתם מכינים כמפת-ניווט לדיון. בניית מסלול לדיון כדי שאנשים לא יצטרכו להחזיק יותר מדי פרטים בראש. מוביל הדיון הוא מדריך פעולת ניווט, ובלי מפה טובה סביר הדיון יסתיים בהתברברות. הכנת מפה טובה לדיון הוא מיומנות שלוקח קצת זמן (אבל מאוד משתלם) לפתח.
    • ליצור תרשים שמסביר Flow מורכב – הוא דבר שלוקח זמן. הקדישו פעם אחת את הזמן הזה לפני הדיון, במקום לנסות לייצר אותו חמש פעמים במהלך הדיון – וכך למרוח את הדיון.
    • ראוי שחומר כתוב וברור – יהיה ציפייה מקדימה לדיון טכני.
      • מדי פעם יהיו כאלו שיכינו חומר ארוך מדי / מתיש / מפורט מדי. עזרו להם לקצר. זה לא תמיד קל.
    • הבינו מי המשתתפים בדיון. הרבה פעמים מגיעים לדיון אנשים שלא בקיאים בנושא, וחשוב להכין להם רקע קצר שיכניס אותם לדיון ביעילות: מה הבעיה, מה קרה עד עכשיו? מה אנחנו יודעים? על מה יש הסכמה, ועל מה יש אי-הסכמה?
    • הכנת חומר לדיון בפעם הראשונה עלולה להיות פעולה לא מתגמלת. זה קשה, אורך זמן, ואולי בסוף לא יהיה דיון מוצלח. אני אנסה להבטיח לכם שזה משתפר בכל הממדים עם הזמן. 3-5 דיונים שהכנתם להם חומר – וזה יתחיל להראות אחרת: קל יותר, ומועיל יותר.
  • עומק הדיון נגזר מעומק החומר שהוכן. כמו ב Designs, סכנה היא שמי שמכין את החומר / מתווה את הדיון – ידלג על נקודות מפתח, ואז הדיון ידלג עליהן (כי כולם ״שבויים״ ברצף שהוגדר). כמובן שאנחנו מצפים ממשתתפים לאתגר ולשים לב לחסר – אך בנושאים מורכבים לא פעם הכנה חסרה נגמרת בדיון חסר. אין לי פתרון לזה, מלבד להקפיד וללמד את מי שמכין את החומר שיעשה מעבר יסודי ויעיל על נקודות הממשק של הבעיה – בכדי להקטין את הסיכון לפספוסים.

התנהלות הדיון

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

  • התייחסו לדיון כ Delivery. הוא כזה, אם תחליטו ותצרו תרבות מתאימה. תרבות דיון יעיל – תשרת אתכם בהחלטות מהירות יותר, וסביבת עבודה שאנשים רציניים – יעריכו יותר.
    • חשוב שמי שמנהל את הדיון יהיה במנטליות של חתירה לסגירת הדיון. זו האחריות שלו לוודא שהדיון מתקדם בצורה יעילה. לא תמיד דיון יסתיים בזמן שתוכנן – וזה לגיטימי. לפעמים קשה להעריך מראש את המורכבות של הדיון. מצד שני – דיונים שסתם נמרחו – הם משהו שלא צריך לקבל. חבל על הזמן והכוחות של כולם.
    • מומלץ מאוד להתחיל את הדיון בהצהרה מה מטרת הדיון. ״אנחנו עושים Barinstorming ומחפשים כיוונים אפשריים לפתרון בעיה X״ או ״אנחנו רוצים לקבל החלטה מה הפתרון לבעיה Y – בהתאם לאלטרנטיבות שנמצאו״ – הם שני דיונים בעלי אופי שונה, וחשוב שכולם יבינו איזה דיון מתנהל.
  • המנעו מזליגה לדיונים אחרים. ״הא? הנושא מאוד קרוב גם לדיון ג׳? יופי. את דיון ג׳ אפשר לנהל במקום וזמן אחר – עכשיו אנחנו בדיון א״.
    • עוד ואריאציה בעייתית היא אנשים שמעלים הגיגים פילוספיים ולא משמעותיים לדיון ״אם היה לנו …, מה זה היה אומר?״ או ״חשבתם על …? (משהו תאורטי לגמרי)״. חשוב לזהות את ההתברברויות האלו – ולעצור אותן מוקדם. לעצור מצבים שבו אנשים מבדרים (מלשון הִתְבַּדְּרוּת) את הדיון במקום לקדם ולהניע את הדיון לכיוון של Delivery.
    • אם מישהו מתנהל בצורה לא יעילה, קרי: חופר יותר מדי – הציפיה שמי שמנהל את הדיון יחתוך אותו. צרו תרבות דיון שמאפשרת ומחייבת לעשות את זה. ״מה? לא דילברת את ההחלטה הטכנולוגית כי שרית לא הפסיקה לחפור? זו לא סיבה מספיק טובה. פעם הבאה – בבקשה עצור את החפירה. האחריות ל Delivery של ההחלטה – היא עליך״.
    • ניהול זמן. לא סביר שעוד 10 דקות נגמר הדיון, ולא התחלנו להתכנס להחלטה. זה עוד היבט במנטליות של דיון = Delivery.
  • דיון תמיד מתחיל ביצירת בסיס משותף. זוכרים את שלב ההכנה? מישהו הכין רקע להכניס את כולם לסדר העניינים. מישהו פירט ותאיר בצורה ברורה ואחידה את הבעיה עבור הדיון: אחידות בהבנת / הגדרת הבעיה – מסייעים מאוד לדיון יעיל. עכשיו זה הזמן ״לצרוך״ את ההכנה הזו, ולהביא את המשתתפים לבסיס משותף שיאפשר דיון יעיל.
    • דרך טובה היא פשוט לקבוע ש 15 הדקות הראשונות של הדיון (או כל זמן אחר שיתאים) משמשות לקריאה פרטנית של החומר שהוכן. כל אחד קורא את המסמך (בשקט, לעצמו), מוסיף הערות – ואז עוברים עליהן לפני / תוך כדי הדיון. הפרקטיקה הזו עובדת לנו בנקסט מצוין – ואני בהחלט ממליץ עליה.
    • כאשר הנושא הוא טעון / במחלוקת – חשוב להגיע להסכמה משותפת של הבעיה. ״צוות א׳ לא אוהב את פתרון הראשון כי <סיבה מנקודת מבט של צד א׳>, וצוות ב׳ לא אוהב את הפתרון השני כי הוא מוטרד מה <משהו>״. עצם ההסכמה של שני הצדדים על מה מדאיג כל צד – מאוד עוזרת לנהל דיון יעיל. אל תפספסו את זה. זכרו לנהל את הדיון כדרך למצוא את הפתרון הנכון ביותר בארגון – ולא כמאבק כוחות.
  • המנעו מ Design באמצעות דיון. לא פעם, תוך כדי דיון מגלים בעיה חדשה שלא חשבו עליה. בעיה שדורשת חידוד, יצירת חלופות (alternatives), ניתוח החלופות – והערכה איזו טובה יותר. מין ״מיני תהליך דזיין״.
    • דיון בקבוצה הוא דרך גרועה לביצוע דזיין. המנעו מהטעות הזו, בחרו אדם או שניים (בעלי אחריות) שיבצעו את התהליך: הגדרת חלופות, ניתוח שלהן וכו׳, יכתבו את הדברים בצורה ברורה לדיון – וכך תוכלו לקחת החלטה טובה – בדיון המשך.
      • ברגע שאתם מזהים שבעצם מתנהל דזיין לא מתוכנן – עצרו זאת. זה יהיה דזיין חפוז ולא מדויק. לא מתקנים פנצ`ר תוך כדי נסיעה.

תרבות דיון

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

  • צרו ושָׁמְרוּ על Psychological Safety – אף אחד לא אמור להיות מובך / מושפל / מותקף בשל דיון או דברים שנאמרו בו. אם דיונים מגיעים למחוזות הפגיעה, אזי אנשים יעסקו בהתגוננות – ולא בעצם הדיון עצמו.
  • אגרסיביות ובריונות קיימים גם אצל חְנָנוֹת בחברות הייטק. אי אפשר להכחיד אותם, אך הדפו אותם אחורה כאשר הם מופיעים. לא פעם בדיונים בין צוותים, הטיעון מדוע לפתח משהו בצוות אחד ולא אחר הוא ״אז לנו זה ייקח יותר זמן מכם״ או ״אנחנו פשוט נעביר לכם את כל הבאגים שקשורים לנושא, סבבה״. לא פעם, יש שמץ של אמת בטיעונים האלו – אבל חשוב לעשות דיון ענייני ולבחון את הערך לחברה, ולא לפעול לפי אינטרסים מקומיים.
  • צרו סביבה שמאפשרת לכולם לדבר, גם אם הם ״זוטרים״. לא פעם, טוב שמוביל הדיון ישאל ויערב את הביישנים – גם אם הם לא יוזמים. ״משה – מה אתה חושב על זה? זה פתרון טוב מבחינתך?״. מצד שני – שימו לב שהדיון לא מתבדר רק כי רצינו שכולם ידברו.

סגירת הדיון

אם אנחנו ממשילים דיון ל Delivery, אנחנו לא רוצים תרבות שבה פיצ׳ר נגמר כשהמפתח לא מודע לעוד קוד שצריך להכתב. סיום – משמע קוד בדוק, ב master, שרץ בפרודקשיין.
באופן דומה, דיון לא מסתיים כאשר נגמר הזמן בפגישה. דיון מסתיים נכון כאשר יש סיכום ברור של הדברים – שאנשים מבינים, כאשר יש Action Aitems ודיוני משנה – אם נדרשים.

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

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

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

סיכום

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

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

כמה דגשים אחרונים:

  • החלטות הנדסיות הן Delivery משמעותי. חשוב לעשות דיונים היטב ולהיות גאים בעשייה – ולא לראות בהם ״תקורה״ שצריך לקצץ ולדלל. כל דיון שני על פריון בחברות תוכנה נגמר ב״יותר מדי פגישות״. אל תקצצו את הפגישות החשובות – דאגו שיהיו יעילות יותר! צרו תרבות שמכירה בערך של דיון טכני טוב. אמירות כמו: ״כל הכבוד שמוליק על הדיון, הוא היה מוצלח! (כי…)״ או ״סגרנו בספרינט ארבעה דיונים חשובים: א,ב,ג,ד״ – צריכות להיות טבעיות, ולא מוזרות.
  • הכנה היא חלק חשוב, שהרבה פעמים מתפספס. כעומק ההכנה – עומק הדיון. האם אתם מוכנים שאצלכם יתנהלו בעיקר דיונים שטחיים?
  • סגירה היא לא מובנת מאליה – וגם שם אנחנו נוטים לפספס הרבה: לא לזכור מה בדיוק היה הסיכום מלפני שבוע, ולעשות ״משהו״ – כי הרי כבר דנו בזה. ״לעשות את מה שעשינו ב 48״.
  • נסו לצמצם Lead Time של דיונים טכניים. אם תצליחו באופן משמעותי – כל הארגון יודה לכם.

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

הפרדת רשויות: מדוע להשקיע ב DTOs ו Entities?

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

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

עקרון תכנותיקה

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

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

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

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

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

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

מדוע לבצע הפרדת רשויות?

לפעמים יש לנו אובייקט מרכזי במערכת. למשל: Person. אנחנו משתמשים בו לשלושה שימושים עיקריים:

  • ב APIs או Events – כדי להעביר מידע אודות Person למערכות אחרות.
    • לפעמים ע״י serialization של המחלקה ל JSON
    • לפעמים אנחנו משתמשים במחלקה על מנת להפיק (generate) ייצוג ב IDL (שפת ביניים)
  • ב Business Logic – בכדי להעביר מידע אודות Person בין חלקים שונים של ה business logic.
  • בשכבת העבודה של בסיס הנתונים – בכדי לשמות מידע של Person בבסיס הנתונים לאורך זמן.
    • לפעמים ע״י serialization של המחלקה ל JSON (למשל: Document databases, או semi-document DB כמו mySQL או Postgres).
    • לפעמים דרך ORMs כמו Active Records או Hibernate (שיצרו סכמת בסיס נתונים בהתבסס על מבנה האובייקט).

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

  • האובייקטים, הרבה פעמים, יהיו זהים ביום היצירה שלהם? אז למה לשכפל קוד?
  • למה לתרגם בין אובייקטים זהים (נניח: ברגע שאוביקט ב Business Logic צריך לעזוב את המערכת כחלק מ Event / קריאת API)

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

Entity Object
(e.g. PersonEntity)
Model
(e.g. Person,
no suffix)
Data Transfer Object (e.g PersonDTO)
שמות מקובלים אחריםPersonDBEntity (clarify the direct relation to DB).PersonModel, PersonDomain, PersonBL (= Business Logic)None I know of.
סיבה להשתנותהוספת מידע שנדרש לצורך שמירה בלבד: ID, זמן / תאריך שמירה או שינוי. שדה נוסף שיקל על פעולת אינדוקס.
אולי רוצים לפצל את שמירת הנתונים ל-2 טבלאות או פורמט אחר לצורך שיפור ביצועים.
העשרת ה BL בשדות / תכונות נוספות שפנימיות למערכת.
שינוי שמות שדות בעקבות תובנות ואפשרות לתאר אותם בצורה נכונה יותר, ייצוג נתונים באופן שקל יותר למערכת לעבוד איתו. למשל LocalDate ולא מחרוזת של תאריך, Money ולא Integer.
התאמת מבנה נתונים ללקוח, נניח אפליקציות FE שייהנו ממבנים ידידותיים יותר ל JS.הוספת שדות מחושבים שלא נמצאים במודל, אך יקלו על הלקוחות (BE או FE).
כיצד משתנה בצורה תואמת-לאחור
(למשל הוספת שדה חדש שניתן לקבוע לו default value)
תאימות לאחור חשובה כי ייתכן ונרצה לקרוא מחר מידע שנשמר לפני שנה-שנתיים. ללא תאימות לאחור – לא נוכל לאחזר מידע ישן.גמישות רבה בשינויים, כי אובייקט המודל לא נשמר ולכן כל אתחול של המערכת (deploy) יכול לעבוד עם גרסה חדשה.תאימות לאחור חשובה כי ישנם לקוחות שימשיכו לצפות ולשדר את המבנה בגרסאות קודמות שלו – ואין לנו שליטה עליהם (אם הלקוחות הם שירותים שלנו – עדיין יש צורך בשינוי הדרגתי).
כיצד משתנה בצורה שאינה תואמת-לאחוראפשרות א: תיקון כל הנתונים בבסיס הנתונים (migration) כך שיתאים ל entity החדש. זה שינוי שיכול להיות קשה, יקר, ומועד-לטעויות יקרות. כיף!אפשרות ב: ליצור גרסאות של ייצוג בבסיס הנתונים, ולהחזיק קוד שמזהה את הגרסה – ויותר לטפל בכל גרסה באופן שונה.אפשרי ברמת הקוד בלבד (refactoring). כל עוד הקוד מתקמפל, והבדיקות עוברות – כנראה מאוד שאנחנו בסדר.לרוב נאלץ לפתור גרסה חדשה של ה API / event (למשל V2) בו יש את המבנה החדש, ולהעביר לקוחות לגרסה החדשה. עבור לקוחות שאין לנו שליטה עליהם – זה יכול להיות תהליך של חודשים הכולל פשרות מסוימות.
הערותלפעמים אנשים מבלבלים בין Entity ו DAO:
Entity – ה object שחוזר.
DAO – הממשק שממנו שולפים את ה Entity.
לא פעם מכיל מתודות / פונקציות – ולא רק נתונים.
מומלץ מאוד שאלו יהיו רק מתודות המקלות על גישה / פענוח הנתונים (מה שנקרא access logic), ולא Business Logic של ממש.
לא פעם מקובל להגדיר Coarse-grained DTO (אובייקט ״גדול״ יותר) – על מנת לצמצם את מספר הקריאות ברשת.
השוואה בין ההבדלים החשובים בין Entity, Model, ו DTO.

דוגמאת קוד

המודל:

@JsonIgnoreType
public class Person {
  @JsonIgnore public final String name;
  @JsonIgnore public final LocalDate birthDate;

  private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(PersonDTO.birthDateFormat);

  public Person(String name, LocalDate birthDate) {
    this.name = name;
    this.birthDate = birthDate;
  }

  public PersonDTO toDTO() {
    return new PersonDTO(name, birthDate.format(formatter));
  }

  static public Person fromDTO(PersonDTO dto) {
    return new Person(dto.name, LocalDate.parse(dto.birthDate, formatter));
  }
}

הערות:

  • לא השתמשתי ב record, בהנחה שזה מבנה פחות מוכר, אז למה לבלבל.
    • שימוש ב public members עבור Entities – הוא דבר שעשיתי בתחילת שנות האלפיים, ותמיד האמנתי שהוא נכון (למרות מעט ביקורת מצד תאורטיקני ג׳אווה שתמיד רצו getters).
  • שורות 1, 3, ו4: JsonIgnoreType@ ו JsonIgnore@ הם ביטחונות של ספריית Jackson (ל seralize/deseralize JSON) שהמחלקה לא תסורייל (seralized) ל JSON ושהמידע שלה לא יישמר/ישלח איכשהו. אנשים נוטים לשכוח שיש DTO ו/או Entity – וחשוב להגן בפני הטעויות הללו. אם התחלנו לשמור את המודל לבסיס הנתונים – התיקון עלול להיות יקר.
    • האם שניהם נחוצים? (ולא מספיק אחד) – אני לא בטוח, אבל Better be safe than sorry.
    • לא כולם משתמשים ב Jackson כמובן – עליכם למצוא את הפתרונות שלכם להגן על המודל שלא ייצא מגבולות ה business Logic ולא יישמר באופן שיחסום אתכם לשינויים עתידיים.
    • האם יש משהו לא-אלגנטי שדווקא המחלקה שאמורה להיות ״הנקיה ביותר״ צריכה להשתמש בתלות לספריית ה serialization ולהצהיר – שהיא ״לא במשחק״? בהחלט לא אלגנטי – אם תמצאו פרונות אלגנטיים יותר אך מעשיים – לכו עליהם.
  • שורות 13 ו 17: אנו רוצים פונקציות עזר פשוטות בכדי להמיר בין מודל ו DTO.
    • לרוב קוד ה DTO יאוכסן בספריה נפרדת, כחלק מה API של המיקרו-שירות / המערכת – ולכן ל DTO לא תהיה גישה ל Model (והגיוני שכך). קוד ההמרה חייב לשבת במודל.

ה (Data Transfer Object (DTO:

public class PersonDTO {
  public final String name;
  public final String birthDate;

  @JsonIgnore public static final String birthDateFormat = "dd/MM/yyyy";

  public PersonDTO(String name, String birthDate) {
    this.name = name;
    this.birthDate = birthDate;
  }
}

הערות:

  • שורה 5 – הפורמט שבו ה DTO שומר את התאריך כמחרוזת (נניח: פורמט שקל לצרוך מתוך JavaScript) הוא פרט מומחיות שלו, ולכן יושב על ה DTO ולא על מחלקת המודל.
    • בהנחה שאנו עובדים עם Jackson – לא נרצה שפרט זה יעבור על הרשת כחלק מהאובייקט – ולכן השימוש ב JsonIgnore@.

ה Entity:

class PersonEntity {
  public final String name;
  public final String birthDate;

  private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

  PersonEntity(String name, String birthDate) {
    this.name = name;
    this.birthDate = birthDate;
  }

  public Person toModel() {
    return new Person(name, LocalDate.parse(birthDate, formatter));
  }

  static public PersonEntity fromModel(Person model) {
    return new PersonEntity(model.name, model.birthDate.format(formatter));
  }

}

הערות:

  • שורות 12 ו 16 – ה Entity הוא זה שמכיר את המודל, כי נרצה שמי שיעשה את ההמרה הוא שכבת ה Data Access ולא ה business Logic. למשל: DAO או Repository המקבלים את המודל ושומרים אותו, או שולפים אובייקט מודל לפי שאילתה נתונה.
  • שורה 5 – הפורמט שבו אנחנו שומרים את התאריך (נניח: פורמט ידידותי ל DATE column בבסיס הנתונים) הוא מידע פרטי של ה Entity.
    • לא הוספתי JsonIgnore@ – כי זה שדה פרטי.

סיכום התלויות:

סיכום

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

שאלה גדולה היא מתי לעשות את זה?

  • לכל מחלקה במערכת?
  • לפעמים (חסר קריטריון: מתי כן ומתי לא?)
  • לעולם לא – חבל על 10 דקות עכשיו, נסתדר בעתיד?

ברור לי ששתי הקיצוניות הן לא נכונות. היו תקופות שפיתחתי ״J2EE״ וכתבנו Enity ו DTO ל 100% מהמחלקות, גם APIs שוליים שרק ביקשו מידע קטן, והיה להן צרכן יחיד – זה מיותר ומחליש את הבנת/חשיבות הצורך.

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

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

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

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

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

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

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

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

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

———

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

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

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

האתגר שלהם: מגוון רחב מאוד של אנשי תוכנה: FE, BE – קל להבין, אבל בגילדה שלהם יש גם אנשי Data Science / ML, Data Engineers, Embedded, ו Firmware. כולם כותבים קוד, אבל באמת צורות העבודה של המקצועות הללו היא שונה דייה, כך שלא קל למצוא ברמת הקוד דוגמאות הרלוונטיות לכולם.

האם דזיין הוא שונה? האם אפשר באמת להגדיר כללים זהים שיתאימו גם למפתחי FrontEnd, גם לאנשי Machine Learning, וגם לאנשי Firmware.

לקחתי על עצמי את האתגר – והאמת שהוא לא היה קשה.

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

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

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

כמה נקודות במצגת ששוות להתייחסות נוספת

למה אפשר לצפות מדזיין טוב?

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

איך נראה דזיין טוב?

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

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

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

דזיין הוא תהליך – ולא מסמך

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

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

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

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

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

מקווה שתמצאו פוסט זה שימוש!

בלוקצ׳יין – מעבר לבאזז

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

בפוסט:

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

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

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

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

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

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

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

א-ריכוזיות (Decentralization)

התכונה הכי משמעותית של פרוטוקולי הבלוקצ׳יין היא הא-ריכוזיות שבה => decentralization. נקודה ראשונה שנרצה להבהיר היא ההבדל המהותי בין התכונות: ״distributed״ ו ״decentralized״.

רגע של עברית: לרוע המזל, המונח העברי מְבֻזָּר כבר ״נתפס״ לתיאור המונח האנגלי distributed – מערכת שמורכבת מחלקים שונים במיקומים שונים. נותרנו, דוברי העברית, בלי מונח ראוי לתאר את המונח decentralized. אני אשתמש בפוסט במונח אֲ-רִכּוּזִי, שאינו נפוץ / מקובל (עדיין).
הייתי שמח לחזור לשנות ה-80, ולשנות את המינוחים ל: distributed=מפוצל, ו decentralized=מבוזר. אם אתם מכירים אמצעי יעיל וזול למסע בזמן – אנא כתבו לי בתגובות.

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

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

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

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

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

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

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

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

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

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

The one thing that’s missing, but that will soon be developed, is a reliable e-cash – a method whereby on the Internet you can transfer funds from A to B without A knowing B or B knowing A

Milton Friedman – 1999

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

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

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

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

הדרך – עוד ארוכה.

מבט טכני

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

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

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

התכונות הטכניות העיקריות של הבלוקצ׳ין הן:

  • Decentralized – א-ריכוזיות: כמו שתיארתי למעלה.
  • Distributed – מבוזרות, הנגזרת במידה רבה מתוך תכונת האי-הריכוזיות.
  • Permanent – מידע רק נוסף לבלו׳ציין, ולעולם לא נמחק / משתנה בו. אפשר לומר: Immutable ו write-only (דרישת ליבה של ספרי-חשבונות).
  • Permissionless – כל אחד יכול לגשת ולקרוא את כל המידע בבלוקצ׳׳ין. כל אחד יכול להוסיף לבלוקצ׳יין טרנזקציות (תחת עמידה בכללים מסוימים).
    • מוביל ל Transparent (שקיפות) – כל מה שקורה על הבלוקצ׳יין פתוח לכל החברים ברשת. דמיינו מערכת שכל המסמכים והפעולות של הבנקים / חברות-האשראי פתוחים לכל: לבקרה וביקורת של כל עיתונאי או גורם בעולם.
    • עם הזמן, עושים הבחנה בין בלוקצ׳יין שהם ״ציבוריים״ (ולכן: Permissionless) לבין כאלו שהם ״פרטיים״ (ולכן, אין להם את תכונת ה Permissionless ו/או Transparency).
  • Consistent – עקביות: על אף שגורמים שונים ולא מתואמים רושמים לבלוקצ׳יין – הרישום יהיה אחד ויוסכם על כולם. ייתכנו רגעים קצרים של חוסר עקביות – שיתוקנו בזמן קצר.
  • Global Scale – הבלוקצ׳יין תוכנן להיות מערכת גלובלית, באופן דומה לזה שהאינטרנט הוא מערכת גלובאלית. יש כיום כ 1000 בלוקצ׳יין גלובאלים אך ניתן להשתמש בבלוק׳ציין כמערכת פרטית / מקומית, ויש לא מעט ספקים שיעזרו לכם להקים ״Blockchain ארגוני״ (למשל: יבמ, AWS, Linux foundation, ועוד).

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

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

חלק מה Nodes ברשת יחזיקו את הבלוקצ׳יין (״בסיס הנתונים״) המלא: כל הבלוקים שאי פעם נוספו לבלוקצ׳יין. ה Nodes הללו נקראים “Full Nodes״ והם בעצם ה backbone של הרשת / מערכת הבלוקצ׳יין.

בלוקים נוספים יחזיקו חלק מה Blockchain (ההיסטוריה הקרובה), וגם הם (בנוסף ל full nodes) מסוגלים לאמת טרנזקציות – הם נקראים Lightweight nodes. אם Lightweight node רוצה להוסיף בלוק לבלוקצ׳יין (״ספר החשבונות״) הוא יעזר ב Full Node לצורך התהליך.

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

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

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

בנוסף ל nodes העיקריים ברשת הביטקוין שעתה ציינו, יש עוד שרתים המריצים פרוטוקולים תומכים: Mining Pools Protocols ו lightweight access protocols – שלא נעסוק בהם בפוסט.

תהליך הקונצנזוס

הבלוקצ׳יין, כפי שציינו, הוא write-only, ולכן הפעולה החשובה ביותר בו – היא פעולה של כתיבה. הכתיבה נעשית ע״י הוספת בלוקים חדשים לשרשרת וכל Node עם יכולות של Miner יכול לעשות זאת. האתגר הגדול הוא לוודא שאותו כורה אנונימי, שאנחנו לא סומכים עליו – יוסיף בלוק ע״פ כללי הפרוטוקול, בלי לשגות ובלי לרמות. בניגוד למערכות מבוזרות ״רגילות״ בהן כל ה nodes עובדים על בסיס אותו הקוד / מתוך אמון הדדי – הנחת היסוד של מערכת א-ריכוזית היא שכל node ברשת הוא פוטנציאלית עויין – וינסה לרמות.

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

ברשת יש אלפים רבים של nodes, שאפשר להניח שחלקם (אולי אפילו רבים מהם) היו מעוניינים לרמות. איך אנחנו בוחרים ב node שיכתוב את הבלוק הבא?

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

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

לפני שנעבור לתיאור תהליך הכרייה עצמו, אציין עוד מגבלות עקרוניות של מערכות הבלוקצ׳יין (כפי שהם כיום):

  • Not Scalable – למרות שבלוקצ׳יין תוכננה כרשת גלובאלית, ואין לה מגבלה טכנית על כמות החברים ברשת או כמות המידע שייכת, קצב כתיבת המידע הוא מוגבל:
    • לא ניתן לרשום בקצב מהיר יותר ממה ש miner node יחיד מסוגל לכתוב. ברשת ביטקוין זה בלוק של 1MB כל עשר דקות. בביטקוין הרשת יכולה להוסיף כ 7 טרנזקציות בשנייה. זה קצב מאוד נמוך יחסית למערכות אחרות (למשל: VISA יכולה לעבד 65K טרנזקציות בשנייה).
    • מרגע שהרשת הופכת לפופולארית, ויש תחרות עזה על ביצוע ה Mining – הכח החישובי הנדרש על מנת להשיג קונצנזוס – מרקיע שחקים.
    • יש מגוון של פיתוחים שאמורים לשפר את ה Scalability של הרשת: גם את אלגוריתם הקונזצנוס שידרוש פחות חישוביות (סולנה – וגם את היכולת לכתוב יותר טרנזקציות בפרק זמן נתון לבלוקצ׳יין. השיפורים הקרובים אמורים לשפר את שני המדדים בסדרי גודל.
    • בלי שיפורים משמעותיים ב Scalability, הרעיון של מערכת בלוקצ׳יין – תקוע.
  • Privacy Concerns – רשתות בלוקצ׳יין הן Permissionless ו Transparent – שזו אחת התכונות המוערכות בהן. מצד שני, כאשר הן ציבוריות – משמע שיש חשש גדול פרטיות.
    • אמנם הטרנזקציות ברשת ביטקוין (לדוגמה) נרשמות ע״פ Address שאף אחד לא יודע לקשר לאדם מסוים, אולם אם ה Address הזה זולג ויודעים שהכתובת abcd היא אני – כולם יכולם לעקוב ולראות בדיוק אלו תשלומים ביצעתי / קיבלתי. מכיוון שהבלוקצ׳יין הוא Permanent – לא ניתן למחוק את המידע או to obfuscate it בכדי להגן על הפרטיות שלי מרגע החשיפה.
    • קישור של אדם לכתובת יכול להתבצע גם ללא דליפה ישירה. למשל התפרסם שקיבלתי כמות ביטקוין מגורם מסוים. זכייה בפרס, למשל. אפשר לעשות reverse engineering על הבלוקצ׳יין ולהתחיל לצמצם אפשרויות ולהבין מה הכתובת שלי.
  • BlockChain interoperability – מערכת הבלוקצ׳יין היא מערכת סגורה: בתוך המערכת היא יודעת לוודא את השלמות של הנתונים. לו היה רק בלוקצ׳יין אחד עולמי – לא הייתה בעיה. אל מכיוון שהמגמה היא של ריבוי בלוקצ׳יינס – בשלב מסיום נרצה לבצע ״טרנזקציות״ ופעולות בין כמה בלוקצ׳יין. איך עושים את זה בצורה אמינה? מה הטעם בבלוקצ׳יינים אמינים, אם כל פעולה ביניהם – חוזרת להיות לא אמינה?

תהליך הכרייה, בגדול, כולל את הצעדים הבאים (לוגית* – לא מה שקורה בפועל):

  • בחירת Miner node שיכתוב את הבלוק הבא (ע״י אלגוריתם קונצנזוס).
  • כתיבת הבלוק הבא מקומית.
  • הפצה של הבלוק החדש לכל רחבי הרשת.

בפועל מה שקורה הוא תהליך כזה:

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

תהליך הקונצנזוס, אם כן, מתרחש בשלבים 2 + 3: פתרון הבעיה המתמטית – ואימות התשובה. תוך כדי פעולה, Miner nodes סוררים יכולים לשלוח עדכונים של בלוקים עם חתימה ״מזויפת״ – אך כל ה Nodes שיקבלו אותם – יתעלמו מהם.

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

גם כאן, יש תהליך של תיקון, ועם הזמן (לא אכנס לפרטים במסגרת הפוסט) – הרשת (בהתבסס על הפרוטוקול) תחליט איזה מהבלוקים התקינים הוא זה שימשיך הלאה – ושאר הבלוקים התקינים יוסרו מהבלוקצ׳יין. תהליך התיקון של הרשת בפני “רישום סותר של בלוקים״ עשוי לקחת מספר מחזורים של רישום בלוק (בביטקוין: מחזור ארוך יחסית של 10 דקות). התהליך הוא סטטיסטי, אך מקובל להניח שתוך 6 מחזורים (כשעה) – סתירות בין בלוקים יסתדרו. ההסתברות לכך היא כ 95% (תלוי במודל החיזוי שנעשה בו שימוש. גורמים ״חיצוניים״, כגון אמינות הרשת וה latency בין nodes שונים – משפיעים על התוצאה).

חוות כרייה של ביטקוין. לא עוד שדות של כרובים…

אלגוריתמי קונצנזוס

אלגוריתם הקונצנזוס של בלוקצ׳יין הביטקוין, נקרא Proof of Work (בקיצור PoW. יש שיאמרו שזה קיצור של “Proof of waste״ – בשל האנרגיה הרבה שנדרשת לחישוביות שלו).

בגדול, כל Miner node יוצר את ״הבלוק הבא״ ואז חותם אותו ב SHA-256 (פונקציית Hash קריפטוגרפית) ובודק את התוצאה. הפרוטוקול מגדיר יעד (להלן: target) של ביטים של אפסים שיופיעו בתוצאה. למשל: 10 ביטים ראשונים ב Hash צריכים להיות אפס כדי לקבל ״חתימה תקינה״.

הבלוק, להזכיר, מכיל Header ו Body (הטרנזקציות עצמן):

מבנה בלוק של בלוקצ׳יין של ביטקוין

את הטרנזקציות משדרים ה Nodes השונים ברחבי הרשת והם נשמרות במבנה מקומי שנקרא memPool. ייתכן (ואפילו סביר) ש Miners nodes שונים ירכיבו ״Next Block״ שמכיל טרנזקציות מעט שונות. זה תקין, ובכל מקרה רק בלוק אחד יתקבל בסופו של דבר. הטרנזקציות שלא נכללו, ייכנסו לבלוק מאוחר יותר.

בנינו את הבלוק שלנו, והעברנו אותו בפונקציית SHA-256 (אפילו פעמיים!), אבל מה… לא יצאו לנו אפסים בכלל! ה Hash שלנו יצא:
e56d336922eaab3be8c1244dbaa713e134a8eba50ddbd4f50fd2fe18d72595cd

להזכיר ש SHA-256 היא פונקציית Hash קריפטוגרפית, כלומר:

  • בעלת Diffusion: שינוי ב bit אחד ב input – ישנה לפחות כחצי מהביטים בתוצאה של ה Hash. כלומר: כל שינוי קטן ב Input ״מערבל״ Hash חדש לחלוטין.
  • Collision resistant: אין דרך (ידועה) ל״הנדס״ את ה Hash שייצא. איני יכול למצוא Input נוסף שייצור אותו Hash כמו Hash שקיבלתי. הדרך היעילה ביותר לקבל Hash מסוים היא לעבוד ב Brute Force ולנסות עוד ועוד Inputs. להזכיר שה Hash הוא של 256bit (כלומר: יש לי כ 1077 אפשרויות ל Hashes שונים), והיכולת למצוא Input שייצור Hash מסוים – אינה סבירה חישובית.
    • מציאת Hash מסוים היא בעיה בלתי-סבירה חישובית (כיום), אך מציאת Hash עם 10 ביטים ראשונים שהם 0 => היא בעיה חישובית אפשרית. עלי לנסות יותר ממיליון אפשרויות (הסתברותית) על מנת להגיע ל Input מתאים.

בתוך ה Header של הבלוק יש שדה בשם Nonce (פירוש: ״מקרה בודד״). זהו בעצם Counter של 32 ביט שמאפשר לי לרוץ על 4 מיליארד איטרציות שונות, בניסיון לקלוע לערך שיביא את ה Hash ל 10 ביטים ראשונים שהם אפס.

בעוד פעולת החיפוש אחרי Hash שעומד ב Target היא פעולה קשה, הדורשת דקות של עבודה מאומצת מחוות שרתים בת אלפי מחשבים – פעולת האימות של ה Hash היא פעולה קלה: אני מריץ פעולה יחידה של Hash על הבלוק – וסופר את מספר הביטים עם ערך 0. אם הם 10 או יותר – הבלוק תקין. האימות מתבצע ע״י כל ה Nodes ברשת הבלוק׳ציין – על מנת לאמת שבלוק הוא תקין / נבחר בצורה תקינה. יש עוד מנגנון קריפטוגרפי שמאמת שהטרנזקציות עצמן תקינות – לא אכסה אותו בפוסט.

ככל שכוח המחשוב של רשת הביטקוין גדל, מציאת Hash שעומד ב Target הוא תהליך שהולך ומתקצר. כל כשבועיים, פרוטוקול הבלוקצ׳יין של ביטקויין משנה את ערך ה Target (מספר הביטים שהינם אפס) לערך שייקח בממוצע לרשת כ 10 דקות לחשב. הדרישה למציאת Hash עם 11 או 12 אפסים – תקשה את הבעיה פי 2 או 4. לא בביטים ככל שכוח המחשוב גדל – הבעיה המתמטית נעשית קשה יותר, כך שזו תמשיך להיות ״בעיה קשה״. בעת כתיבת הפוסט הדרישה של הפרוטוקול היא ל 80 אפסים (כלומר: bits) – וכוח המחשוב שעומל על פתרון הבעיה, כל 10 דקות מסביב לשעון – הוא חסר תקדים. ה nonce, אם תהיתם – כבר אינו מספיק, וכורים משתמשים בכמה תרגילים (כמו ״משחק״ בזמן הטרנזקציה) על מנת שיוכלו לנסות יותר וריאציות.

מעבר ל Proof of Work

לא כיסינו את כל ההיבטים של אלגוריתם ה Proof of Work אך יש לו בעיות ברורות. בעיה אחת היא צריכת אנרגיה הולכת וגוברת ככל שיש יותר Nodes ברשת.

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

כשהפרוטוקול הוגדר, היה קשה לדמיין מצב שבו 51% מה Miner nodes מתאגדים. כיום, בשל אופי אלגוריתם ה Proof of Work ש״מעניש״ שחקנים קטנים – ישנן התאגדויות כרייה בשם Miner Pools. חוות כרייה רבות מצטרפות לאיגוד המתחלק ברווחים (מטבעות ביטקוין המתקבלים בעקבות רישום של כל בלוק) – ע״פ יחס כוח החישוב של החברים, כך שגם חוות כרייה קטנה יחסית (מאות מחשבים בלבד) – יכולה להיות רווחית.

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

Proof of Stake אמור לצמצם דרמטית את דרישות החישוב של פרוטוקול הבלוקצ׳יין, וגם לייתר את הצורך בהתאגדויות של Mining Pools. הוא עדיין לא מושלם – ויש וריאציות רבות שלו, שבלוקצ׳יינס שונים מנסים.

ביטקוין עצמו נחשב בלוקצ׳יין שמרני מאוד, ולא נראה שיעבור ל PoS בקרוב, אך בלוקצ׳יין אתריום נחשב למאמץ נלהב של חידושים, ומזמן הכריז על מעבר ל PoS. מסיבות טכניות (מערכת מורכבת => שינויים הם קשים) המעבר הזה נדחה, וכרגע במקום היעד של יוני 2022, נראה שהמעבר יסתיים רק ב 2023.

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

סיכום

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

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

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

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