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

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

מה השתנה

04/08/2024

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

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

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

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

פשוט תנו לי מספר שורה

03/08/2024

הפונקציה ROW_NUMBER של SQL מוסיפה מספרי שורות לתוצאות שאילתות, כך לפחות לפי שמה. אבל מספיק לנסות להריץ את השאילתה הבאה כדי להבין שיש פה משהו יותר עמוק:

SELECT *, ROW_NUMBER() from employees;

תגובת בסיס הנתונים תהיה משהו כמו:

SQLite3Error: SQLITE_ERROR: sqlite3 result code 1: misuse of window function ROW_NUMBER()

מה זה? למה misuse? ומה זה אומר window function? איזה חלון יש פה?

קל מאוד ללכת ל ChatGPT כדי שיתקן את השאילתה. הוא יחזיר את זה:

SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS row_num FROM employees;

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

ה Issue בגיטהאב שפתר לי את כל הבעיות

02/08/2024

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

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

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

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

איך עובד פרויקט Rails עם ESBuild

01/08/2024

החלום של DHH עבור ריילס הוא לוותר על ה Build Step ופשוט לשלב בדף ה HTML את הקישורים לסקריפטים באמצעות ES Modules. בזכות התמיכה של דפדפנים ב HTTP2 וב Import maps הסיפור הזה אפילו עובד די טוב בפרויקטי ריילס המסתמכים על JavaScript.

אבל כשאנחנו מוסיפים TypeScript וריאקט לתמונה העסק מסתבך ושלב בניה הופך הכרחי. גירסה 7 של ריילס שילבה ממשק סטנדרטי לבניית קבצי Front End שנקרא JS Bundling. מנגנון זה מאפשר לעבוד עם esbuild, webpack או rollup ולשלב אותם בתוך פרויקט ריילס. אבל מה שמיוחד ב JS Bundling בעולם של ריילס הוא שאין קובץ הגדרות אחד שעובד על כל הכלים ובמקום זה עלינו לבחור את אחד מהכלים ולבנות לו את קובץ ההגדרות בעצמנו. לפני כמה שבועות פרסמתי כאן מדריך שמסביר איך לשלב React ו TypeScript בפרויקט ריילס ושם הצעתי על הספריה vite-ruby. היום אני רוצה להראות מבנה פרויקט דומה אבל הפעם בעזרת esbuild ותוך שימוש ב JSBundling.

המשך קריאה

אם ?? כל כך יותר טוב, למה לא משתמשים בו יותר?

31/07/2024

אופרטור ?? ב JavaScript, או בשמו הרשמי Nullish Coalescing operator, הוא גירסה הגיונית יותר של ||. טוב לפחות הגיונית יותר לחלק משמעותי מהמצבים. עבור || הערך 0 נחשב ל"שקר" ועבור ?? הוא נחשב ל"אמת". זה אומר שעם || יש לנו:

> const items = [10, 20, 30, 40]
undefined
> const firstIndexOfTenOrFifty = items.indexOf(10) || items.indexOf(50)
undefined
> firstIndexOfTenOrFifty
-1

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

> const items = [10, 20, 30, 40]
undefined
> const firstIndexOfTenOrFifty = items.indexOf(10) ?? items.indexOf(50)
undefined
> firstIndexOfTenOrFifty
0

אז למה בכל זאת אנחנו כמעט לא רואים אותו בקוד? כמה רעיונות:

  1. אנחנו פחות מכירים ופחות רגילים להשתמש בתחביר חדש.

  2. אנחנו חוששים שאלה שיקראו את הקוד לא מכירים.

  3. אנחנו לא בטוחים באיזה דפדפנים הוא יעבוד (עובד בכל מקום).

  4. ממילא רוב הזמן אנחנו בודקים "או" בין ערכים בוליאנים, אז זה לא כזה משנה.

מה דעתכם? באיזו מידה אתם משתמשים בשני סימני השאלה? ולמה אתם לא משתמשים בו יותר?

אתה עוד תשלם על זה

30/07/2024

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

אלה הדברים שסיבכו אותנו עד עכשיו:

  1. כל מנגנון בניית ה JavaScript/CSS השתנה מאוד בריילס בשנים האחרונות. כשהפרויקט נכתב במקור לא היתה דרך סטנדרטית לשלב FrontEnd App עם קוד ריאקט ולכן כל פרויקט נראה אחרת.

  2. שימוש ב Composite Primary Keys בעבר לא נתמך בריילס. היום הוא כבר נתמך ולכן יש לעדכן את הקוד שיעשה שימוש במנגנון החדש (כי הפיתרון הישן נשבר).

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

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

ה Killer Feature החדש של node.js (או: האם זה הסוף של דינו?)

29/07/2024

