ru
Feedback
ToCode

ToCode

Открыть в Telegram

טיפים קצרים למתכנתים מאת ינון פרק

Больше
1 420
Подписчики
Нет данных24 часа
-17 дней
Нет данных30 день
Архив постов
ToCode
1 421
# שתי טעויות עם הצעות נכנסות שתי טעויות נפוצות שאנחנו עושים עם הצעות נכנסות (הצעות עבודה, הצעות לפרויקטים): 1. מתיחסים להצעה בודדת כאילו היא היחידה - וכך מוכנים להתפשר על העקרונות שלנו מהפחד שלא תהיה הזדמנות נוספת. 2. מתיחסים לעשר הצעות כאילו מדובר באינסוף - וכך מתחילים לזלזל בלקוחות ולהתנהג כמו פרימדונה, מתוך מחשבה שממילא תמיד תבוא הצעה נוספת. הדרך הנכונה פשוטה לכתיבה אך מסובכת ליישום: יש להסתכל על כל הצעה כאילו היא האחרונה ולתת את היחס הטוב ביותר האפשרי למציע, במקביל יש לזהות מה גרם להצעה הזאת להיכנס ולייצר "עוד מאותו דבר" כדי שהצעות טובות ימשיכו לזרום. לא להיכנע לפחד ולא לשאננות, אלא ללכת קדימה בצורה מחושבת, לזהות תבניות שמביאות יותר הצעות והצעות טובות יותר וליישם אותן ולהמשיך כל הזמן לעבוד קשה.

ToCode
1 421
סרביס ההזדהות יוסיף בצורה אוטומטית מזהה משתמש בתור HTTP Header לכל בקשה שנכנסת מהדפדפן ברגע שהיא מגיעה אלינו לאחד הסרביסים. בצורה כזאת כל סרביס "יודע" מי המשתמש שעומד מולו ואיזה דברים אותו משתמש רשאי לעשות, גם אם אין לסרביסים האחרים גישה לנתוני המשתמשים. מנגנון של API Gateway יוודא שמשתמש מגיע לסרביס שדורש הרשמה רק אחרי שהוא נרשם והתחבר לאתר. ## תשלום בקופה ברגע שלקוח מוכן לשלם "סל הקניות" יפנה ל"מערכת ההזמנות" ויבקש לפתוח הזמנה חדשה במערכת על המוצרים המבוקשים ובמחירים המבוקשים (אנחנו לא רוצים ששינוי מחיר שקורה אחרי ביצוע ההזמנה ישפיע על הסכום לתשלום). סל הקניות יחזיר לדפדפן מזהה הזמנה. הדפדפן יפנה למערכת התשלומים עם מזהה ההזמנה שלו ויקבל בחזרה קישור לדף תשלום, למשל בפייפאל. לאחר ביצוע התשלום בדף הלקוח עובר אוטומטית לדף תודה בחנות, ובמקביל פייפאל תשלח הודעה למערכת התשלומים שלנו על תשלום שבוצע בהצלחה. ברגע שמערכת התשלומים מזהה שתשלום על הזמנה מסוימת התקבל בהצלחה היא שולחת הודעה למערכת ההזמנות בבקשה לעדכון הסטטוס. דף התודה יהיה מחובר ב Web Socket למערכת ההזמנות, וכך נוכל להציג למשתמש עדכון בזמן אמת כל פעם שסטטוס ההזמנה מתעדכן. ## הצעת מוצרים קשורים כל חנות שמכבדת את עצמה מציעה ללקוח גם מוצרים קשורים בדף מוצר, או מדי פעם שולחת הודעות על מוצרים קשורים לאימייל אם הלקוח לא נכנס תקופה מסוימת למערכת. אנחנו יכולים לכתוב את הלוגיקה שמחשבת איזה מוצרים קשורים בעזרת מיקרו סרביס נוסף. אותו סרביס יתחבר למערכת המוצרים כדי לגלות מידע על מוצרים, אבל ישמור את ההמלצות שלו ב Cache מקומי כדי לא ליצור תלות מיותרת במערכת המוצרים. דפדפן יוכל לפנות למערכת ההמלצות מתוך כל דף מוצר ולקבל רשימה של מוצרים קשורים להצגה. משימה מתוזמנת תוכל לרוץ פעם ביום, לזהות מוצרים מומלצים ללקוחות מסוימים ולשלוח להם אימייל עם תקציר מוצרים אלה. ## סיכום הסתכלות על מערכת בתור אוסף של Micro Service עוזרת לנו לחשוב על החלקים השונים של המערכת ולהכיל אותם כך שעכשיו הרבה יותר קל לכתוב כל חלק. אנחנו כבר לא צריכים לכתוב "חנות" ענקית עם כל המנגנונים הקשורים אליה, אלא רק "סרביס של סל קניות" או "מערכת ניהול מוצרים". התמקדות בכל תת-מערכת עוזרת לשמור על סדר בפיתוח, לבדוק כל רכיב בנפרד וגם לחלק את העבודה טוב יותר בין צוותים בארגון. בין השורות ראינו כאן מספר מנגנונים לתקשורת בין המערכות השונות: לפעמים סרביס היה צריך מידע עכשיו, למשל בארכיטקטורה שראינו כאשר סל קניות צריך לפתוח הזמנה חדשה במערכת, הוא ירצה לשלוח את הגולש לדף ההזמנה החדשה ובשביל זה הוא יצטרך להחזיר לדפדפן את מזהה ההזמנה. אי אפשר לסיים לפתוח הזמנה חדשה בלי לקבל מספר הזמנה - וזו תקשורת סינכרונית. דוגמה נוספת היתה סרביס סל הקניות, שבשביל להחזיר ללקוח את כל המוצרים למסך סל הקניות פנה לסרביס של רשימת המוצרים, ורק כשקיבל חזרה את הרשימה יכל להחזיר תשובה ללקוח. לעומת זאת כשלקוח מחכה בדף התודה לקבל את האישור מפייפאל אין לנו אף סרביס שעובד. הסרביס של מערכת התשלומים ממתין להודעה נכנסת מפייפאל, וכשההודעה תגיע הוא ישלח אותה בדחיפה לדפדפן באמצעות מנגנון של Web Socket. מנגנון שלישי שעזר לנו לצמצם תלויות בין Services היה ה Cache: במקום שמערכת ההמלצות כל פעם תפנה למערכת המוצרים כדי לקבל את המידע שהיא צריכה, היא תשמור ב Cache המלצות על מוצרים (אחרי החישוב). כאשר יש עדכון למערכת המוצרים, מערכת המוצרים תוכל להוציא הודעה (אסינכרונית) למערכת ההמלצות כדי שזו תחשב מחדש את ההמלצות שלה ותשמור לעצמה Cache חדש.

