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

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

ארבעה שלבים בתהליך לימוד והקשיים במעבר ביניהם

27/02/2021

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

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

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

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

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

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

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

טיפ ריאקט וטייפסקריפט: תמיד בידקו קודם ש TS יודע מה הטיפוס

26/02/2021

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

export default function App() {
  const [data, setData] = React.useState();

  function handleClick() {
    setData({ value: _.random(10) });
  }

  return (
    <div className="App">
      {data && <p>Value is: {data.value}</p>}
      <button onClick={handleClick}>Randomize</button>
    </div>
  );
}

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

export default function App() {
  const [data, setData] = React.useState();

  function handleClick() {
    setData(_.random(10));
  }

  return (
    <div className="App">
      {data && <p>Value is: {data}</p>}
      <button onClick={handleClick}>Randomize</button>
    </div>
  );
}

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

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

export default function App() {
  const [data, setData] = React.useState<Record<string, any> | undefined>();

  function handleClick() {
    setData({ value: _.random(10) });
  }

  return (
    <div className="App">
      {data && <p>Value is: {data.value}</p>}
      <button onClick={handleClick}>Randomize</button>
    </div>
  );
}

היום למדתי: שליפת מידע מ JSON באמצעות JSON-ptr

25/02/2021

את xpath אני מכיר הרבה זמן אבל רק היום גיליתי שיש לו מקבילה וותיקה שתעזור לנו למשוך מידע בקלות מאוביקטי JSON. זה נקרא jsonptr וכבר יש עבורו מסמך איפיון של IETF שנקרא rfc6901 ומספר מימושים ב JavaScript ובשפות אחרות. בואו נראה איך זה עובד.

המשך קריאה

מה יותר מאובטח: סמס או משתמש וסיסמה?

24/02/2021

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

המשך קריאה

מתקפת הכלים

23/02/2021

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

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

import getConfig from 'next/config'
import Image from 'next/image'

// Only holds serverRuntimeConfig and publicRuntimeConfig
const { serverRuntimeConfig, publicRuntimeConfig } = getConfig()
// Will only be available on the server-side
console.log(serverRuntimeConfig.mySecret)
// Will be available on both server-side and client-side
console.log(publicRuntimeConfig.staticFolder)

function MyImage() {
  return (
    <div>
      <Image
        src={`${publicRuntimeConfig.staticFolder}/logo.png`}
        alt="logo"
        layout="fill"
      />
    </div>
  )
}

export default MyImage

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

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

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

ארבע עשרה דוגמאות לשאילתות SQL ב knex.js

22/02/2021

לאחרונה התחלתי לעבוד יותר ב knex.js בסביבת Node ובינתיים מאוד נהנה מהספריה והיכולות שלה. קנקס היא בעצם בונה שאילתות, קצת דומה ל Sequelize, רק שבמקום מבנה של ORM קנקס אימצה גישה יותר פתוחה ויותר קרובה ל SQL. הם לא מנסים להסתיר מכם את העובדה שאתם עובדים ב SQL, אלא לתת תחביר JavaScript קצת יותר גמיש במקום התחביר הטקסטואלי של SQL.

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

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

המשך קריאה

פייל

21/02/2021

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

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

  2. לא היה קהל - הפרויקט עלה לאוויר אבל אף אחד לא רצה להשתמש בו.

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

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

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

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

יכול וצריך

20/02/2021

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

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

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

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

תוכנית תשעת השלבים בכניסה לקוד קיים

19/02/2021

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

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

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

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

  3. מריץ את הבדיקות (כן אני יודע אני אופטימי שיש בדיקות אוטומטיות).

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

  5. נכנס למערכת בתור משתמש רגיל ומשחק עם הכפתורים

  6. כותב בדיקה חדשה ל Flow שגיליתי כששיחקתי עם המערכת (זה לא משנה אם כבר קיימת בדיקה ל Flow הזה. לא חייבים לעשות קומיט).

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

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

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

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

קומפוננטה משולשת

18/02/2021

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

function MyTripleComponent(props) {
  const { text } = props;

  if (text === 1) {
    return <p>Hello</p>;
  } else if (text === 2) {
    return <p>Bye bye</p>;
  } else {
    return <p>I don't understand</p>;
  }
}

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

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

function MyTripleComponent(props) {
  const { type } = props;

  if (type === 1) {
    const [text, setText] = React.useState("");

    return (
      <label>
        <input
          type="text"
          value={text}
          onChange={(e) => setText(e.target.value)}
        />
        {text}
      </label>
    );
  } else if (type === 2) {
    return <p>Bye bye</p>;
  } else {
    return <p>I don't understand</p>;
  }
}

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

Rendered more hooks than during the previous render.

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