paint-brush
כיצד להתמודד עם מורכבות בעת תכנון מערכות תוכנהעל ידי@fairday
64,676 קריאות
64,676 קריאות

כיצד להתמודד עם מורכבות בעת תכנון מערכות תוכנה

על ידי Aleksei23m2024/02/05
Read on Terminal Reader
Read this story w/o Javascript

יותר מדי זמן; לקרוא

המורכבות היא האויב! בואו ללמוד איך להתמודד עם זה!
featured image - כיצד להתמודד עם מורכבות בעת תכנון מערכות תוכנה
Aleksei HackerNoon profile picture

במה מדובר?

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


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


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

מהי דאגה רוחבית?

אם נסתכל בוויקיפדיה, נמצא את ההגדרה הבאה


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


זה מאוד מתאר מה זה, אבל אני רוצה להרחיב ולפשט אותו מעט:

דאגה רוחבית היא מושג או מרכיב של המערכת/ארגון המשפיעים (או 'חוצים') חלקים רבים אחרים.


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


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

סיווג היבטים

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


אז, אני הולך לפצל היבטים למקרו ומיקרו .


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


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


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


במאמר זה, ההתמקדות העיקרית שלי תהיה בהיבטי המאקרו.

היבטי מאקרו

מבנה הארגון

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


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


תמיד האמנתי שהמושג הזה הוא אכן אוניברסלי מאוד ומייצג את כלל הזהב.


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


Fantasy about keeping in mind a lot of bounded contexts

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


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


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


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

כדור בוץ גדול

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


Entertaining illustration made by ChatGPT

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

ארכיטקטורת מערכת

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


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


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


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


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


לדוגמה, כגון:

  1. אדריכלות מונוליטית

  2. עיצוב מונחה דומיין

  3. מבוסס רכיבים

  4. שירותי מיקרו

  5. צינור ומסננים

  6. מונחה אירועים

  7. מיקרוקרנל

  8. מוכווני שירות


וְכֵן הָלְאָה…


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


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


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

  1. כמעט תמיד מתחיל בסגנון הארכיטקטורה המונוליטי שכן הוא מבטל את רוב הבעיות המתעוררות עקב אופי המערכות המבוזרות. זה גם הגיוני לעקוב אחר מונוליט מודולרי כדי להתמקד ברכיבי בנייה עם גבולות ברורים. יישום גישה מבוססת רכיבים יכול לעזור להם לתקשר זה עם זה על ידי שימוש באירועים, אבל קיום שיחות ישירות (המכונה RPC) מפשט את הדברים בהתחלה. עם זאת, חשוב לעקוב אחר תלות בין רכיבים שכן אם רכיב A יודע הרבה על רכיב B, אולי, הגיוני למזג אותם לאחד.
  2. כאשר אתה מתקרב למצב שבו אתה צריך לשנות את קנה המידה של הפיתוח והמערכת שלך, אתה יכול לשקול לעקוב אחר דפוס Stangler כדי לחלץ בהדרגה רכיבים שצריך לפרוס באופן עצמאי או אפילו להתאים לדרישות ספציפיות.
  3. עכשיו, אם יש לך חזון ברור של העתיד, שהוא קצת מזל מדהים, אתה יכול להחליט על הארכיטקטורה הרצויה. ברגע זה, אתה יכול להחליט על מעבר לארכיטקטורת שירותי מיקרו על ידי יישום גישות תזמורת וכוריאוגרפיה, שילוב דפוס CQRS לפעולות כתיבה וקריאה בקנה מידה עצמאי, או אפילו החלטה להישאר עם ארכיטקטורה מונוליטית אם היא מתאימה לצרכים שלך.


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


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

בחירת ערימת טכנולוגיה

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