ToCode
1 421
למרות האתגרים ארכיטקטורת Micro Services איתנו כדי להישאר. שירותי ענן כמו AWS ו Azure מספקים כלים מובנים לפיתוח בגישה זו וחברות גדולות רבות כבר עובדות כך. היכרות עם העולם, הכלים, האתגרים וההזדמנויות של Micro Services היא הכרחית למפתחי Full Stack היום. בואו נמשיך לראות איך היינו ניגשים לבנות את מערכת החנות שתיארתי בהתחלה בגישת Micro Services. ## לחנות יש מערכת ניהול שם מנהל החנות יכול להזין מוצרים, מחירים ולבחור פרמטרים שונים שקשורים למראה אתר החנות. הדרישה הראשונה של הלקוח שלנו היא לקבל מערכת ניהול לחנות כדי שיוכל להזין בה פרמטרים של מראה החנות, לבנות מלאי מוצרים, לצאת במבצעי הנחה, לראות את ההזמנות ולעשות את כל מה שצריך בשביל לנהל את החנות. אבל כשאנחנו קוראים את הדרישה הזאת במונחי Micro Services קל לראות שדרישה זו מייצגת מספר עולמות תוכן שונים שעדיף יהיה לנו לפצל אותם למספר Services. במקום לבנות מערכת ניהול אחת אני מעדיף להסתכל על האספקטים של החנות או ה Domains השונים שאנחנו צריכים: 1. ניהול מוצרים 2. ניהול מראה 3. יצירת קמפיינים והנחות 4. ניהול הזמנות 5. ניהול משתמשים כל Domain כזה יכול להיכתב בתור Micro Service נפרד ולתקשר עם הסרביסים האחרים באמצעות API. נמקד לרגע במערכת ניהול המוצרים. מערכת זו תכלול אוסף של מסכי ניהול בהם מנהל מערכת יכול להזין את תיאורי המוצרים, להעלות תמונות למוצרים, לקבוע מלאי, לקבוע את המחירים וכל מה שמוצר צריך. המידע יישמר בבסיס נתונים פנימי של מערכת המוצרים. בגלישה לאתר החנות הדפדפן יפנה דרך API למערכת המוצרים וימשוך משם את המידע הנדרש על המוצרים. לדוגמה נניח שיש לנו מספר מוצרים שצריכים להיות מקודמים בעמוד הבית, אז בגלישה לעמוד הבית הדפדפן ימשוך בדיוק את הפרטים שצריך על מוצרים אלה. באותו האופן Micro Service אחר יכול להיות אחראי על "מראה" האתר. שם נוכל לקבוע את הכותרת הראשית של אתר החנות, את הצבעים של החנות, אולי את תמונת הלוגו וכל פרמטר אחר שאנחנו רוצים לאפשר למנהל האתר לשנות. מבחינת מנהל האתר שני סרביסים אלה נראים כמו מערכת אחת: הוא נכנס למערכת ניהול ובתפריט יכול להיכנס למסך ניהול המוצרים או מסך ניהול המראה. מתחת לפני השטח הפרמטרים של המראה נשמרים בבסיס נתונים נפרד מהמידע על המוצרים. ## לחנות יש אתר ציבורי אליו משתמשים יכולים להגיע דרך מנוע חיפוש או דרך קישור שקיבלו מחבר. פיתוח האתר הציבורי יהיה פרויקט Front End. הוא יכול להיות כתוב ב JavaScript או באיזשהו פריימוורק. הדבר החשוב כאן הוא שכל המידע מגיע מהשרת דרך קריאות API. לדפדפן לא אכפת אם הוא מדבר עכשיו עם סרביס X או סרביס Y, מאחר והוא פשוט פונה ל URL, מקבל את המידע ומציג אותו על המסך לגולש. ## בתוך האתר הציבורי יש מנגנון של סל קניות. הסרביס הבא שלנו הוא סל הקניות. במערכת מונולית סל הקניות היה חלק מהמערכת ונשמר בבסיס הנתונים יחד עם פרטי המשתמשים ופרטי המוצרים. במערכת Micro Services אנחנו צריכים מבנה יותר מתוחכם. סל הקניות יקבל בקשות מהדפדפן דרך ה API. כל גולש שמגיע לאתר יקבל מזהה ייחודי שיישמר אצלו ב Session, ואם הוא מבצע Login המזהה הזה גם יישמר בבסיס הנתונים במערכת המשתמשים (עוד סרביס) ויישלח אלינו לסל הקניות באמצעות HTTP Header. כשמשתמש רוצה להוסיף מוצר לסל הדפדפן ישלח בקשה לסל הקניות עם אותו מזהה ייחודי של הגולש ומזהה המוצר שהוא רוצה להוסיף לסל. סל הקניות לא צריך לשמור את פרטי המוצרים ומספיק לו להשתמש בבסיס נתונים קטן עם טבלה בודדת שמכילה מזהה משתמש, האם זה משתמש מאומת במערכת או אורח, ומזהה המוצר שהוא רוצה להוסיף. בכניסה למסך סל הקניות הדפדפן יוכל לפנות דרך ה API לסרביס של סל הקניות ולבקש לראות את פרטי כל המוצרים בסל. בנקודה זאת סרביס סל הקניות יפנה לסרביס ניהול המוצרים, ימשוך את פרטי כל המוצרים שמתאימים למזהים ששמורים אצלו ויחזיר את כל הפרטים שהדפדפן צריך כדי להציג את המוצרים. סרביס סל הקניות יצטרך להתמודד עם מצב שסרביס המוצרים כרגע לא עונה לו, או שחלק מהמוצרים כבר לא נמצאים שם. כדי להציע הנחות סרביס סל הקניות יוכל לפנות לסרביס אחר של "קמפיינים והנחות", להעביר לו את המוצרים שנבחרו ואת מזהה המשתמש ולקבל חזרה רשימה של קופונים ומבצעים שהמשתמש זכאי להם. כחלק מהסרביס, משימה מתוזמנת תרוץ פעם בשבוע כדי למחוק את סלי הקניות שלא מקושרים למשתמש רשום במערכת. ## לקוחות החנות שרוצים לקנות צריכים להירשם לאתר סרביס הזדהות יהיה אחראי על ניהול המשתמשים, רישום, שליחת מיילים לאיפוס סיסמה וחיבור דרך יישומי צד-שלישי כמו פייסבוק וגוגל. אנחנו אפילו לא חייבים לכתוב סרביס הזדהות בעצמנו ואפשר להשתמש בסרביס קיים כמו Amazon Cognito או auth0.

