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

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

למי אכפת מה Critical Rendering Path

18/06/2019

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

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

הנה דוגמא קצרה להמחשה - נניח שיש לנו קובץ HTML שנראה כך:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <link href="https://fonts.googleapis.com/css?family=Rubik&display=swap" rel="stylesheet">

        <title>Demo</title>
<style>
p { font-family: 'Rubik', sans-serif; display: none; }
</style>
    </head>
    <body>
    <script src="demo.js"></script>
    </body>
</html>

והוא טוען קובץ JavaScript בשם demo.js שנראה כך:

setTimeout(function() {
  const div = document.createElement('div');
  div.style.fontFamily = 'Rubik';
  div.textContent = "hello world";
  document.body.appendChild(div);
}, 1000);

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

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

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

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

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

אם אתם רוצים ללמוד יותר על Critical Rendering Path ולראות דוגמאות למציאתו ושיפורו באתרים אמיתיים מוזמנים להצטרף אליי ביום חמישי לוובינר של שעה בנושא. הרישום בקישור:

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

בביצועים צריך גם לדעת לוותר

17/06/2019

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

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

הנה דוגמא קצרה מהאתר היום - לאחרונה שמתי לב שלוקח לאתר המון זמן להיפתח. מבט מהיר בלוגים הראה שהבעיה במנגנון ה Server Side Rendering. זה המנגנון שגורם לזה שכשאתם פותחים דף באתר השרת ישלח לכם קובץ HTML תקני שייפתח גם אם ה JavaScript מבוטל אצלכם על המכונה. אני מאוד אוהב את הרעיון שהפוסטים נפתחים גם בלי JavaScript ומנגנון ה SSR היה תנאי סף מבחינתי לשילוב React במערכת. והנה המשחק של התקציב נותן את המכה שלו, כי עכשיו האפשרויות הן:

  1. למצוא למה SSR עובד לאט ולתקן אותו (לא בטוח שאפשר, בטוח שהחיפוש ייקח זמן).

  2. להוסיף מנגנון Caching בצד השרת לתוצאה של ה SSR (יעבוד אבל ייקח יותר זיכרון בשרת, ייקח זמן למימוש ואולי יביא בעיות אחרות)

  3. לוותר על SSR

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

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

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

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

הזמן הנכון ללמוד מונחים מקצועיים

16/06/2019

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

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

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

מחירים שלא רואים

15/06/2019

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

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

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

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

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

ידע שנשאר

14/06/2019

לפני עשרים שנה הייתי בראיון עבודה והתמודדתי עם שאלות בנושא SQL. זה היה בדיוק כמה ימים אחרי שקראתי את הספר "למד את עצמך SQL ב 24 שעות", או במילים אחרות לא ידעתי כלום. דמיינו כמה הייתי מופתע אם מישהו היה אומר לי אז באותו ראיון שעשרים שנה אחרי עוד אמשיך לעבוד ב SQL, ללמד SQL ולהתבלבל בין Outer Joins ל Inner Joins.

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

  1. הלינוקס שלמדתי בתיכון עדיין עוזר לי גם היום.

  2. ה SQL שלמדתי לפני עשרים שנה ממשיך להיות חלק בלתי נפרד מהחיים שלי כמתכנת.

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

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

פיתרון בעיות באמצעות אלגוריתם רקורסיבי

13/06/2019

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

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

המשך קריאה

הפעלת קוד בכל כניסה לתיקיה ב Bash

12/06/2019

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

$ rvm list

   ruby-2.0.0-p247 [ x86_64 ]
   ruby-2.1.2 [ x86_64 ]
   ruby-2.3.1 [ x86_64 ]
 * ruby-2.4.4 [ x86_64 ]
   ruby-2.5.0 [ x86_64 ]
=> ruby-2.6.3 [ x86_64 ]

# => - current
# =* - current && default
#  * - default

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

$ rvm use 2.1.2

ונוודא שאכן הגירסא הוחלפה עם:

$ ruby --version
ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-darwin13.0]

אז איפה הטריק? מסתבר שאם נשים בתוך תיקיה קובץ בשם .ruby-version, באופן אוטומטי בכניסה לתיקיה גירסת הרובי תשתנה כדי להתאים לקובץ זה. זה נראה ככה:

$ mkdir test
$ cd test
$ echo ruby-2.1.2 > .ruby-version
$ cd ..
$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin18]

$ cd test
$ ruby --version
ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-darwin13.0]

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

$ type cd
cd is a function
cd () 
{ 
    __zsh_like_cd cd "$@"
}

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

cd()
{
    echo "wow"
    cd "$@"
}

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

cd()
{
    echo "wow"
    builtin cd "$@"
}

החלק שאני הכי אוהב בפיתוח מערכת

11/06/2019

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

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

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

עשה ואל תעשה: איך להישאר בחיים אחרי ירידה בשכר

10/06/2019

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

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

המשך קריאה

השלוש דקות הכי טובות בקולונוסקופיה

09/06/2019

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

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

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

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

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

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