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

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

מהי Callback Function ולמה שבכלל יהיה לכם אכפת ממנה?

״רוצה לכתוב לי את זה כאן?״ ״לא עזוב זה ארוך... אתקשר אליך בערב״

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

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

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

בואו נפרק את זה כדי לראות את המבנה:

function myCallbackFunction() {
  $('p').text('Thanks!');
}

$('button').on('click', myCallbackFunction);

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

  1. הפונקציה on מקבלת שני פרמטרים: הראשון הוא שם האירוע והשני הוא ה Callback Function. אפשר לחשוב על זה כאילו בהפעלת הפונקציה on ביקשנו מידע - וזה באמת יהיה נכון. ביקשנו לדעת מי לחץ על הכפתור. הבעיה היחידה היא שאף אחד עדיין לא לחץ על הכפתור. לכן אני מעביר את פונקציית ה״צלצל אליי בערב״, או בשמה המקצועי את ה Callback Function. כשמישהו ילחץ על הכפתור הפונקציה on תתעורר ותפעיל את פונקציית ה Callback שלי.

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

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

והנה הקוד המפורק מתוכו:

function myCallback(data) {
  $('pre').html(JSON.stringify(data));
}

$.get('https://swapi.co/api/people/1', myCallback);

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

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

function getHairColor(id) {
  function myCallback(data) {
    $('pre').html(data.hair_color);
  }

  $.get(`https://swapi.co/api/people/${id}`, myCallback);
}

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

const hairColor = getHairColor(1);
alert("Luke's hair color is ", hairColor);

אני מקווה שעכשיו אתם כבר רואים שזה לא הולך לעבוד. הפונקציה getHairColor מחזירה את הערך לפני שהיא סיימה לקבל את המידע ב Ajax. בשביל להציג את צבע השיער מבחוץ אנחנו צריכים לשנות את המבנה שלה כך שהיא תקבל Callback Function. בדיוק כמו on. בדיוק כמו get.

הנה דרך אחת בה זה יכול לעבוד:

function getHairColor(id, fn) {
  function myCallback(data) {
    fn(data.hair_color);
  }

  $.get(`https://swapi.co/api/people/${id}`, myCallback);
}

getHairColor(1, function(hairColor) {
  alert(hairColor);
});

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

איך (ולמה) לכתוב React Hook

17/03/2019

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

נודה על האמת הפונקציה React.createClass היתה סוג של פשרה מהיום הראשון. הרי אם היו class-ים ב JavaScript כשריאקט התחילה כנראה לא היו צריכים לכתוב אותה. לפונקציה זו מקבילה בהרבה ספריות UI אחרות ישנות יותר כמו למשל Class.create של פרוטוטייפ או declare של dojo.

אבל משהו מאוד גדול הלך לאיבוד במעבר מ React.createClass ל class המודרני, ולמשהו הזה קוראים Mixins. מיקסינס הפכו במעבר למחלקות למבנה שנקרא Higer Order Components שהיה הרבה פחות אינטואיטיבי לרוב המפתחים. בפוסט היום ניזכר יחד מה היו מיקסינס, איך HoC אמורים היו להחליף אותם ומה Hooks מצליחים לעשות טוב יותר. מוכנים?

המשך קריאה

לא מה שחשבת

16/03/2019

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

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

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

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

תתחילו עם המחיר

15/03/2019

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

אבל האמת שעדיף ללכת הפוך: אני רוצה להרוויח X ש"ח בחודש; מה מעצבים גרפיים שמרוויחים את הסכום הזה עושים? איך הם הגיעו לאן שהם הגיעו? נשמע שכדאי ללכת באותו כיוון.

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

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

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

כשה API לא מסתדר עם האינטואיציה

14/03/2019

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

function Counter() {
  let [count, setCount] = useState(0);

  useEffect(() => {
    let id = setInterval(() => {
      setCount(count + 1);
    }, 1000);
    return () => clearInterval(id);
  }, []);

  return <h1>{count}</h1>;
}

ה Counter בפקד נעצר ב-1.

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

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

import React, { useState, useEffect, useRef } from 'react';

function Counter() {
  let [count, setCount] = useState(0);

  useInterval(() => {
    // Your custom logic here
    setCount(count + 1);
  }, 1000);

  return <h1>{count}</h1>;
}

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

כל מה שרציתם לדעת על Git Rebase ולא ידעתם את מי לשאול

13/03/2019
git

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

המשך קריאה

במורד מחילת הארנב

12/03/2019

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

וזה יכול להימשך שעות. אפילו ימים.

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

ההבדל בין להבין ללדעת

11/03/2019

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

https://www.youtube.com/watch?v=qs0b2t8SM88&t=647s

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

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

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

אנטי-תבניות שלמדתי בבית ספר

10/03/2019

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

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

המשך קריאה

בואו נלמד לתכנת כמו שהייתם לומדים לרכב על אופניים

09/03/2019

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

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

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

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

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