תכנון ארכיטקטורת dApp: מחוזים חכמים ועד חוויית משתמש

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

שירותי פיתוח בלוקצ'יין

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1375
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1349
  • עיצוב לוגו לחברת B2B Advance
    עיצוב לוגו לחברת B2B Advance
    794
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1087
  • פיתוח לוגו חברת AIDER
    פיתוח לוגו חברת AIDER
    1032
  • פיתוח CRM עבור Chasseurs
    פיתוח CRM עבור Chasseurs
    1129

מדוע ארכיטקטורת dApp מתפוררת כאשר העומס גדל

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

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

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

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

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

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

מה מעניקה סכמה מחושבת היטב: אפקט מדיד

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

זמן הוצאת שינויים

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

שיעור הפעולות הידניות

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

סוג הכשל שנעלם

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

מספר התקריות וצפיות

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

גישות לארכיטקטורת dApp: השוואת מצבים

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

שלושה מצבים והעלות שלהם

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

במה שונה סכמה מודולרית מחוזה מונוליטי?

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

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

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

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

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

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

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

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

האם יהיה צורך לכתוב מחדש את החוזה הקיים?

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

כיצד מתחברים שירותים חיצוניים?

נתונים מבחוץ מגיעים דרך אורקלים ואינדקסרים, ומערכות תשלומים וחשבונאות — דרך שכבת מתאמים (adapters). קריאה חיצונית מבודדת באמצעות פסקי זמן (timeouts), חזרות ומפסק (circuit breaker): אי-זמינות של המקור אינה חוסמת פעולות של משתמשים.

האם נתקל במגבלות הרשת?

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

מי מנהל את ההרשאות והאבטחה לאחר המסירה?

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

נדון במשימה: מה לשלוח לצורך הערכה ותוכנית

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

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

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

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