זו רשימת השיקולים הבסיסיים לבחירת מחסנית טכנולוגיה:

  • דרישות ומורכבות הפרויקט. לדוגמה, ניתן לבנות אפליקציית אינטרנט פשוטה עם מסגרת Blazor אם למפתחים שלך יש ניסיון איתה, אך בשל חוסר הבשלות של WebAssembly, בחירת React ו-Typescript להצלחה ארוכת טווח יכולה להיות החלטה טובה יותר
  • צרכי מדרגיות וביצועים. אם אתה צופה קבלת כמות גדולה של תעבורה, בחירה ב-ASP.NET Core על פני Django יכולה להיות בחירה נבונה בשל הביצועים המעולים שלה בטיפול בבקשות במקביל. עם זאת, החלטה זו תלויה בהיקף התנועה שאתה מצפה. אם אתה צריך לנהל מיליארדי בקשות פוטנציאליים עם זמן אחזור נמוך, הנוכחות של Garbage Collection עשויה להיות אתגר.
  • גיוס עובדים, זמן פיתוח ועלות. ברוב המקרים, אלו הם הגורמים שאנו צריכים לדאוג להם. זמן לשוק, עלות תחזוקה ויציבות גיוס עובדים מונעים את צרכי העסק שלך ללא מכשולים.
  • מומחיות ומשאבים של צוות. מערך המיומנויות של צוות הפיתוח שלך הוא גורם קריטי. בדרך כלל יעיל יותר להשתמש בטכנולוגיות שהצוות שלך כבר מכיר, אלא אם כן יש סיבה חזקה להשקיע בלימוד מחסנית חדשה.
  • בגרות. קהילה חזקה ואקוסיסטם עשיר של ספריות וכלים יכולים להקל מאוד על תהליך הפיתוח. לטכנולוגיות פופולריות יש לעתים קרובות תמיכה קהילתית טובה יותר, שיכולה להיות בעלת ערך רב לפתרון בעיות ומציאת משאבים. כך, תוכל לחסוך משאבים ולהתמקד בעיקר במוצר.
  • תחזוקה ותמיכה לטווח ארוך. שקול את הכדאיות לטווח ארוך של הטכנולוגיה. טכנולוגיות מאומצות ונתמכות באופן נרחב נוטות פחות להתיישנות ובדרך כלל יקבלו עדכונים ושיפורים שוטפים.


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

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


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

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


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


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

נקודת כשל בודדת (SPOF)

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


ישנן מספר טכניקות בסיסיות שאנו יכולים ליישם כדי למנוע נקודות כשל בודדות:

  1. עוֹדֶף. הטמעת יתירות עבור רכיבים קריטיים. המשמעות היא שיש רכיבי גיבוי שיכולים להשתלט אם הרכיב הראשי נכשל. ניתן להחיל יתירות על פני שכבות שונות של המערכת, כולל חומרה (שרתים, דיסקים), רשתות (קישורים, מתגים) ותוכנה (מסדי נתונים, שרתי יישומים). אם אתה מארח הכל בספק ענן אחד ואפילו יש לך גיבויים שם, שקול לבנות גיבוי נוסף רגיל באחר כדי להפחית את העלות האבודה שלך במקרה של אסון.
  2. מרכזי נתונים. הפץ את המערכת שלך על פני מספר מיקומים פיזיים, כגון מרכזי נתונים או אזורי ענן. גישה זו מגנה על המערכת שלך מפני תקלות ספציפיות למיקום כמו הפסקות חשמל או אסונות טבע.
  3. כישלון. החל גישת failover עבור כל הרכיבים שלך (DNS, CDN, מאזני עומסים, Kubernetes, API Gateways ומסדי נתונים). מכיוון שבעיות עלולות להתעורר באופן בלתי צפוי, חיוני שתהיה תוכנית גיבוי שתחליף כל רכיב בשיבוט שלו לפי הצורך במהירות.
  4. שירותים בזמינות גבוהה. ודא שהשירותים שלך בנויים להיות ניתנים להרחבה אופקית וזמינים מאוד מההתחלה על ידי הקפדה על העקרונות הבאים:
    • תרגל חוסר מצב של שירות והימנע מאחסנת הפעלות של משתמשים במטמונים בזיכרון. במקום זאת, השתמש במערכת מטמון מבוזרת, כגון Redis.
    • הימנע מהסתמכות על הסדר הכרונולוגי של צריכת ההודעות בעת פיתוח לוגיקה.
    • צמצם את השינויים הפורצים כדי למנוע הפרעה לצרכני API. במידת האפשר, בחר בשינויים התואמים לאחור. כמו כן, שקול את העלות שכן לפעמים, יישום שינוי שבירה עשוי להיות חסכוני יותר.
    • שלב ביצוע הגירה בצינור הפריסה.
    • קבע אסטרטגיה לטיפול בבקשות במקביל.
    • יישם גילוי שירות, ניטור ורישום רישום כדי לשפר את המהימנות והצפיות.
    • פתח היגיון עסקי כדי להיות אדיש, מתוך הכרה שכשלים ברשת הם בלתי נמנעים.
  5. סקירת תלות. בדוק באופן קבוע וממזער תלות חיצונית. כל תלות חיצונית יכולה להציג SPOFs פוטנציאליים, ולכן חיוני להבין ולצמצם סיכונים אלה.
  6. שיתוף ידע קבוע. לעולם אל תשכח את החשיבות של הפצת ידע בתוך הארגון שלך. אנשים יכולים להיות בלתי צפויים, והסתמכות על אדם בודד היא מסוכנת. עודדו את חברי הצוות לעשות דיגיטציה של הידע שלהם באמצעות תיעוד. עם זאת, שימו לב לתיעוד יתר. השתמש בכלי AI שונים כדי לפשט את התהליך הזה.

מַסְקָנָה

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


תודה שקראת! נתראה בפעם הבאה!