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

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

דבר אחד טוב

04/11/2020

בן אדם מחפש עבודה ורואה מודעה שאומרת:

דרוש/ה מתכנת/ת:

  1. שלוש שנות ניסיון בפיתוח NodeJS

  2. ניסיון משמעותי עם Angular/React/Vue

  3. ניסיון מעמיק עם Rest API

  4. ניסיון מעמיק עם AWS

  5. יתרון לניסיון עם Docker ו Kubernetes

ואז הבן אדם אומר לעצמו - טוב, אני יודע לכתוב Full Stack, כתבתי קצת Node ו React בתפקיד הקודם, נראה משרה בשבילי, אבל עדיין אני לא 100% עומד בדרישות, וגם בעבודה הקודמת שלי עבדתי רק שנתיים בפיתוח נוד. אני יודע! אני יכול לכתוב פרויקט שישתמש בכל הטכנולוגיות ברשימה ואז הם יראו כמה אני מוכשר ומיד יגייסו אותי.

ומכאן המצב רק מתדרדר.

כי אי אפשר לפתח לבד מערכת עם קוד צד-שרת ב Node.JS, צד לקוח ב React, תקשורת ב REST API (בעצם אם כבר אני בונה עכשיו משהו בשביל לעשות רושם אז מה פתאום REST עדיף GraphQL) ואז להעלות את כל זה ל AWS בתוך קונטיינרים. אפילו אם הייתם מכירים את הטכנולוגיות ברמה טובה. הדברים האלה לוקחים זמן ולוקחים צוות. בלי זה העבודה תצא חובבנית.

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

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

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

גאווה מקצועית, כישלון ותחושת כישלון

03/11/2020

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

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

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

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

קדימה ואחורה עם cal

02/11/2020

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

$ cal

   November 2020      
Su Mo Tu We Th Fr Sa  
 1  2  3  4  5  6  7  
 8  9 10 11 12 13 14  
15 16 17 18 19 20 21  
22 23 24 25 26 27 28  
29 30                 

יש גם אנשים מוזרים שאוהבים לראות את היומן שלהם מלמעלה למטה אז הם המציאו את ncal:

$ ncal

    November 2020     
Su  1  8 15 22 29   
Mo  2  9 16 23 30   
Tu  3 10 17 24      
We  4 11 18 25      
Th  5 12 19 26      
Fr  6 13 20 27      
Sa  7 14 21 28      

אבל בואו, אנחנו לא כאלה.

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

                            2020
      October               November              December        
Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa  
             1  2  3   1  2  3  4  5  6  7         1  2  3  4  5  
 4  5  6  7  8  9 10   8  9 10 11 12 13 14   6  7  8  9 10 11 12  
11 12 13 14 15 16 17  15 16 17 18 19 20 21  13 14 15 16 17 18 19  
18 19 20 21 22 23 24  22 23 24 25 26 27 28  20 21 22 23 24 25 26  
25 26 27 28 29 30 31  29 30                 27 28 29 30 31        

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

פיצ'ר שני שאני אוהב ב cal הוא היכולת להציג לוח שנה של כל חודש היסטורי או עתידי פשוט באמצעות בחירת החודש והשנה. הנה כמה דוגמאות:

$ cal 11 2019

   November 2019      
Su Mo Tu We Th Fr Sa  
                1  2  
 3  4  5  6  7  8  9  
10 11 12 13 14 15 16  
17 18 19 20 21 22 23  
24 25 26 27 28 29 30  

$ cal 11 1918
   November 1918      
Su Mo Tu We Th Fr Sa  
                1  2  
 3  4  5  6  7  8  9  
10 11 12 13 14 15 16  
17 18 19 20 21 22 23  
24 25 26 27 28 29 30  

$ cal 11 2250
   November 2250      
Su Mo Tu We Th Fr Sa  
                1  2  
 3  4  5  6  7  8  9  
10 11 12 13 14 15 16  
17 18 19 20 21 22 23  
24 25 26 27 28 29 30  

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

cal() {
  if [[ ("$1" = -* || "$1" = +*) && "$1" != -3 ]]
  then
    current_month=$(date +%m)
    current_year=$(date +%Y)
    month=$(( ($current_month + $1) % 12 ))
    year=$(( $current_year + $1 / 12 ))
    cal $month $year
  else
    command cal "$@"
  fi
}

