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

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

שינוי גישה

25/07/2022

למרות כמה אילוצים של השפה, אין שום בעיה לכתוב קוד C בשפת Java; אין שום בעיה לכתוב בדיקות שלא בודקות כלום, גם עם 100% כיסוי קוד; וראיתי מספיק תוכניות jQuery שבמקרה כתובות בריאקט.

שינוי טכנולוגיה לא מבטיח שינוי גישה. זה שינוי הגישה שהוא המפתח לשינוי הטכנולוגי.

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

  1. בדיקות יחידה.

  2. קוד "גנרי" שכתבתי בשביל הגישה הישנה, אבל עכשיו רק מעכב אותי.

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

  4. והכי קשה - תפיסת עולם ודרכי עבודה שהיו נכונות בגישה הישנה אבל עכשיו כבר לא.

אפקטים וקוד איתחול בריאקט 18

24/07/2022

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

בגירסה 18 נראה שהמאמץ הזה הסתיים.

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

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

import React, { useEffect } from 'react';
import { StyleSheet, View, Text } from 'react-native';
import * as Brightness from 'expo-brightness';

export default function App() {
  useEffect(() => {
    (async () => {
      const { status } = await Brightness.requestPermissionsAsync();
      if (status === 'granted') {
        Brightness.setSystemBrightnessAsync(1);
      }
    })();
  }, []);

  return (
    <View style={styles.container}>
      <Text>Brightness Module Example</Text>
    </View>
  );
}

הקוד המקורי בקישור: https://docs.expo.dev/versions/v45.0.0/sdk/brightness/#brightnessrequestpermissionsasync

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

וזאת בדיוק ההנחה שנשברת בריאקט 18: הנחת העבודה של ריאקט 18 (והלאה) היא שקומפוננטות יכולות תמיד לצאת מהמסך ולהיכנס חזרה. ריאקט שומר לעצמו את הזכות להוציא ולהכניס קומפוננטות למסך כשזה יתאים לו, ומצב הפיתוח של ריאקט 18 מבהיר את זה כשב Strict Mode אוטומטית כל קומפוננטה עוברת unmount ואז שוב mount כשהיא נכנסת למסך.

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

הודעת השגיאה

23/07/2022

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

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

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

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

עבודה יפה בכיוון הלא נכון

22/07/2022

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

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

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

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

המשחק הוא התאמה - לבנות פיתרון יפה שלוקח בחשבון את הבעיה ומביא תוצאות.

לא שווה את המאמץ

21/07/2022

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

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

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

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

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

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

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

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

מה עושים עם התלויות של התלויות ב node

20/07/2022

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

{
  "name": "webapp-demo",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-select": "4.3.1"
  },
  "devDependencies": {
    "@types/react": "^18.0.15",
    "@types/react-dom": "^18.0.6",
    "@vitejs/plugin-react": "^2.0.0",
    "vite": "^3.0.0"
  }
}

אם תנסו לשים אותו בתיקיה ולהריץ npm install זה ייכשל, כי react-select גירסה 4.3.1 צריך את ריאקט 16 או 17, והפרויקט שלי משתמש בגירסה 18 של ריאקט. זאת הודעת השגיאה:

npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: webapp-demo@0.0.0
npm ERR! Found: react@18.2.0
npm ERR! node_modules/react
npm ERR!   react@"^18.2.0" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^16.8.0 || ^17.0.0" from react-select@4.3.1
npm ERR! node_modules/react-select
npm ERR!   react-select@"4.3.1" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR!
npm ERR! See /Users/ynonp/.npm/eresolve-report.txt for a full report.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/ynonp/.npm/_logs/2022-07-19T12_28_29_781Z-debug-0.log

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

מה שמביא אותנו לטריק של היום - המילה overrides. עם מפתח overrides אני יכול לשנות את הגירסאות של התלויות של התלויות שלי. בדוגמה שלנו נוסיף את המפתח ל package.json:

{
  "name": "webapp-demo",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-select": "4.3.1"
  },
  "devDependencies": {
    "@types/react": "^18.0.15",
    "@types/react-dom": "^18.0.6",
    "@vitejs/plugin-react": "^2.0.0",
    "vite": "^3.0.0"
  },
  "overrides": {
    "react-select": {
      "react": "18.2.0",
      "react-dom": "18.2.0"
    }
  }
}

והכל מותקן בשלום.

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

$ npm ls react

webapp-demo@0.0.0 /Users/ynonp/tmp/blog/webapp-demo
├─┬ react-dom@18.2.0
│ └── react@18.2.0 deduped
├─┬ react-select@4.3.1
│ ├─┬ @emotion/react@11.9.3
│ │ └── react@18.2.0 deduped
│ ├─┬ react-input-autosize@3.0.0
│ │ └── react@18.2.0 deduped invalid: "^16.3.0 || ^17.0.0" from node_modules/react-input-autosize
│ ├─┬ react-transition-group@4.4.2
│ │ └── react@18.2.0 deduped invalid: "^16.3.0 || ^17.0.0" from node_modules/react-input-autosize
│ └── react@18.2.0 deduped
└── react@18.2.0

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

טיפ לימודי: מתחילים לאט

19/07/2022

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

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

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

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

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

מה שמביא אותנו לגישה שניה, לא פחות יעילה, והיא להתחיל לאט:

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

  2. ביום השני רק להתקין את הכלים.

  3. ביום השלישי לבנות פרויקט חדש ולראות שרץ.

  4. ביום הרביעי לשנות משהו קטן בטמפלייט או להוסיף פיצ'ר קטן.

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

חדש באתר: עדכון תכני Redux ו React Router בקורס ריאקט

18/07/2022

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

את הקורס הקלטתי ב 2020 כש Hooks עוד היו דבר חדש, וכשעוד קיוויתי ש create-react-app לא באמת יתפוס.

מאז create-react-app תפס הרבה יותר מדי חזק, והיום אי אפשר לזוז בלעדיו. הוקס השתלטו על העולם והם הדרך הסטנדרטית לבנות ממשקים בריאקט, וריאקט ראוטר כרגיל עשה עוד re-write שלא תומך אחורה.

מה שמביא אותנו לעדכון האחרון-

  1. נוסף שיעור על create-react-app.

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

  3. פרק React Router הוקלט מחדש כדי להתאים ל React Router 6. אני רק מקווה שהחבר'ה שם יתעייפו לפניי מכל ה Breaking Changes שלהם.

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

פחד מכישלון

17/07/2022

זה גדול עליי

אין מצב שאני אצליח להבין את כל החומר

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

יותר מדי נושאים

בחיים לא אמצא זמן לזה

בחיים לא אהיה מספיק טוב כדי למצוא עבודה

עזוב אני לא בגיל ללמוד עכשיו תחום חדש


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

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

כמה זמן ייקח לך לכתוב טטריס?

16/07/2022

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

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

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

כל ההבדל בינך היום לבין הבן אדם שכותב טטריס בשעה הוא לשבת לכתוב טטריס עשר פעמים. אפשר להתחיל כאן: https://data-flair.training/blogs/python-tetris-game-pygame/