לא רחוק היום בו נוכל להפעיל קבצי TypeScript ב node.js, כך לפי דיון בנושא בגיטהאב של נוד (כבר עובד ב Nightly). אלה הדגשים של הפיצ'ר:

  1. אין בדיקת טיפוסים בהרצה. זו אגב גם ההתנהגות של deno, באן וגם esbuild בפרונט אנד. הסיבה היא שאין טעם לבדוק טיפוסים לפני הרצה, ועדיף להשתמש בטיפוסים בתור טיפים ל IDE או לבדיקה יזומה כחלק מהרצת בדיקות או CI/CD.

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

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

שמות מועדים לפורענות

28/07/2024

הספריה swr משמשת למשיכת מידע מהרשת ביישום ריאקט. בשימוש הבסיסי הקוד עשוי להיראות כך:

import React from "react";
import useSWR from "swr";

const fetcher = (url) => fetch(url).then((res) => res.json());

export default function App() {
  const { data, error, isLoading } = useSWR(
    "https://api.github.com/repos/vercel/swr",
    fetcher
  );

  if (error) return "An error has occurred.";
  if (isLoading) return "Loading...";
  return (
    <div>
      <h1>{data.name}</h1>
      <p>{data.description}</p>
      <strong>👁 {data.subscribers_count}</strong>{" "}
      <strong>✨ {data.stargazers_count}</strong>{" "}
      <strong>🍴 {data.forks_count}</strong>
    </div>
  );
}

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

מה עושים? תשמחו לשמוע ש SWR מגיעה עם עוד פונקציה בשם המופלא useSWRImmutable. היא נועדה לפי התיעוד למקרים בהם המשאב (כלומר הדבר שאנחנו מקבלים מהשרת) לעולם לא משתנה, ולכן SWR לא ינסה אף פעם למשוך מחדש את המידע על דעת עצמו.

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

מה שאפשר לתקן

27/07/2024

לפי התפיסה הרווחת לגבי איכות של מתכנתים (נינג'ות, כפי שמכונים במודעות הדרושים) אלה הדברים שכדאי להסתכל עליהם כשאנחנו מגיעים להעריך מתכנת או מתכנתת:

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

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

  3. היכולת להיכנס לקוד, לתקן או להרחיב אותו בלי לשבור דברים קיימים.

  4. היכולת לזהות בעיות מהר.

  5. היכולת לבחור מבין מספר אלטרנטיבות את הפיתרון היעיל ביותר.

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

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

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

  3. המחויבות לחפש מקרי קצה ולטפל בהם, גם כשה Happy Path כבר כתוב.

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

  5. המחויבות לבנות תהליכים שיעזרו גם למתכנתים שיבואו אחרינו.

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

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

טיפ ריילס: איך לבדוק ש sprocket מותקן ועובד

26/07/2024

ספריית sprocket של ריילס אחראית על כל מה שקשור לעיבוד מראש של קבצי JavaScript ו CSS והכנתם לדפדפן. סוג של וובפאק שמשולב בקוד השרת. מאז ומעולם המנגנון הזה היה מסורבל ודרש המון קונפיגורציה, ובנוסף בגירסה 7 של ריילס הם הפכו את sprocket לאופציונאלי ושינו חלק מה APIs. ביישום ריילס חדש אין בעיה וכל ההגדרות נוצרות כמו שצריך מתוך ה Project Generator, אבל בשידרוג השרת עלול להחזיר נתיבים לא נכונים או לא לשים את הקבצים במקום שלהם, מה שגורם לתקלות מוזרות.

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

ynonp@Ynons-MacBook-Air ~/tmp/testrailsasaf/demo (main?) $ ./bin/rails c
Loading development environment (Rails 7.1.3.4)
3.1.1 :001 > ActionController::Base.helpers.asset_path('application.css')

 => "/assets/application-0cdd707d119a6e0b8c1eab9387d787586044421b4e95fbbb9e668e75c6d9fe6f.css"
3.1.1 :002 > ActionController::Base.helpers.asset_path('xyz')
(irb):2:in `<main>': The asset "xyz" is not present in the asset pipeline. (Sprockets::Rails::Helper::AssetNotFound)

הפונקציה מקבלת פרמטר אחד שהוא שם של קובץ Asset, שזה אפילו לא קובץ CSS אלא קובץ שמגדיר איזה קבצי css או scss צריך לטעון. זכרו ש sprocket מאחד את כל קבצי ה CSS לקובץ אחד (כי זה מה שהוא עושה), ואז הוא מוסיף Hash לשם הקובץ כדי שדפדפנים יוכלו לשמור את הקובץ ב cache. התוצאה של זה היא התוצאה של אותה asset_path. אם מפעילים את הפונקציה על שם שלא מתאים לקובץ הגדרות CSS מקבלים את השגיאה שה asset לא נמצא.

בעיות ב sprocket יגרמו או להחזרת אותו שם קובץ (בלי ה digest), להדפסת ערך אפילו בתגובה למחרוזות שלא מתאימות ל asset-ים או אפילו להתרסקות של ה ruby. רוב הזמן אפשר לסדר את הבעיות בעזרת שידרוג sprocket עצמו, שידרוג רובי או שידרוג Gem-ים אחרים בפרויקט.