ToCode
1 421
בצוותים קטנים העבודה יחד על אותו פרויקט כשהקוד כולו נמצא במקום אחד וכתוב בשפה שכולם מבינים מייצרת פרודוקטיביות גבוהה. כשהפרויקט קטן ובתחילת הדרך אנחנו רוצים לצמצם תקורה ולהשקיע רק כמה שצריך בתשתית כדי שנוכל להתמקד בפיתוח המערכת עצמה. ## מה רע במונולית ככל שחברה ובתוכה צוות הפיתוח גדלים כך אנחנו מתחילים לראות מונוליתים שמסתבכים: 1. קשה לנו לגייס אנשים חדשים כי מתכנתים רוצים לעבוד בטכנולוגיה X ואצלנו המונולית כתוב בטכנולוגיה Y. 2. מתכנתים לא תמיד מבינים את האילוצים והחיבורים הטבעיים במערכת, ולאורך זמן נוצרות תלויות בין מודולים שונים במערכת, מודולים שלא היו אמורים להיות קשורים. שינוי שהכניס מתכנת במסך של סל הקניות פתאום יכול להשפיע על רכיבים אחרים ולא קשורים במערכת ויהיה לנו קשה לזהות למה. 3. העלאת קוד חדש, גם אם קטן, היא תמיד תהליך מלחיץ כי אנחנו לא מעלים לפרודקשן רק את השינוי - אנחנו מעלים את כל המונולית מחדש. טעות קטנה במודול אחד יכולה לשבור את כל המערכת. 4. כשהמערכת שלנו מתחילה להיות סופר-פופולרית לפעמים נרצה להגדיל קיבולת של השרת כדי לתת חווית שימוש טובה לכל הגולשים החדשים. במונולית הגדלת הקיבולת מתחלקת בצורה שווה בין כל חלקי המערכת, כך שבחנות הדוגמה שלנו אם נוסיף שרת אותו שרת יריץ את הפרויקט המלא, כולל את מערכת הניהול, מערכת התזכורות ומסך ניהול הלקוחות, כשבעצם מה שאני רציתי זה להוסיף כמה שיותר כח מחשוב לאתר הציבורי ולמערכת הקניות כדי לוודא שאנשים תמיד יכולים לשלם. 5. קוד גדול מדי הוא גם חיסרון. כשמספר השורות במערכת עובר את המאות אלפים או אפילו מיליונים אין אף אחד בצוות שמכיר את כל חלקי המערכת ומתכנתים נדרשים לעבוד בסביבה אותה הם אינם מבינים עד הסוף. ## איך Micro Services יכולים לעזור לנו בגישת המונולית אנחנו מחלקים את האפליקציה לחלקים שונים באמצעות שפת התכנות עצמה, למשל באמצעות שבירת הפונקציונאליות למחלקות ולמודולים, אבל תמיד נשארים עם מערכת אחת גדולה. גישת Micro Services מציעה להפריד את האפליקציה לתתי-מערכות, כאשר כל מערכת תרוץ בתור תהליך נפרד, תהיה כתובה בסביבה משלה ואפילו תשתמש בבסיס נתונים משלה. המערכת יתקשרו ביניהן באמצעות איזשהו HTTP API או באמצעות שליחת הודעות אחת לשניה. בגישת ה Micro Services, כל סרביס מפותח על ידי צוות קטן ומטפל בהיבט קטן של פעילות המערכת. במערכת החנות שתיארתי בתחילת השיעור אפשר לדמיין שכל סעיף יהיה Micro Service עצמאי. פיתוח בגישת Micro Services יכול לעזור לנו לפתור חלק מהאתגרים בפיתוח מונולית: 1. אין בעיה לגייס מתכנתים חדשים. לא משנה איזו טכנולוגיה הם אוהבים, יש לנו סרביס שכתוב בזה. 2. התלויות בין הסרביסים מוצגות בצורה קשיחה באמצעות API. אי אפשר בטעות ליצור תלות חדשה או להשתמש במידע שמישהו אחר עלול לשנות. רק מה שב API זמין לסרביסים אחרים. 3. בהעלאה לפרודקשן אפשר להעלות רק את הסרביס שהשתנה ולא צריך להעלות את המערכת כולה. 4. אם צריך להגדיל קיבולת אין בעיה להעלות עוד שרתים עם הסרביס הספציפי שצריך עכשיו את הקיבולת הגדולה יותר, בלי לשנות את הסרביסים שפחות נוגעים בהם. 5. קוד של מיקרו סרביס הוא הרבה יותר קטן מקוד של מערכת מלאה ויכול להסתכם במאות או אלפי שורות. ב 25.3.2014 מרטין פולר וג'יימס לואיס פרסמו מאמר מפורסם בשם המופלא Microservices, בו הם מפרטים את הגישה, היתרונות והחסרונות שלה. אני ממליץ לכם לקרוא אותו. ## אתגרים בפיתוח Micro Services במעבר ל Micro Services אנחנו הולכים להיתקל בלא מעט אתגרים שלא הכרנו בעבודה על מערכות מונולית. אלה המרכזיים שבהם: 1. ניהול זהות - כי עכשיו המידע על המשתמש מפוצל בין מספר בסיסי נתונים. 2. ניטור - כדי לזהות התנהגות חריגה או עומס על סרביסים מסוימים 3. התמודדות עם תקלות - כי פניה ל API היא מהלך הרבה פחות אמין מקריאת מידע ישירות מבסיס נתונים 4. ניהול Log - כי כל סרביס רץ על מכונה נפרדת אבל עדיין צריך להיות מסוגלים לראות את כל מה שקרה במקום אחד 5. קושי בתחזיקה כשהצוות מתחלף - כי לאף אחד אין מושג איך לקרוא את קוד הסרביס ההוא ב erlang שנראה כמו רעיון טוב לפני שנתיים. 6. ניהול גירסאות - כי מה זה אומר בכלל "להעלות גירסה" של מערכת, כשכל הזמן גירסאות של סרביסים מתעדכנות. 7. טרנזאקציות - כי מה קורה כשתהליך מסוים אמור להשפיע על מספר סרביסים, ובאחד מהסרביסים התהליך נופל.

