שלום אורח התחבר

הבלוג של ינון פרק

טיפים קצרים וחדשות למתכנתים

מעדיפים לקרוא מהטלגרם? בקרו אותנו ב:@tocodeil

או הזינו את כתובת המייל וקבלו את הפוסט היומי בכל בוקר אליכם לתיבה:

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

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

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

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

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

  2. העלאת גירסה ב Zero Downtime Deployments.

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

  4. אבסטרקציה של Cron Jobs ומעקב אחרי הג'ובים שרצו או נכשלו.

  5. ניהול אוטומטי של "סודות".

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

סך הכל אחרי שמתרגלים העבודה עם קוברנטס היתה לי (ותהיה לכם) קלה יותר מאשר העלאת קונטיינרים ידנית לשרת או עבודה עם docker-compose.

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

https://www.tocode.co.il/workshops/107

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

נתראה בחמישי, ינון

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

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

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

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

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

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

קסום.

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

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

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

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

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

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

המשך קריאה...

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

המשך קריאה...

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

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

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

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

שאלה- האם צריך לבצע commit אחרי reset? מה יקרה אם נעשה? מה יקרה אם לא נעשה?

תשובה- זה תלוי. והנה הפירוט.

המשך קריאה...

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

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

למה זה קורה? ויותר חשוב, אם אתם מהאנשים שמתייאשים לפני הזמן, איך להפסיק את זה?

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

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

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

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

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

  4. כדאי לשריין זמן ספציפי לעבודה על הפרויקט שבו לא משנה איך אתם מרגישים אתם עובדים על הפרויקט הזה. וגם את הזמן הזה כדאי לחלק למשימות הקטנות יותר שמרכיבות אותו. לדוגמה: בכל בוקר מ 10 עד 11 אני לומד טכנולוגיה חדשה. פעם בשבוע אני משתתף במיטאפ. בכל יום אני משקיע שעתיים בין 11 ל 13 בעבודה על פרויקט קוד פתוח קיים (בהתחלה ללמוד את הפרויקט ואחרי זה להתחיל לפתור Issues עליו).

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

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

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

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

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

נו, אז בואו נדבר על כמה זה באמת עולה:

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

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

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

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

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

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

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

אני מקווה שאתם כבר מכירים את הסקריפט wait-for-it שגם מגיע עם דביאן וגם אפשר להוסיף בקלות להתקנה של כל קונטיינר ופותר בדיוק את הבעיה הזאת. ובכל מקרה אם המערכת שלכם כתובה ב Node.JS שווה להכיר שיש פיתרון יותר מוצלח שמשתלב באפליקציה והוא המודול wait-on.

מודול wait-on מאפשר לקבל רשימה של משאבים מכל מיני סוגים ויודע לחכות עד שכל המשאבים יהיו באוויר. הסוגים הנתמכים כוללים: קובץ, נתיבי רשת (http ו https), חיבור tcp וחיבור socket.

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

הנה דוגמה פשוטה לתוכנית Node.JS שמחכה ששרת redis יעלה על localhost ורק אז מתחברת אליו ומעלה ערך של מפתח בשם count:

const redis = require('redis');
const port = 3000;

const waitOn = require('wait-on');
const resources = [
  'tcp:localhost:6379'
];

waitOn({ resources }, () => {
  // here everything's ready
    console.log('ready!');

    const client = redis.createClient({
      port      : 6379,
      host      : 'localhost',
    });

  client.get('count', (err, count) => {
    if (err) return next(err);
    console.log(`count = ${count}`);
    client.incr('count', () => {
        client.quit();
    });
  });
});