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

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

המיומנות הכי חשובה שחסרה ל Chat GPT

21/06/2023

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

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

כשאני אשאל איך לכתוב אימייל שימכור אני אקבל תשובה מפורטת, אפילו שאין לו מושג למי אני מנסה למכור ומה.

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

וכמובן שהתנהגות זו תימשך גם בכל שאלה טכנית.

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

היום הוא זמן טוב להתאמן על מיומנויות אלה.

איך להתקין k3s יחד עם ה Dashboard על multipass

20/06/2023

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

המשך קריאה

ומה אם לא תהיה לי עבודה?

19/06/2023

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

"מה אם לא אמצא לקוחות?"

"מה אם הלקוחות שאמצא לא ירצו לשלם?"

"מה אם ארוויח הרבה פחות ממה שאני רגילה להרוויח היום?"

"מה אם אצטרך לעשות משהו שונה ממה שקיוויתי שאעשה?"

"ומה אם לא אצליח לעשות דברים אחרת?"

"מה אם הרעיון שלי לא כזה טוב?"

"מה אם לא אמצא משקיע?"

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

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

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

זמן לצאת לרקוד.

חמישה בוטים לטלגרם שתוכלו לכתוב כפרויקט צד

18/06/2023

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

המשך קריאה

בול בפוני

17/06/2023

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

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

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

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

שילוב React Router Data API עם RTK Query

16/06/2023

אחד השילובים האהובים עליי בתקופה האחרונה הוא החיבור בין Data API של React Router ל RTK Query. בקצרה, ה Data API אומר שאנחנו יכולים להוציא את כל הלוגיקה של "מתי" מידע נטען מהשרת ל Router במקום שיישמר בקומפוננטות, ו RTK Query יודע למדל טוב את הלוגיקה של "איך" מידע נטען מהשרת. יחד הם שילוב מנצח כפי שנראה בפוסט הבא.

המשך קריאה

לחפש את ה"לא אפשרי"

15/06/2023

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

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

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

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

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

ובחזרה ל ES Modules - בדיוק בגלל שכל ה export-ים חייבים להיות זמינים בזמן קומפילציה דפדפנים יכולים לטעון מהר את התלויות גם בלי להריץ את הקוד. זה חלק מהכח של ES Modules שלא קיים ב CommonJS.

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

איך להתמודד עם FormData מתוך קוד Express

14/06/2023

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

המשך קריאה

צרות של ריאקטיביים

13/06/2023

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

עכשיו הבעיה שלהם הפכה להיות איך לזהות ש r/atom כזה השתנה, והתשובה היא ריקטיביות. בדומה ל Vue ועוד יותר ממנו ל Solid, גם ריאייג'נט מסתכל בזמן חישוב הקומפוננטה לאיזה אטומים ניגשו, ומחבר אותם לקומפוננטה כך ששינוי בערך האטום יגרום לחישוב מחדש של הקומפוננטה.

לכן הקוד הבא ל Counter עובד:

(defn counter []
  ;; run on init, skip on re-calculations
  (r/with-let [value (r/atom 0)]
    [:div
     {:style {:margin "10px"}}
     [:p (str "Value " @value)]
     [:button {:on-click #(swap! value inc)} "+"]
     [:button {:on-click #(swap! value dec)} "-"]]))

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

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

(defn textboxes []
  (r/with-let [value (r/atom "hello")]
    [:div
     (for [i (range 5)]
       [:input {:value @value
                :on-change (fn [ev] (reset! value (.. ev -target -value)))}])]))

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

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

התיקון הוא פשוט אחרי שמבינים את הבעיה - רק צריך להפוך את ה for מלולאה עצלה ללולאה מלאה עם doall והכל מסתדר:

(defn textboxes []
  (r/with-let [value (r/atom "hello")]
    [:div
     (doall
      (for [i (range 5)]
        [:input {:value @value
                 :on-change (fn [ev] (reset! value (.. ev -target -value)))}]))]))