ToCode
1 421
# מ Monolith ל Micro Services חברות רבות נמצאות כבר או שוקלות תהליך של מעבר מפיתוח מערכת קלאסי בגישת המונולית לפיתוח בגישת Micro Services. למרות שהמונח Micro Services אינו חדש, אני חושב שהכלים הטכנולוגיים לפיתוח בגישה זו יחד עם עולם הידע שכבר נצבר בתעשיה מאוד התפתחו בשנה-שנתיים האחרונות והיום כמעט כל אחד יכול להרים מערכת בגישה זו אם רק מכירים את אותן טכניקות ואותם כלים. בפוסט זה נדבר על הדרך שאפשר לעשות במעבר ממונולית למיקרו סרביסס. ## הגישה הקלאסית (Monolyth) לפיתוח יישומים הגישה הקלאסית לפיתוח, או כמו שאוהבים לכנות אותה "גישת המונולית" היא האינטואיציה הראשונה שלנו כשאנחנו באים לכתוב מערכת. בגישת המונולית המערכת היא תוכנית אחת גדולה, שיכולה להיות כתובה בתור אוסף של פונקציות או אוסף של מחלקות, שאחראית על ביצוע כל האספקטים של העבודה. נניח שאנחנו רוצים לבנות מערכת לניהול חנות דיגיטלית. בלי לרדת לפרטים הכי קטנים אנחנו יכולים לדמיין את תתי המערכות הבאות בבואנו לכתוב מערכת לחנות: 1. לחנות יש מערכת ניהול שם מנהל החנות יכול להזין מוצרים, מחירים ולבחור פרמטרים שונים שקשורים למראה אתר החנות. 2. לחנות יש אתר ציבורי אליו משתמשים יכולים להגיע דרך מנוע חיפוש או דרך קישור שקיבלו מחבר. 3. בתוך האתר הציבורי יש מנגנון של סל קניות. משתמשים יכולים להוסיף לעצמם מוצרים לסל הקניות, לראות מה נמצא כרגע בסל, אולי לקבל הנחות (קנה 2 חולצות וקבל גרביים מתנה), להוציא מוצרים מהסל. 4. בתוך האתר הציבורי יש מנגנון של ניהול משתמשים. אנשים יכולים "להתחבר" לאתר כדי שסל הקניות שלהם יישמר או כדי לשלם על הזמנה. מערכת המשתמשים מאפשרת למשתמשים לאפס סיסמה ששכחו או לשנות כתובת מייל או פרטים אישיים אחרים. 5. משתמשים רשומים יכולים ללכת לקופה כדי לשלם על המוצרים שכרגע נמצאים בסל הקניות שלהם. אחרי התשלום הם יכולים להיכנס למסך הזמנות ולראות מה מצב ההזמנות שלהם ואם יש משלוח שצפוי להגיע בקרוב. 6. חנויות דיגיטליות גדולות לומדות את תחומי העניין של המשתמשים ויודעות להציע להם מוצרים נוספים שיעניינו אותם. כך אם אני מתחבר פעם בכמה ימים להסתכל על חולצות, המערכת יכולה באופן אוטומטי לשלוח לי אימייל שמספר על חולצה חדשה שהגיע למלאי. בדרך כלל אני גם יכול לבחור לקבל פחות אימיילים או לקבל את ההודעות בדרך אחרת, למשל בסמס או ווטסאפ. 7. לחנויות מסוימות יש מועדוני לקוחות. כל משתמש באתר יכול להיות חבר מועדון, ומנהל החנות יוכל לראות מי הלקוחות שקונים הכי הרבה כדי להציע להם מבצעים מיוחדים או הטבות. בגישת המונולית יהיה לנו פרויקט אחד, שכתוב בשפת תכנות אחת, משתמש בבסיס נתונים אחד, ויודע לענות על כל הדרישות בתוך מערכת אחת. בבסיס הנתונים יהיו טבלאות עבור משתמשים, מוצרים, סלי קניות, הזמנות, קופונים וכל מידע נוסף שהחנות צריכה כדי לפעול. כשאני צריך להוסיף פיצ'ר אני נכנס למקום המתאים במערכת ומוסיף את הקוד. כשאני צריך לכתוב בדיקות אני נכנס לתיקיית הבדיקות ומוסיף את הבדיקה. וכשצריך להעלות גירסה פשוט מעלים את כל קוד המערכת המעודכן. בתוך הקוד מודולים שונים (בדרך כלל class-ים) יטפלו בחלקים השונים של המערכת. כשמודול מסוים יצטרך מידע הוא יוכל לשלוף את המידע מבסיס הנתונים. כשמודול מסוים יצטרך להשתמש בפונקציונאליות של מודול אחר הוא יוכל פשוט להפעיל את הפונקציה. ## מה טוב במונולית פיתוח מונולית היא הגישה הראשונה שאנשים חושבים עליה כשמגיעים לכתוב מערכת חדשה והיא עדיין הגישה המובילה במקומות רבים. היתרונות של מונולית כוללים: 1. כמעט תמיד קל לנו יותר להוסיף קוד למערכת קיימת מאשר להתחיל פרויקט חדש מאפס. לכן במונולית יחסית קל להוסיף פיצ'רים חדשים או לעדכן פיצ'רים. 2. כשכל הקוד באותו פרויקט קל לבדוק תרחישים מורכבים באמצעות בדיקות End To End. 3. כשכל המידע שמור בבסיס נתונים אחד קל להיכנס לבסיס הנתונים ולמצוא בעיות במידע או מידע לא תקין. קל לעשות "תיקונים" ידניים בתוך בסיס הנתונים למשל כשלקוח מסוים צריך עדכון דחוף למידע. 4. כשהקוד כולו כתוב באותה שפת תכנות ובאותו Framework, קל לעבור בין חלקים שונים בקוד כדי לזהות באגים או לעדכן קוד חוצה מודולים שמשפיע על הרבה מנגנונים במערכת. 5. כשמונולית מתרסק הוא עושה הרבה רעש: וזה טוב כי אם פתאום הכל מפסיק לעבוד קל יותר לשים לב לזה, לתקן ולהעלות את המערכת מחדש. 6. בעת פיתוח פיצ'ר או תיקון באג כל המידע וכל הפונקציונאליות של היישום זמינים לנו במקום אחד. זה אומר שאני יכול להשתמש במידע מבסיס הנתונים שעד עכשיו לא חשבתי שאצטרך בלי לבקש רשות מאף אחד. 7. קל לנהל גירסאות כשכל מה שיש לנו זה קוד אחד ענק וכל גירסה חדשה כוללת את הקוד כולו.

