לדלג לתוכן

מתודולוגיית Twelve-Factor App מוסברת

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

קוד אחד, הרבה פריסות (Codebase)

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

תלויות מפורשות (Dependencies)

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

קונפיגורציה בסביבה, לא בקוד (Config)

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

שירותי גיבוי כמשאבים מצורפים (Backing Services)

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

הפרדה בין בנייה, שחרור והרצה (Build, Release, Run)

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

תהליכים חסרי מצב (Processes)

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

קישוריות דרך פורט (Port Binding)

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

מדרגיות דרך תהליכים (Concurrency)

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

הפעלה וכיבוי מהירים (Disposability)

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

מקבילות בין פיתוח לייצור (Dev/Prod Parity)

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

לוגים כזרם אירועים (Logs)

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

משימות ניהול כתהליכים חד פעמיים (Admin Processes)

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

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

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

לסיכום

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