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

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

טיפ JavaScript: עדכון פרמטרים של שורת כתובת

18/10/2022

כתובת אינטרנט יכולה להכיל פרמטרים אחרי סימן שאלה שמגיעים בפורמט של שם הפרמטר ואז סימן שווה ואז הערך שלו - למשל בכתובת הבאה יש שני פרמטרים בשמות foo ו bar עם הערכים 10 ו 20:

http://www.tocode.co.il?foo=10&bar=20

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

  1. פונקציית get שמקבלת שם של פרמטר ומחזירה את הערך הראשון שמקושר אליו

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

  3. פונקציית set שמעדכנת ערך של פרמטר ומשאירה רק מופע אחד שלו.

את שאר הפונקציות אפשר למצוא בתיעוד כאן: https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams

בעזרת אותן פונקציות אני יכול לשלוף ולהדפיס את הערכים של foo ו bar מהכתובת הקודמת:

const url = new URL("http://www.tocode.co.il?foo=10&bar=20");

> url.searchParams.get('foo')
'10'

> url.searchParams.get('bar')
'20'

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

> url.searchParams.set('foo', 'new value')
> url.searchParams.set('newKey', 12)

> url.toString()
'http://www.tocode.co.il/?foo=new+value&bar=20&newKey=12'

הדרך השניה

17/10/2022

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

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

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

אולי. אבל יש עוד אפשרויות-

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

אולי הדרך השניה באמת יותר טובה?

אולי היכרות עם עוד דרך תעזור לך להבין טוב יותר את הקוד של הדרך הראשונה?

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

ארבע טעויות נפוצות בשימוש ב useEffect

16/10/2022

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

המשך קריאה

רעיונות שלא בטוח עובדים

15/10/2022

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

הגיע הזמן שנתגבר על השקר הזה.

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

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

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

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

המשך קריאה

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

14/10/2022

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

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

האמת היא שהפריימוורק הוא לא העניין פה.

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

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

פריימוורק הוא לא הבעיה וגם לא הפיתרון.

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

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

המקום הנכון לתיקון

13/10/2022

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

וכן הזן של פייתון משקר. כשהם כותבים:

There should be one-- and preferably only one --obvious way to do it.

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

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

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

טיפ ריאקט: טיפול באירועים גלובאליים

12/10/2022

בריאקט מאוד קל לטפל באירועים ברמת הקומפוננטה - צריך רק להוסיף מאפיין on ושם האירוע. למשל בשביל לטפל באירוע keydown על אלמנט בתוך קומפוננטת ריאקט אני יכול לכתוב:

export default function App() {
  const [keys, setKeys] = useState("");

  function handleKeyDown(e) {
    setKeys(keys + e.key);
  }

  return (
    <div className="App" onKeyDown={handleKeyDown}>
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <p>{keys}</p>
      <input type="text" />
    </div>
  );
}

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

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

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

import { useEffect, useState } from "react";
import "./styles.css";

function GlobalKeyboardEvents({ onKeyDown }) {
  useEffect(() => {
    document.body.addEventListener("keydown", onKeyDown);
    return function () {
      document.body.removeEventListener("keydown", onKeyDown);
    };
  }, [onKeyDown]);
  return <></>;
}

export default function App() {
  const [keys, setKeys] = useState("");

  function handleKeyDown(e) {
    setKeys(keys + e.key);
  }

  return (
    <div className="App" >
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <p>{keys}</p>
      <input type="text" />
      <GlobalKeyboardEvents onKeyDown={handleKeyDown} />
    </div>
  );
}

ואפשר לשחק איתו לייב בארגז החול בקישור: https://codesandbox.io/s/frosty-violet-llfo2g?file=/src/App.js:0-711

מחשבות שמאטות אותי

11/10/2022

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

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

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

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

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

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

היום למדתי: איך לדבג תוכנית בקונטיינר אחר

10/10/2022

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

המשך קריאה

זהירות: סקריפטים בפרודקשן

09/10/2022

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

I am experiencing this breaking change, my production app is broken and unusable to my clients.

Me three. Prod is down. Got woken up here by confused users

It affected my app in production too, axios is not a function.

Confirmed as breaking production applications on my end as well. This is a big miss in testing coverage for a library like this.

Also having multiple broken production apps here.

Experiencing issues as well on production apps. Error: "axios is not a function"

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

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

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

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

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