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

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

מדריך קוד: בואו נכתוב משחק זיכרון ב Redux ו React

06/04/2022

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

המשך קריאה

שאלה של גישה

05/04/2022

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

ואז מצאתי את המשפט הבא בתיעוד של Redux Toolkit:

With RTK Query, you usually define your entire API definition in one place. This is most likely different from what you see with other libraries such as swr or react-query, and there are several reasons for that. Our perspective is that it's much easier to keep track of how requests, cache invalidation, and general app configuration behave when they're all in one central location in comparison to having X number of custom hooks in different files throughout your application.

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

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

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

הזמנה לוובינר: היכרות עם Solid.JS

04/04/2022

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

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

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

function useDocumentTitle(title) {
    useEffect(() => {
        document.title = title;
    }, [title]);
}

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

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

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

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

התוצאה היא פריימוורק שנראה דומה לריאקט אבל עובד אחרת לגמרי:

  1. הקומפוננטות הן פונקציות וקוד לשימוש חוזר הוא Custom Hook, אבל התלויות מזוהות בצורה אוטומטית ואין שום אילוץ להפעיל Hooks רק מתוך קוד של קומפוננטה.

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

  3. אין Virtual DOM ולכן יש הרבה פחות חשיבות (מבחינת ביצועים) לחלוקה נכונה לקומפוננטות.

  4. בהרבה מאוד מצבים נקבל ביצועים טובים יותר עבור קוד כמעט זהה.

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

אפשר להצטרף לוובינר בחינם בלחיצת כפתור בדף האירוע כאן: https://www.tocode.co.il/workshops/116

נתראה ינון

מהו useDeferredValue ולמה שיהיה לכם אכפת

03/04/2022

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

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

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

הקוד הבא ממחיש את ההתנהגות הרצויה תוך שימוש ב useDeferredValue:

export default function App() {
  const [search, setSearch] = useState("");
  const dsearch = useDeferredValue(search, { timeoutMs: 10000 });
  return (
    <div className="App">
      <input
        type="search"
        value={search}
        onChange={(e) => setSearch(e.target.value)}
      />
      <FilteredList search={dsearch} isPending={dsearch !== search} />
    </div>
  );
}

ואפשר לראות אותו בפעולה בקודסנדבוקס הבא:

קצת הסברים על הקוד:

  1. הסטייט search מייצג את הטקסט בתיבה; המשתנה dsearch הוא עותק של search שהאלמנטים שתלויים בו פחות חשובים.

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

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

עוד שתי סיבות טובות לחוב טכני

02/04/2022

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

הסיבות הקלאסיות לחוב טכני כוללות-

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

  2. כתיבת קוד ללא בדיקות או ללא תיעוד

  3. כתיבת קוד שלא מטפל במקרי שגיאה נפוצים

  4. אי שידרוג תלויות כשגירסאות חדשות יוצאות

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

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

המשך קריאה

פיבוט

30/03/2022

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

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

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

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

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

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

אפילו שזה רק שורה

28/03/2022

משמעות הקיצור DRY היא Don't Repeat Yourself, ובהקשר של קוד אנחנו מתכוונים לא לחזור על אותו קטע קוד שוב ושוב. אבל מה אם קטע הקוד הזה הוא שורה אחת?

המשך קריאה