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

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

חידת ריאקט: פוקוס

25/06/2021

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

import "./styles.css";

import React, { useRef, useState } from "react";

export default function Targil1(props) {
  const inputCount = 4;

  const [inputsText, setInputsText] = useState(new Array(inputCount).fill(""));

  const inputsRef = [];

  for (let i = 0; i < inputCount; i++) {
    inputsRef.push(useRef(null));
  }

  const containerDiv = {
    display: "flex"
  };

  function ChangeValueAndFocus(index, e) {
    inputsText[index] += e.key;

    inputsRef[(index + 1) % inputCount].current.focus();

    setInputsText([...inputsText]);
  }

  return (
    <div style={containerDiv}>
      {inputsText.map((item, index) => (
        <input
          value={item}
          key={index}
          autoFocus={index === 0 ? true : false}
          ref={inputsRef[index]}
          onKeyPress={(e) => ChangeValueAndFocus(index, e)}
        />
      ))}
    </div>
  );
}

וזה בקודסנדבוקס: https://codesandbox.io/s/tender-curie-ux3g5?file=/src/App.js

לדעת מה לחפש

24/06/2021

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

בקיצור מפה לשם אני מצלצל לגוגל לשאול איך יוצרים קובץ ב Github Action ויש מגיע לתוסף הזה: https://github.com/marketplace/actions/create-file.

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

    - name: Create file
      run: |
        echo First        > other.txt
        echo Second Line >> other.txt
        echo Third       >> other.txt

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

ניסיון מר

23/06/2021

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

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

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

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

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

בדיקת רכיב חיפוש פגישות ב Meetup

22/06/2021

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

  1. טופס החיפוש מורכב משני שדות Input, אחד עבור נושא האירוע והשני עבור המיקום

  2. בשדה הנושא אפשר לרשום כל מה שרוצים - הכל טוב.

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

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

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

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

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

def test_search_form(browser):
    browser.get(meetup_homepage_url)

    form = browser.find_element_by_tag_name("form")
    subject_input = form.find_element_by_id("search-keyword-input")
    subject_input.send_keys("hiking")

    location_input = form.find_element_by_id('location-typeahead-searchLocation')

    action = ActionChains(browser)
    action.move_to_element(location_input)
    action.click()
    action.send_keys("London, GB")
    action.pause(2)
    action.send_keys(Keys.DOWN)
    # Select location
    action.send_keys(Keys.ENTER)

    # Submit the form
    action.send_keys(Keys.ENTER)
    action.perform()

    assert browser.current_url == "https://www.meetup.com/find/?keywords=hiking&location=gb--greater-london--london&source=EVENTS"

שימו לב להגדרת המשתנה action ולבניה האיטית שלו: קודם הולכים לשדה ה Location, אחר כך לוחצים עם העכבר כדי להעביר את הפוקוס, אחר כך כותבים טקסט, מחכים שתי שניות (בשביל ה Ajax), ואז לוחצים חץ למטה, Enter ורק אז Enter נוסף כדי להגיש את הטופס. הפקודה action.perform היא זאת שמפעילה את השרשרת.

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

הפילוסופיה של יוניקס

21/06/2021

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

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

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

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

מבוא זריז ל Next.JS

20/06/2021

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

המשך קריאה

ללמוד עם הרגליים על הקרקע

19/06/2021

מאוד מפתה להסתכל על נושא עצום שאתה צריך ללמוד ולתכנן תוכניות שאפתניות, משהו כמו "אם אני רק אשב כל היום ללמוד אוכל להספיק בשלושה חודשים וקצת ללמוד את כל עולם ה Full Stack". ובאמת כשאנחנו מסתכלים על בוטקמפים ותוכניות הלימוד שלהם אנחנו רואים למשל תוכנית בת 16 שבועות בה לומדים MongoDB, Express, Node.JS, HTML, CSS, JavaScript ו React מאפס, וחושבים אוקיי, אני יכול לעשות את זה, אני רק צריך לשבת מספיק ברצינות.

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

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

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

עשר עצות להתנהגות מקצועית כלפי לקוחות (טיפ פרילאנס)

18/06/2021

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

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

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

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

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

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

  6. היו פתוחים לגבי הקשיים אבל אל תפילו אותם על הלקוח.

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

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

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

  10. הקדימו את הזמנים.

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

לא סתם קוראים לזה "החלק הקשה"

17/06/2021

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

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

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

הזמנה לוובינר: בדיקות בפרודקשן

16/06/2021

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

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

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

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

החסרונות של השיטה ברורים:

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

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

  3. הבדיקה מגלה את הבעיה מאוחר מדי, אחרי ה Deployment במקום לפניו.

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

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

מחר בעשר בבוקר אני וגבור סבו נעביר וובינר (באנגלית הפעם, כי גם לי מתחשק לגוון) על כתיבת בדיקות לאתר קיים והרצתן בסביבת פרודקשן. אנחנו מתכננים לקחת את אתר meetup.com, לבנות עבורו תוכנית בדיקות ולממש כמה שנספיק ממנה, וכמובן להריץ את הבדיקות משרת בדיקות נפרד דרך Github Actions. אם בא לכם להצטרף כצופים או לעזור לנו בכתיבה מוזמנים להירשם בקישור: https://code-maven.com/selenium-with-python-live.

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

נתראה, ינון.