ToCode
1 421
# בשביל מה זה טוב? הי ינון, אנחנו מחפשים קורס Docker למתכנתים פה. הרבה חבר'ה עוזבים כי מרגישים שהמערכת שלנו מיושנת ולא נותנת להם כלים טובים להמשך. אנחנו עובדים על קוד PHP שנכתב במקור לפני 15 שנה ואין מצב להיכנס ל Refactoring בעתיד הנראה לעין אז אני די מבין אותם. בכל מקרה חשבנו לפנק אותם בקורס על איזה טכנולוגיה מודרנית שירגישו בעניינים. אפשר לשלב גם AWS, קוברנטס וכל מה שהולך היום. אם אפשר אחרי הקורס להמשיך לסידרת הרצאות העשרה על כל מיני Buzzwords זה יהיה מעולה. יש לך משהו כזה? --- הי ינון, יש לנו מערכת PHP ישנה שכרגע אנשים די סובלים מהמשך תחזוקה שלה, ולאחרונה איבדנו כמה מהמתכנתים הטובים שלנו כי הרגישו שהמערכת גוררת אותם אחורה. אנחנו רוצים לעמוד חזרה על הרגליים ולתת פייט למתחרים שלנו ולכן החלטנו להתחיל שידרוג (איטי) לטכנולוגיית ענן בגישת Micro Services. אנחנו רוצים להתחיל להוציא התנהגות ומידע מהמערכת הקיימת ולממש אותם בתור Service ב Node.JS או Go, ומחפשים קורס שיעזור לנו עם המעבר. דוקר חייב להיות שם וגם הבנה טובה של ארכיטקטורת Micro Services. אם אפשר לקבל גם ליווי מקצועי אחרי הקורס בבניית הסרביסים הראשונים שלנו זה יהיה מעולה. --- הרבה יותר מבחירת הנושאים, ה"בשביל מה זה" הוא שקובע איזה קורס תקבלו. ואם אתם לא מרוצים מסיפור הרקע זה הדבר שכדאי לתקן לפני הכל.

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