ועכשיו אני יכול להעביר מינוס מספר או פלוס מספר כדי לראות את החודש שבא לפני או אחרי X חודשים (חוץ מ -3 אותה השארתי בהתנהגות ברירת המחדל):

$ cal -4

     July 2020        
Su Mo Tu We Th Fr Sa  
          1  2  3  4  
 5  6  7  8  9 10 11  
12 13 14 15 16 17 18  
19 20 21 22 23 24 25  
26 27 28 29 30 31     

$ cal +6

      May 2020        
Su Mo Tu We Th Fr Sa  
                1  2  
 3  4  5  6  7  8  9  
10 11 12 13 14 15 16  
17 18 19 20 21 22 23  
24 25 26 27 28 29 30  
31                    

שלום עולם Lua And LÖVE

01/11/2020

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

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

function love.load()
  x = 100 
  y = 100
  speedX = 5
  speedY = 5
end

function love.draw()
  love.graphics.setColor(255, 0, 0)
  love.graphics.circle("fill", x, y, 40)
end

function love.update()
  width, height = love.graphics.getDimensions( )

  if x + 20 == width or x - 20 == 0 then
    speedX = speedX * -1
  end

  if y + 20 == height or y - 20 == 0 then
    speedY = speedY * -1
  end
  x = x + speedX
  y = y + speedY
end

ב LOVE אנחנו מגדירים כמה פונקציות ו love תקרא להן כשהיא מוצאת לנכון. הפונקציה load נקראת כשהתוכנית מתחילה, הפונקציה update נקראת כל פעם שצריך להבין מה הדבר הבא שצריך לצייר והפונקציה draw נקראת כשצריך לצייר פריים חדש.

יכולים לראות מה הקוד עושה?

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

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

על החשיבות של useEffect בפיתוח ריאקט

31/10/2020

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

המשך קריאה

קריאות בשתי מילים

30/10/2020

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

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

feature "Clicking on the editable header will enter edit mode", %{session: session} do
    session
    |> visit("/")
    |> WallabyWorkflows.login("user@demoapp.com", "10203040")
    |> click(Query.css(".hero-main-header.editable"))
    |> assert_has(Query.css(".is-editing"))
end

אפילו בלי להכיר את אליקסיר קל מאוד להבין 3 מתוך 4 הפעולות בתוכנית הבדיקה פשוט בגלל השמות שלהן: visit כנראה שולחת את הדפדפן לנתיב מסוים, click כנראה לוחצת על אלמנט שמזוהה לפי השאילתה שעברה כפרמטר ו assert_has מוודא שאלמנט מסוים נמצא בעמוד. אבל מה עושה WallabyWorkflows.login?

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

הבעיה השניה היא שם הפעולה login. השם הזה לא עוזר לי להבין מה הקשר בין הפעולה לבין הפרמטרים שלה והמעבר מ login ל user@demoapp.com כאילו נקטע באמצע. שימוש בשם כמו login_as והעברת האימייל והסיסמה בתור Named Arguments יכולים לעשות הבדל גדול. סך הכל אחרי שינוי השורה נקבל:

feature "Clicking on the editable header will enter edit mode", %{session: session} do
    session
    |> visit("/")
    |> BrowserMacro.login_as(email: "user@demoapp.com", password: "10203040")
    |> click(Query.css(".hero-main-header.editable"))
    |> assert_has(Query.css(".is-editing"))
end

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

איך לכתוב בדיקות

29/10/2020

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

  1. מתי לכתוב את הבדיקה?

  2. מה לבדוק?

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

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

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

זאת שעושה פחות וזאת שעושה יותר

28/10/2020

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

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

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

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

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

זה כנראה לא היה המשרד

27/10/2020

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

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

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

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

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

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

לך בעקבות הריח

26/10/2020

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

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

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

שעה וקצת מאוחר יותר פתחנו את קוד הספריה מתוך תיקיית node_modules כדי למצוא בה את השורה:

export * from "./Components/Icon/Icon";

ו-בום.

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