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

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

קל לשנות

21/01/2022

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

  1. מימוש של פונקציה

  2. חתימה של פונקציה

  3. רשימת פונקציות או מחלקות שמיוצאות ממודול

  4. רשימת טבלאות ב DB ועמודות של כל טבלה

  5. רשימת API Routes והחלטה על הפרמטרים של כל נתיב

  6. פרוטוקולים לתקשורת בין מערכות (API ציבורי)

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

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

זה שמדבר

19/01/2022

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

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

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

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

בדיקות מחוץ לקופסה

18/01/2022

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

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

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

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

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

  5. בדיקות כדי לשפר נגישות - ספריות בדיקה כמו testing-library אבל גם סלניום יעבדו טוב יותר אם האתר נגיש, כי ספריית הבדיקה, כמו קורא מסך, צריכה לתקשר עם האלמנטים שעל המסך ורגישה הרבה יותר לקוד מאשר לעיצובים וצבעים. לא פעם קרה לי שהוספתי תווית טקסט או מאפיין aria-label רק בשביל שיהיה לי יותר קל לתפוס אלמנט מסוים בספריית הבדיקה.

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

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

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

טכניקות Refactoring לקוד ריאקט ששווה להתאמן עליהן

17/01/2022

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

  1. להעלות State לקומפוננטה עליונה (ולקבל אותו חזרה כ Props).

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

  3. להוציא State ל Context.

  4. להחזיר State מ Context לקומפוננטה עליונה, ולהעביר אותו למטה בתור Props לקומפוננטות הפנימיות.

  5. להוציא חלק מקומפוננטה לקומפוננטה חיצונית חדשה, כדי לפשט קומפוננטות מסובכות.

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

  7. להוציא החוצה לוגיקה + State ל Custom Hook.

  8. ליצור קומפוננטה חדשה מקומפוננטה קיימת כדי לקרוא ל Hook בצורה מותנית.

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

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

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

קריאה מודרכת בפונקציה groupBy מ lodash

16/01/2022

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

המשך קריאה

שאלות בלי תשובות

15/01/2022

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

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

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

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

והחיפוש לא דורש שתהיה תשובה בסוף.

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

14/01/2022

איך לא טיפלנו בזה כשזה רק התחיל? נו זה ברור-

  • בהתחלה זה לא נראה כזה ביג דיל

  • היה נדמה שתמיד אפשר לשנות בעתיד

  • רצינו לעלות לאוויר

  • רצינו להתקדם בפיצ'רים יותר חשובים

  • זה לא היה שווה את המאמץ

ועכשיו? עכשיו מאוחר מדי: יש כבר לקוחות שמכירים את כתובת ה IP שלנו ומסתמכים עליה; הנתונים ב DB כבר שמורים בצורה מסוימת ויש יותר מדי שורות בשביל להתחיל להעתיק לטבלה חדשה; הקוד כבר הועתק ברחבי המערכת; יש יותר מדי פיצ'רים ולא ברור איפה מתחילים לכתוב בדיקות.

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

משחקים עם Deta

13/01/2022

לא, זו לא שגיאת כתיב בכותרת - אכן יש מערכת ענן חינמית לגמרי בשם deta שכוללת גם בסיס נתונים וגם אפשרות לכתוב קוד ווב ב Python או Node.JS. הלכתי לשחק עם ה API שלהם כדי לראות מה אפשר לקבל בלי לשלם.

המשך קריאה

איך לשנות כללי ESLint ב create-react-app

12/01/2022

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

import { render } from '@testing-library/react';
import App from './App';

test('renders learn react link', () => {
  const screen = render(<App />);
  const linkElement = screen.getByText(/learn react/i);
  expect(linkElement).not.toBeInTheDocument();
});

על פני:

import { screen, render } from '@testing-library/react';
import App from './App';

test('renders learn react link', () => {
  render(<App />);
  const linkElement = screen.getByText(/learn react/i);
  expect(linkElement).not.toBeInTheDocument();
});

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

בתקופה האחרונה העדפה זו נהייתה קשה יותר לביצוע בגלל ש create-react-app כולל הגדרות eslint שממליצות בדיוק על ההיפך, כלומר על הגישה השניה. ההסבר שלהם כאן: https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/prefer-screen-queries.md

מה עושים? מתקנים את ה eslint כמובן. בתוך הקובץ package.json של פרויקט create-react-app חדש נוכל למצוא את הבלוק הבא:

  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },

כל מה שצריך לעשות זה לזהות את שם הכלל מתוך הודעת השגיאה או דף ההסבר על הכלל, במקרה שלנו הכללים הבעייתיים הם testing-library/prefer-screen-queries ו testing-library/render-result-naming-convention ואז מוסיפים בלוק rules ל package.json שמנטרל את שניהם:

  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ],
    "rules": {
      "testing-library/prefer-screen-queries": "off",
      "testing-library/render-result-naming-convention": "off"
    }
  },

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

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