ToCode
1 421
# חידת Node.JS ו Winston לפני כמה ימים הראיתי כאן איך לכתוב לוגים של שרת Node.JS באמצעות Winston. מה שלא סיפרתי לכם זה שלוינסטון יש המון הרחבות שמאפשרות לו לכתוב את הלוגים לאינסוף יעדים. בפרויקט שהקמתי לא מזמן רציתי להוציא את הלוגים של וינסטון לשרת לוגים מרוחק שהריץ syslog. בתמימותי כתבתי את הקוד הבא כדי לאתחל אוביקט logger:
const winston = require('winston');
require('winston-syslog').Syslog;


// creates a new Winston Logger
const logger = winston.createLogger({
  level: 'debug',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.printf(({ level, message, timestamp }) => (
      `${timestamp} ${level}: ${message}`
    )),
  ),
  transports: [
    new winston.transports.Syslog({
      host: process.env.SYSLOG_NG_HOST,
      app_name: process.env.SYSLOG_NG_APPNAME,
    }),
  ],
});

logger.stream = {
  write(message, _encoding) {
    logger.info(message);
  }
};

module.exports = logger;
הקוד עבד אבל כלל מוקש לא נעים בכלל. נסו למצוא מה היה הבאג ולספר בתגובות.

ToCode
1 421
# אולי עוד ספר ב 12 שנים בבית ספר אני לא זוכר אפילו מקצוע אחד בו המורה אמר "ילדים יש לכם שלוש אפשרויות לספר לימוד, ומותר לבחור יותר מאחד". לפעמים קיבלנו מטלה לסכם או ללמוד על איזה נושא ממקור חיצוני, אבל זה היה החריג, המדליק, המיוחד. היום יום של בית הספר מורכב מספר לימוד, מורה שמסביר את החומר ותלמידים שכותבים. (וממה ששמתי לב מצפיה בתוכנית הלימודים של הבן הגדול שלי, לפחות עד כיתה ג זה עדיין עובד כך). לא פלא שכשאנחנו מחפשים היום קורס אנחנו מחפשים את "הקורס המקיף על..." ומתפתים לקנות את אחד הקורסים עם הסילבוס האינסופי ביודמי. איפשהו המחשבה אומרת שאם צריך לבחור רק קורס אחד, עדיף לבחור את המקיף ביותר. אבל האמת שגם לילדים וגם למבוגרים שווה להתרגל לשיטה אחרת: שווה לחפש כמה שיותר מקורות לימוד, כמה שיותר קורסים, כמה שיותר ספרים. שווה להתרגל לעולם פתוח שיש בו מגוון דעות, מגוון פיתרונות ומגוון גישות. זה לא במקום, זה בנוסף.

