top of page
  • תמונת הסופר/תJonathan Barda & Niv Sluzki

לעבור לאיוונטים עם קינדר בואנו



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

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


אבל למה בעצם?

למה קשה לנו לשנות דברים?


ישנן כמה סיבות שבגללן קשה לנו לשכנע שהפתרון שלנו שווה את 20 הספרינטים הקרובים ואת כל תקציב התרבות של Q2:

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

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

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



ביסים קטנים


מה עושים?

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


אנחנו אוהבים לקחת את זה בביסים קטנים.

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


נתחיל בביס אחד ונסיים את כל החבילה בביס השני

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

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

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


השיטה שלנו היא: לדחות בעיות.

וזה גם מה שאנחנו מציעים לכם!


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



מקרה בוחן - מקריאה לכתיבה


במוצר שלנו יש מערכת הסקת מסקנות.

כמו שרלוק הולמס, רק בלי הכובע ועם יותר פייתון.


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


היו לכך הרבה מאוד סיבות ויתרונות שלא נכנס אליהם כאן.

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


אבל יש בעיה.

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

זה בעייתי כי:

  1. להתחיל להיכנס לקוד של צוות אחר לוקח זמן.

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

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


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

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



ווטסון, נראה לי שצריך פה קפקא



סבבה, אז מה הבעיה?


קודם כל, סינכרוניות.

החשש הכי גדול מ-Eventים הוא שבקשה אחת תתחיל שרשרת אירועים, תקרא לתהליכים שהם Blocking, ותשפיע מאוד על הביצועים.

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


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


התלבטנו אם פשוט להרים Kafka או איזה RabbitMQ ולגמור עניין, אבל פאק.

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

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


כמו שענה לנו ה-CTO כשביקשנו לחזור לשתות נספרסו: בשביל להיכנס לפרויקט כזה צריך סיבה ממש ממש טובה.


אולי נסחפנו?

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

אולי החששות שלנו לא נכונים?

מצד שני, אולי הם כן?

אולי אין סיכוי שהתשתית הזאת תעבוד בלי מנגנון אירועים אסינכרוני?



איך מקבלים החלטה?


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

אנחנו מעדיפים ללכת לים (מטאפורית, בואו…).

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

אז החלטנו בשלב הראשון לנסות לעשות את זה סינכרוני.


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

ביס של קינדר בואנו מיני.


לא סתם מערכת טיפשה - השתמשנו במנגנון מוכר ופשוט, Design Pattern שנקרא משקיף (Observer). זה כמו משקיף של האו״ם , רק שהוא באמת עושה משהו.

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

פשוט וקל. הכל קורה בתוך אותו ה-process.


אם היינו חכמים (לא מתחייבים לזה), ונזהרנו במימוש שבחרנו, נוכל להחליף את המנגנון הזה למנגנון אחר בעתיד. אולי בהמשך המימוש מאחורי הקלעים יהיה cellery או Kafka או משהו אחר.



מה מצב העו״ש?


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


מה חסכנו?

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

  2. כאבים של אסינכרוניות. ה-VP R&D שלנו, סאפו, עשה הרצאה על ״איך לכתוב מערכת אסינכרונית מבלי שהשיער יהפוך לאפור״, ויש לנו הרבה ניסיון בחברה וחוש ריח לדעת ממה להיזהר.

  3. בעיות Deployment. ה-Deployment שלו מראש מורכב. אנחנו תומכים ב-SaaS ו-OnPrem מהיום הראשון. להכניס עוד מורכבות כזו זה משהו שצריך לקחת בחשבון.

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

  5. כיף לצוות ה-Devops. מצטערים פרננדו, לא תקבל את תקציב ה-Cloud שבנית עליו.




מה הרווחנו?

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

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

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


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

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


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





עליות וירידות, הפסדים והפתעות


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


מה הפסדנו?

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

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


ממה הופתענו? ביצועים.


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

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


המקרה הכי מפתיע היה כשצוות ה-SDK שלנו (אין לנו באמת צוות כזה, תקראו את Team Topologies, זה סתם בשביל לפשט, אל תתפסו אותנו במילה נו!) החליט לעבור לקריאות אסנכרוניות.

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



סיכום


המטרה שלנו היא להגיע למערכת-מבוססת-אירועים אמיתית, אסינכרונית.

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


כדי לפתור את הבעיה הזאת אנחנו צריכים:

  1. לכתוב קוד שתומך בקונספט של אירועים

  2. לחקור ולבחור טכנולוגיה רלוונטית

  3. להטמיע את הטכנולוגיה כחלק מה-Deployment

  4. לפתור בעיות חדשות שיצוצו כתוצאה מ-3 :)


אנחנו כרגע בביס הראשון, והוא היה טעים, קריספי כזה.

נראה לנו שנפלנו על הקינדר בואנו הלבן.

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


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


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


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

את שארית הבעיות שהחלטנו לא לנצח, נדחה לספרינט הבא.


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



מפלצת כיס, אילוסטרציה


757 צפיותתגובה 1

1 Comment


Guest
Feb 19, 2022

מאוד ממליץ לבדוק את https://dramatiq.io/motivation.html לפני celery

Like
bottom of page