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

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

הדבר שלא עשית

31/10/2021

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

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

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

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

תרגיל אחד מספיק

30/10/2021

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

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

קסום.

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

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

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

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

29/10/2021

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

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

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

המשך קריאה

טיפ ריאקט: רינדור רשימות ארוכות

28/10/2021

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

המשך קריאה

פרודוקטיביות

27/10/2021

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

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

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

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

התמדה בימי קורונה

25/10/2021

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

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

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

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

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

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

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

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

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

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

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

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

למחוק!? ואם אצטרך את זה בעתיד?

24/10/2021

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

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

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

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

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

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

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

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

טיפ Node ו Docker - השתמשו ב wait-on כדי לחכות לקונטיינרים אחרים

23/10/2021

אחת הבעיות בעבודה עם קונטיינרים היא שהקונטיינרים כל הזמן עולים ויורדים. במיוחד אם אני משתמש ב 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();
    });
  });
});

וכמה אפליקציות יצאו מאז?

22/10/2021

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

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

אז עזבתי והמשכתי לעשות דברים אחרים.

ושנתיים אחרי, ב 2013, Nguyễn Hà Đông פירסם את פלאפי בירד וזכה להצלחה פנומנלית.

וב 2014 גבְּריאֶלֶה צ'ירולי פירסם את 2048 שהפך ללהיט ממכר.

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

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

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