ToCode
1 421
ב app.js של פרויקט express חדש שנוצר על ידי express-generator השורות הבאות אחראיות על יצירת הלוגר מורגן:
var logger = require('morgan');

app.use(logger('dev'));
אני מחליף אותן לקוד הבא:
var morgan = require('morgan');
var logger = require('./logger');
app.use(morgan(':method :url :status :res[content-length] - :response-time ms', { stream: logger.stream }));
ועכשיו בהפעלת השרת וגלישה מדפדפן אני מקבל גם לקונסול וגם לקובץ את התוכן הבא:
2021-07-09T17:26:31.663Z info: GET / 200 170 - 104.904 ms
2021-07-09T17:26:31.705Z info: GET /stylesheets/style.css 304 - - 1.058 ms
## עוד כמה יעדי לוג בעמוד הבא תוכלו למצוא רשימה די גדולה של יעדים ש Winston יודע לכתוב אליהם את ההודעות שלכם: https://github.com/winstonjs/winston/blob/master/docs/transports.md בין היעדים שאני אהבתי יש את MongoDB, Syslog, Amazon Cloudwatch, Elasticsearch, Papertrail וכמובן Slack.

ToCode
1 421
# כתיבת קובץ לוג משרת Express באמצעות Winston וינסטון היא ספריית לוגים ל Node.JS שיודעת לעשות שני דברים מאוד טוב: היא יודעת לשלוח את הלוגים שלכם להרבה סוגים של יעדים, והיא יודעת לפרמט את הלוגים שלכם בכל צורה שתבחרו. החיבור בין שני הדברים הוא קסום כי עם וינסטון אני יכול בקלות לכתוב את הלוגים לקונסול במצב פיתוח ולקובץ במצב ייצור, או גם לקובץ וגם לקונסול, או לשרת לוגים מרוחק בענן, וכל זה באמצעות שינוי קטן בקונפיגורציה. בואו נראה איך להתקין ולהשתמש בספריה. ## כמה דוגמאות לשמירת לוג עם Winston אני מתחיל בפרויקט Node.JS רגיל (ללא אקספרס) ומתקין את וינסטון עם:
$ npm install --save winston
עכשיו אפשר לכתוב קובץ demo1.js עם התוכן הבא:
const winston = require('winston');

const logger = winston.createLogger({
  level: 'debug',
  format: winston.format.simple(),
  transports: [
    new winston.transports.File({ filename: 'logs/dev.log' }),
    new winston.transports.Console(),
  ],
});

logger.info("Program Starts");

for (let i=0; i < 10; i++) {
  logger.debug(`Counting ... ${i}`);
}

logger.info("Program Ends");
זה היה פשוט נכון? אנחנו יוצרים לוגר שיקח את כל ההודעות החל מרמת debug (שזה כמעט כולן... היחידה שלא תישמר תהיה logger.silly) ויכתוב אותן גם לקובץ וגם לקונסול. התוכנית עצמה פשוט משתמשת בלוגר שיצרנו, ובעולם האמיתי נשמור את קוד יצירת הלוגר בקובץ משלו וכל מי שיצטרך את הלוגר יוכל להפעיל require לאותו קובץ. הפעלת התוכנית מדפיסה את הפלט הבא, וגם כותבת אותו לקובץ logs/dev.log:
info: Program Starts
debug: Counting ... 0
debug: Counting ... 1
debug: Counting ... 2
debug: Counting ... 3
debug: Counting ... 4
debug: Counting ... 5
debug: Counting ... 6
debug: Counting ... 7
debug: Counting ... 8
debug: Counting ... 9
info: Program Ends
אבל בינינו זה לא הלוג הכי אינפורמטיבי בעולם. בואו נוסיף Timestamp כדי לדעת מתי נכתבה כל הודעה:
const winston = require('winston');

const logger = winston.createLogger({
  level: 'debug',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.printf(({ level, message, timestamp }) => (
      `${timestamp} ${level}: ${message}`
    )),
  ),
  transports: [
    new winston.transports.File({ filename: 'logs/dev.log' }),
    new winston.transports.Console(),
  ],
});

logger.info("Program Starts");

for (let i=0; i < 10; i++) {
  logger.debug(`Counting ... ${i}`);
}

logger.info("Program Ends");
והפלט עכשיו:
2021-07-09T17:11:43.730Z info: Program Starts
2021-07-09T17:11:43.731Z debug: Counting ... 0
2021-07-09T17:11:43.732Z debug: Counting ... 1
2021-07-09T17:11:43.732Z debug: Counting ... 2
2021-07-09T17:11:43.732Z debug: Counting ... 3
2021-07-09T17:11:43.732Z debug: Counting ... 4
2021-07-09T17:11:43.733Z debug: Counting ... 5
2021-07-09T17:11:43.733Z debug: Counting ... 6
2021-07-09T17:11:43.733Z debug: Counting ... 7
2021-07-09T17:11:43.733Z debug: Counting ... 8
2021-07-09T17:11:43.733Z debug: Counting ... 9
2021-07-09T17:11:43.733Z info: Program Ends
פוקנציות הפורמט מגיעות מספריית logform ואפשר למצוא כאן רשימה של כל הפורמטים בספריה: https://github.com/winstonjs/logform ## חיבור וינסטון לאקספרס בפרויקט אקספרס כבר יש לנו מידלוור אחד שכותב לוגים - זהו מורגן. תשמחו לדעת שאין בעיה לחבר בין השניים, רק צריך לדעת לכתוב את שורת הקוד הנכונה. ניצור פרויקט אקספרס חדש ובתוכו אני יוצר קובץ בשם logger.js עם התוכן הבא:
const winston = require('winston');

const logger = winston.createLogger({
  level: 'debug',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.printf(({ level, message, timestamp }) => (
      `${timestamp} ${level}: ${message}`
    )),
  ),
  transports: [
    new winston.transports.File({ filename: 'logs/dev.log' }),
    new winston.transports.Console(),
  ],
});

logger.stream = {
  write(message) {
    logger.info(message);
  }
};

module.exports = logger;

ToCode
1 421
# איך לקרוא את כל התיעוד תיעוד של ספריה או כלי זו דרך מצוינת ללמוד על כל האפשרויות של הספריה, הרי בתיעוד טוב הכל כתוב. אם היה אפשר לקרוא את כל התיעוד ולהטמיע אותו בשיטת העבודה שלנו, הייתי יכול לכתוב קוד שמשתמש בספריה בדיוק בדרך בה התכוונו להשתמש בה. אבל החלום הזה קצת מזכיר את החלום של ללמוד שפה דרך קריאת מילון. כל המילים אולי כתובות שם, אבל אין שום דרך להבין ולהטמיע אותן רק מתוך קריאה. המוח האנושי לא עובד כך. המוח האנושי עובד בכיוון ההפוך: הוא מחפש בעיות ורק אחרי שיש לו בעיה הוא מחפש בשבילה פיתרונות. אחרי שפיתרון מסוים חוזר מספר פעמים לכמה בעיות שונות אנחנו מתחילים להטמיע אותו ומוכנים להשתמש בו גם בהקשרים חדשים, ולאט לאט מזהים באיזה מצבים צריך ולא צריך להשתמש באותו פיתרון. הבעיה? למצוא את הבעיות זאת עבודה מאוד קשה. הספריה שבחרתם ללמוד מטפלת בהמון מקרים של המון אנשים שונים. ספריות טובות נבנות לאורך שנים ומטפלות במקרים שנבנו בצורה אורגנית. דיווח אחרי דיווח, בקשת פיצ'ר אחרי בקשת פיצ'ר, ולפעמים גניבה ספרותית מספריות מקבילות. אנשים חכמים מאוד אספו בעיות של אנשים חכמים אחרים והטמיעו את הפיתרונות בתוך הספריה. מי שינסה למצוא לבד את הבעיות ולחפש רק פיתרונות עבורן הולך מהר מאוד להתאכזב: רוב החלקים בתיעוד יישארו בצל, כיוון שלא יהיו לנו בעיות מתאימות שיקחו אותנו אליהם. הפיתרון לכן הוא לא לקרוא את התיעוד אלא לנהל איתו דיאלוג. מתחילים בתיעוד, קוראים על יכולת או מנגנון בספריה, ואז סוגרים את התיעוד ומנסים לבנות לבד את המצב (הבעיה) שבגללו יכולת זו פותחה. את הבעיה שמישהו העלה שהביאה את כותבי הספריה לכתוב את החלק הזה בה. אחרי שיש לנו כיוון ראשון לבעיה אנחנו מתחילים "לשחק" עם הקוד, ומוצאים עוד בעיות שצריכות את אותו פיתרון (חייבות להיות, כי אף כותב ספריה לא יתאמץ להוסיף קוד בשביל לפתור בעיה שולית של איזה נודניק מהאינטרנט). בסופו של דבר אנחנו רוצים להגיע למצב שאנחנו מסוגלים לדקלם בעיות ומכירים את כל הפיתרונות "הקלאסיים" לבעיות אלה, כלומר הפיתרונות שאנשים השתמשו בהם לפני שאותה יכולת היתה חלק מהספריה. אנחנו רוצים להבין מה הבעיות בכל פיתרון ולמה היה חשוב להכניס פיתרון מובנה לספריה שעכשיו אנחנו לומדים. חיזרו על זה עם כל דף מהתיעוד ותראו שלא רק שאתם מצליחים לקרוא ולזכור, אחרי כמה שבועות אתם גם מבינים הרבה יותר טוב את הספריה וכל הדברים שהיא יכולה לעשות.