ToCode
Ir al canal en Telegram
1 418
Suscriptores
Sin datos24 horas
-17 días
-430 días
Archivo de publicaciones
1 417
ברור אני רואה את הבאג
חיפוש באג עם AI הוא חוויה מעניינת. לא משנה מה אני עושה ה AI תמיד "רואה את הבאג" ותמיד יש לו רעיונות מופלאים איך לפתור את הבאג האמיתי או המדומיין שהוא ראה. ככה נראה החיפוש (ובסוף התיקון) שעשינו היום:
ניסיון ראשון - מצב שאלה
אני אוהב חיפושים בקוד במצב Ask כי ככה ה AI לא מתחיל לכתוב תיקונים לבאגים שהוא ממציא, אבל הבעיה במצב Ask היא שחייבים לספק ל AI את כל הקונטקסט. בניגוד ל Agent, במצב Ask הוא לא מחפש לבד. טוב בעיקר כשאתם יודעים איפה הבעיה.
הבאג שאני חיפשתי היה בעיה בבלוג שלפעמים כפתורי השיתוף פתחו את מסך השיתוף של לינקדאין או פייסבוק בטאב חדש, אבל קלקלו את הטאב הנוכחי ושינו את ה URL שלו למשהו מומצא. התחלתי במצב Ask עם קוד ה HTML של מסך השיתוף וקיבלתי המון רעיונות לא רלוונטיים.
ניסיון שני - מצב סוכן
ידעתי שהבאג קשור ל JavaScript כי הקישור כן נפתח בטאב חדש כמו שצריך, אבל עדיין לא ידעתי איפה בדיוק. בניסיון השני כבר חשבתי בגדול, ביקשתי ממצב Agent להסביר את כל ה JavaScript שיכול להשפיע על הלינק וגם הוספתי לקונטקסט את כל קבצי ה JavaScript של הפרויקט.
הוא בתגובה המשיך להמציא באגים אבל לא הגיע לתוצאה הנכונה.
ניסיון שלישי ופיתרון - הדבקת ה HTML מהדפדפן
הפיתרון בניסיון השלישי היה תוצאה של יותר מזל משכל. בשביל להוכיח ל AI שיש בעיה ב JavaScript הדבקתי את ה HTML של העמוד מהדפדפן לתוך הפרומפט. תראה, אמרתי לו, זה לינק תקין לגמרי הבעיה חייבת להיות ב JavaScript.
ואז ה AI ראה את מה שאני לא ראיתי בלינק:
<a href="https://www.linkedin.com/shareArticle?mini=true&url=http://localhost:3000/blog/demo-post-4&title=demo+post+4&summary=this+is+a+my+fourth+post+.....Hello+World%21" target="_blank" class="p-2 text-gray-600 transition-colors rounded-full hover:text-white hover:bg-[#0A66C2]" title="Share on LinkedIn" data-turbo="false" onclick="saAutomatedLink(this, 'outbound');">
אחרי ה URL מופיע מאפיין onclick שמפעיל פונקציית JavaScript שמדווחת ל SimpleAnalytics על אירוע לחיצה. אם לוחצים על הקישור לפני שהפונקציה מוגדרת דברים רעים קורים.
אפשר לדמיין כל מיני תיקונים אבל במקרה שלי ממילא רציתי להיפרד מ Simple Analytics אז ניצלתי את ההזדמנות והעברתי את האתר למערכת ה Analytics של קלאודפלייר (חינמית וממש נחמדה) והתקלה המשיכה למקום טוב יותר.1 417
טיפוסים חזקים ו AI
אין ספק ש AI אוהב מידע על טיפוסים. ההבדל בין הכותרת הזו לפונקציה בפייתון:
def count_lines(fp: typing.IO):
לפונקציה הזו:
def count_lines(fp: str):
מאוד ברור גם לבני אדם וגם ל AI ומאפשר ל AI לייצר את המימוש הנכון לכל כותרת. יותר מזה, כשאני מבקש מ Gemini להשלים מימוש של פונקציית פייתון שלא מכילה Type Hints הוא מוסיף לי אותם מיוזמתו.
במקביל אני מופתע לגלות שגם בשפות שלא כוללות Type Hints אני מקבל מימושים טובים וכמעט בלי בעיות טיפוסים. ב langlets יש לי כבר כ 2,500 שורות JavaScript וה AI מצליח להתמודד עם זה בלי טעויות. ב Ruby של הפרויקט הוא כן טועה אבל בעיקר כשאני כותב קוד מבלבל.
מה שמביא אותנו לשאלה - עד כמה חשובים טיפוסים חזקים בעידן ה AI? שאלתי את קלוד והוא העלה 3 מקרים חשובים בהם מערכת טיפוסים היא ממש קריטית להבנת הקוד:
1. קוד שמפותח לאורך שנים בסטנדרטים משתנים.
2. החלפת מפתחים בצוות (שגורמת לשינוי בסטנדרטים).
3. אינטגרציה בין מערכות.
במילים אחרות החוכמה הישנה חוזרת אבל בשינויים קטנים: אם אתם יכולים לשמור על סטנדרט גבוה של קוד ומוכנים לעשות Refactor לעתים קרובות (זה קל מאי פעם עם ה AI), להחזיק תיעוד מסודר ובדיקות בתוקף אז ל AI יהיה מאוד קל לעבוד על הפרויקט שלכם והוא לא יצטרך Strong Types. אתם ממילא לא כותבים את הקוד עצמו ולכן גם לכם לא יהיו טעויות בטיפוסים.1 417
השבוע בוובינר - שרתי MCP וחיבורם ל Copilot
בשבועות האחרונים עבדנו על פרומפטים וראינו כמה חשוב לנסח נכון את הפרומפט ואיך לבנות לאט לאט פרומפטים שעושים דברים גדולים.
אבל ההבטחה הכי גדולה של AI היום היא היכולת לחבר אותו לדברים בעולם. למעשה כשאנחנו משתמשים ב AI IDE כמו קופיילוט או קרסר אנחנו כבר מחוברים לדברים מסוימים בעולם: ה AI יכול לקרוא ולכתוב קבצים ולפעמים להפעיל פקודות. שרתי MCP הם הדרך להוסיף "יכולות" נוספות לאותו AI IDE. כל שרת MCP שנתקין מאפשר ל AI להשתמש בכלי נוסף כדי לענות על פרומפט שלנו.
לדוגמה שרת MCP של גיטהאב יאפשר ל AI לגשת למאגר בגיטהאב של הפרויקט ולהבין איזה Issues פתוחים יש כך שנוכל לבקש ממנו לתקן באג מסוים שכבר מפורט באותו Issue. שרת MCP של Playwright מאפשר ל AI להריץ דפדפן ולבצע פעולות בדף אינטרנט, שרת MCP של מנוע חיפוש יאפשר ל AI לחפש באינטרנט ו MCP של בסיס נתונים יאפשר ל AI לחטט בבסיס הנתונים כדי להבין איזה מידע גרם לבאג.
ביום חמישי בבוקר נעבור על מספר שרתי MCP, נתקין אותם לתוך ה Copilot ונראה באיזה מצבים הם יכולים לעזור לנו לקבל יותר מחברנו המלאכותי.
כמו תמיד המפגש בחינם ללא הקלטה, יתקיים ביום חמישי בעשר בבוקר ובשביל להצטרף צריך רק לכתוב את המייל בטופס בקישור ולינק לזום יישלח אליכם לתיבה:
https://tocode.ravpage.co.il/tocodeai
והחרוצים שביניכם שרוצים לבוא מוכנים מוזמנים לקרוא או לרענן פוסט שכבר כתבתי על MCP ואיך כותבים שרת MCP בפייתון בקישור הזה:
https://www.tocode.co.il/blog/2025-04-mcp-intro
נתראה בחמישי בבוקר.
1 417
className="px-6 py-3 rounded-xl text-white font-bold bg-gradient-to-br from-red-400 to-pink-500 hover:scale-105 active:scale-95 transition transform duration-200 shadow-lg"
>
- Decrease
</button>
<button
onClick={reset}
className="px-6 py-3 rounded-xl text-white font-bold bg-gradient-to-br from-yellow-300 to-orange-400 hover:scale-105 active:scale-95 transition transform duration-200 shadow-lg"
>
Reset
</button>
<button
onClick={increment}
className="px-6 py-3 rounded-xl text-white font-bold bg-gradient-to-br from-green-400 to-blue-500 hover:scale-105 active:scale-95 transition transform duration-200 shadow-lg"
>
+ Increase
</button>
</div>
</div>
</div>
);
}
export { useCounter };
ועכשיו ה Counter בעמוד השני יוכל להיות הרבה יותר מינימליסטי או עתידני או מה שנבחר ועדיין הלוגיקה לא תשתנה.
מבנה זה מתחבר לכח העל של ה AI לזהות תבניות ולשכפל אותן. במקום שיהיה לי קובץ CSS לאתר וכל HTML חדש אוטומטית יקבל את העיצוב מאותו קובץ CSS, עכשיו יש לי קומפוננטה ובשביל להשתמש בה בדף אחר באתר או באתר אחר אני עובר דרך ה AI
Create a \HomepageCounter\ component based on the existing \AboutpageCounter\ but matching the design to the home page.1 417
הרהורים על טיילווינד ועיצוב בתוך קומפוננטות
אחד הרעיונות שהיו פופולריים כשהתחלתי ללמוד HTML היה האפשרות להחליף עיצוב לחלוטין באמצעות שינוי CSS. זה המשיך ללוות אותנו לתוך האיפיון של CSS3 וגם למודולים חדשים יותר של CSS, כולל ובמיוחד במודולים של פלקסבוקס וגריד.
הגישה אז היתה שאפשר יהיה לכתוב קבצי CSS שונים כדי לייצר עיצובים מאוד שונים לאותה מערכת. השתמשנו ב JavaScript כדי לשנות קלאסים, אבל הגדרת העיצוב עצמה שהתאימה לקלאסים אלה הגיעה מקובץ CSS שאמור להיות קל לתחזוקה והחלפה.
אני מודה שזה לא ממש עבד. בהרבה אתרים שינוי עיצוב דרש גם שינוי במבנה ה HTML וראינו הרבה מעקפים כמו לכתוב את אותו קטע בעמוד פעמיים ב HTML ולהחליט מתוך CSS איזה מהם להציג. ובכל זאת היה משהו קסום בחלום הזה שאפשר יהיה לבנות Theme שונה למערכת רק באמצעות קובץ CSS.
היום עם ריאקט וטיילווינד נראה שזרקנו את החלום הזה לחלוטין. הנה קומפוננטת מונה לחיצות האהובה עליי:
import React, { useState } from "react";
export default function ShinyCounter() {
const [count, setCount] = useState(0);
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-r from-pink-400 via-yellow-300 to-purple-500">
<div className="bg-white bg-opacity-20 backdrop-blur-lg border border-white border-opacity-30 rounded-2xl p-10 shadow-2xl text-center">
<h1 className="text-5xl font-extrabold text-white drop-shadow-md mb-6">
Shiny Counter
</h1>
<div className="text-7xl font-bold text-white drop-shadow-lg mb-6">
{count}
</div>
<div className="flex gap-4 justify-center">
<button
onClick={() => setCount(count - 1)}
className="px-6 py-3 rounded-xl text-white font-bold bg-gradient-to-br from-red-400 to-pink-500 hover:scale-105 active:scale-95 transition transform duration-200 shadow-lg"
>
- Decrease
</button>
<button
onClick={() => setCount(0)}
className="px-6 py-3 rounded-xl text-white font-bold bg-gradient-to-br from-yellow-300 to-orange-400 hover:scale-105 active:scale-95 transition transform duration-200 shadow-lg"
>
Reset
</button>
<button
onClick={() => setCount(count + 1)}
className="px-6 py-3 rounded-xl text-white font-bold bg-gradient-to-br from-green-400 to-blue-500 hover:scale-105 active:scale-95 transition transform duration-200 shadow-lg"
>
+ Increase
</button>
</div>
</div>
</div>
);
}
אין איך לשנות לה את ה CSS כדי לקבל עיצוב אחר או להשתמש בה בעמוד אחר ושהיא תקבל את העיצוב מהעמוד. זאת הקומפוננטה. זה העיצוב שלה. Take it or leave it.
הגישה היום רואה את ה HTML, ה CSS וה JavaScript בתור יחידה אחת. בשביל לשנות את העיצוב עלינו לכתוב קומפוננטה אחרת. זה חלק מהחשיבות של הוצאת הלוגיקה ל Hook, כלומר בסיפור של ה Counter נוכל לכתוב:
import React from "react";
function useCounter(initialValue = 0) {
const [count, setCount] = React.useState(initialValue);
const increment = () => setCount(count + 1);
const decrement = () => setCount(count - 1);
const reset = () => setCount(initialValue);
return { count, increment, decrement, reset };
}
export default function ShinyCounter() {
const { count, increment, decrement, reset } = useCounter();
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-r from-pink-400 via-yellow-300 to-purple-500">
<div className="bg-white bg-opacity-20 backdrop-blur-lg border border-white border-opacity-30 rounded-2xl p-10 shadow-2xl text-center">
<h1 className="text-5xl font-extrabold text-white drop-shadow-md mb-6">
Shiny Counter
</h1>
<div className="text-7xl font-bold text-white drop-shadow-lg mb-6">
{count}
</div>
<div className="flex gap-4 justify-center">
<button
onClick={decrement}1 417
className="px-6 py-3 rounded-xl text-white font-bold bg-gradient-to-br from-red-400 to-pink-500 hover:scale-105 active:scale-95 transition transform duration-200 shadow-lg"
>
- Decrease
</button>
<button
onClick={reset}
className="px-6 py-3 rounded-xl text-white font-bold bg-gradient-to-br from-yellow-300 to-orange-400 hover:scale-105 active:scale-95 transition transform duration-200 shadow-lg"
>
Reset
</button>
<button
onClick={increment}
className="px-6 py-3 rounded-xl text-white font-bold bg-gradient-to-br from-green-400 to-blue-500 hover:scale-105 active:scale-95 transition transform duration-200 shadow-lg"
>
+ Increase
</button>
</div>
</div>
</div>
);
}
export { useCounter };
ועכשיו ה Counter בעמוד השני יוכל להיות הרבה יותר מינימליסטי או עתידני או מה שנבחר ועדיין הלוגיקה לא תשתנה.
מבנה זה מתחבר לכח העל של ה AI לזהות תבניות ולשכפל אותן. במקום שיהיה לי קובץ CSS לאתר וכל HTML חדש אוטומטית יקבל את העיצוב מאותו קובץ CSS, עכשיו יש לי קומפוננטה ובשביל להשתמש בה בדף אחר באתר או באתר אחר אני עובר דרך ה AI
Create a \HomepageCounter\ component based on the existing \AboutpageCounter\ but matching the design to the home page.1 417
הרהורים על טיילווינד ועיצוב בתוך קומפוננטות
אחד הרעיונות שהיו פופולריים כשהתחלתי ללמוד HTML היה האפשרות להחליף עיצוב לחלוטין באמצעות שינוי CSS. זה המשיך ללוות אותנו לתוך האיפיון של CSS3 וגם למודולים חדשים יותר של CSS, כולל ובמיוחד במודולים של פלקסבוקס וגריד.
הגישה אז היתה שאפשר יהיה לכתוב קבצי CSS שונים כדי לייצר עיצובים מאוד שונים לאותה מערכת. השתמשנו ב JavaScript כדי לשנות קלאסים, אבל הגדרת העיצוב עצמה שהתאימה לקלאסים אלה הגיעה מקובץ CSS שאמור להיות קל לתחזוקה והחלפה.
אני מודה שזה לא ממש עבד. בהרבה אתרים שינוי עיצוב דרש גם שינוי במבנה ה HTML וראינו הרבה מעקפים כמו לכתוב את אותו קטע בעמוד פעמיים ב HTML ולהחליט מתוך CSS איזה מהם להציג. ובכל זאת היה משהו קסום בחלום הזה שאפשר יהיה לבנות Theme שונה למערכת רק באמצעות קובץ CSS.
היום עם ריאקט וטיילווינד נראה שזרקנו את החלום הזה לחלוטין. הנה קומפוננטת מונה לחיצות האהובה עליי:
import React, { useState } from "react";
export default function ShinyCounter() {
const [count, setCount] = useState(0);
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-r from-pink-400 via-yellow-300 to-purple-500">
<div className="bg-white bg-opacity-20 backdrop-blur-lg border border-white border-opacity-30 rounded-2xl p-10 shadow-2xl text-center">
<h1 className="text-5xl font-extrabold text-white drop-shadow-md mb-6">
Shiny Counter
</h1>
<div className="text-7xl font-bold text-white drop-shadow-lg mb-6">
{count}
</div>
<div className="flex gap-4 justify-center">
<button
onClick={() => setCount(count - 1)}
className="px-6 py-3 rounded-xl text-white font-bold bg-gradient-to-br from-red-400 to-pink-500 hover:scale-105 active:scale-95 transition transform duration-200 shadow-lg"
>
- Decrease
</button>
<button
onClick={() => setCount(0)}
className="px-6 py-3 rounded-xl text-white font-bold bg-gradient-to-br from-yellow-300 to-orange-400 hover:scale-105 active:scale-95 transition transform duration-200 shadow-lg"
>
Reset
</button>
<button
onClick={() => setCount(count + 1)}
className="px-6 py-3 rounded-xl text-white font-bold bg-gradient-to-br from-green-400 to-blue-500 hover:scale-105 active:scale-95 transition transform duration-200 shadow-lg"
>
+ Increase
</button>
</div>
</div>
</div>
);
}
אין איך לשנות לה את ה CSS כדי לקבל עיצוב אחר או להשתמש בה בעמוד אחר ושהיא תקבל את העיצוב מהעמוד. זאת הקומפוננטה. זה העיצוב שלה. Take it or leave it.
הגישה היום רואה את ה HTML, ה CSS וה JavaScript בתור יחידה אחת. בשביל לשנות את העיצוב עלינו לכתוב קומפוננטה אחרת. זה חלק מהחשיבות של הוצאת הלוגיקה ל Hook, כלומר בסיפור של ה Counter נוכל לכתוב:
import React from "react";
function useCounter(initialValue = 0) {
const [count, setCount] = React.useState(initialValue);
const increment = () => setCount(count + 1);
const decrement = () => setCount(count - 1);
const reset = () => setCount(initialValue);
return { count, increment, decrement, reset };
}
export default function ShinyCounter() {
const { count, increment, decrement, reset } = useCounter();
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-r from-pink-400 via-yellow-300 to-purple-500">
<div className="bg-white bg-opacity-20 backdrop-blur-lg border border-white border-opacity-30 rounded-2xl p-10 shadow-2xl text-center">
<h1 className="text-5xl font-extrabold text-white drop-shadow-md mb-6">
Shiny Counter
</h1>
<div className="text-7xl font-bold text-white drop-shadow-lg mb-6">
{count}
</div>
<div className="flex gap-4 justify-center">
<button
onClick={decrement}1 417
3. יצירת דפי פעילות חדשים - אם תכנסו לאחד הקורסים בלאנגלטס תראו שהם מורכבים מדפי פעילויות מסוגים שונים כמו התאמת משפט לתרגום, הרכבת משפט מבנק מילים, התאמת מילים לתרגומים ועוד. בעבר השקעתי הרבה מחשבה בבניית אבסטרקציות כדי שאפשר יהיה לבנות "דפי פעילות" חדשים בקלות. זה היה מאתגר כי מצד אחד צריך קומפוננטות משותפות שנראות דומה (Design System אחיד) אבל מצד שני ההתנהגות של כל מסך יכולה להיות מאוד שונה. בעזרת AI אני יכול היום ליצור דפי פעילויות חדשים בפרומפט אחד וכמעט תמיד מקבל תוצאה טובה מהפרומפט הראשון. כל מה שצריך זה להדביק את הקוד של 3-4 דפי פעילויות ולבד ה AI מבין את התבנית, מה משותף, לפי איזה סטנדרטים כותבים את הקוד ומאיפה מגיע המידע. כן לכל דף יש את האתגרים שלו אבל היתרון שאני מצליח בכתיבת דף פעילות חדש לקבל בסיס ראשוני שנראה מעוצב לפי המבנה של המערכת ואז אני יכול להתמקד ב JavaScript וב CSS של אותו דף פעילות כדי לסדר אותו.
שורה תחתונה העבודה עם AI שונה בין הדברים הקשים לדברים הקלים:
1. בדברים הקשים, כמו שינויי ארכיטקטורה, ה AI מאפשר לי להשקיע יותר זמן בחשיבה ולהבין איפה אני רוצה כל חלק בפרויקט. הוא מאפשר לי לשנות את דעתי, לנסות מבנים שונים והשיחות ובניית הפרומפט והתוכנית זה חלק מתהליך ההבנה והחשיבה.
2. בדברים הקלים, ובעיקר פיתוח פיצ'רים בתוך עיצוב וארכיטקטורה קיימת, ה AI יכול לרוץ מאוד מהר ולתת מאות ואלפי שורות קוד שלא שוברים שום דבר. גם כשיש בהם באגים אותם באגים תחומים בתוך פונקציה או קלאס בודד ולא משפיעים על המבנה של כל המערכת.
הבנת ההבדל בין פיצ'רים קשים לקלים היא אחד המפתחות לעבודה יעילה עם AI ומימוש פיצ'רים מהר בלי לפגוע באיכות.
1 417
דברים ש AI עשה ממש טוב
בוובינר אתמול דיברנו על איך לגשת לשינויי ארכיטקטורה גדולים עם AI. ראינו כמה חשוב להשקיע זמן בלבנות תוכנית מראש בעזרת מצב Ask של ה AI, איך משפרים את התוכנית בעצמנו או בעזרת רעיונות של אותו AI ואיך בסוף הופכים אותה לתוכנית עבודה מסודרת, קובץ ארכיטקטורה ומימוש.
לקראת סוף הוובינר עלתה שאלה חשובה - אם אנחנו "מבזבזים" כל כך הרבה זמן באיטרציה על הפרומפטים ובמחשבה על כל פרט קטן, אולי היה עדיף לכתוב את השינוי הזה כבר ידנית?
חלק מהשינויים במערכת הם באמת שינויים קשים. הם דורשים החלטות כמו איזה טבלאות ועמודות חדשות נוסיף לבסיס הנתונים, איפה כל חלק בקוד ישב, באיזה מקרי קצה נרצה לטפל ואיזה מקרים פשוט לא מספיק חשובים והטיפול בהם רק יסבך את הקוד יותר מדי ושלא לצורך. איזה חלקים בקוד אנחנו רוצים לבנות בצורה שיהיה קל לשנות בעתיד ואיזה דברים אנחנו בטוחים שיישארו איתנו לתקופה ארוכה. החלטות זה לא הצד החזק של ה AI. הוא יכול לעזור לנו לראות את ההשלכות של כל החלטה, אבל כמעט באף מצב מעניין לא הייתי נותן לו להחליט.
רוב השינויים במערכת הם לא כאלה.
רוב השינויים במערכת הם שינויים המשכיים, שינויים שמתבססים על המצב הקיים ומרחיבים אותו: פיתוח פיצ'ר שלא משנה את איך שהמידע שמור בבסיס הנתונים, תיקון בעיית ביצועים שמתפרסת על עשרות או מאות קבצים, התקנת ספריית JavaScript חדשה ועדכון הקוד בכל האפליקציה להשתמש בה.
זה לא היה במסגרת הנושאים של הוובינר (אולי יתאים למפגש אחר), אבל הנה כמה פיצ'רים שבניתי ב langlets שבזכות ה AI לקחו הרבה הרבה פחות זמן ממה שהיו צריכים לקחת.
1. מסך בית שמציג גריד של קורסים - דף הבית של לאנגלטס מורכב מגריד של כל הקורסים במערכת. זה היה הפרומפט בשבילו:
Implement the courses#index page based on the attached HTML file, matching the design to our system #file:show.html.erb
List of courses in top row is taken from current_user.recommended_for_me. If the list is empty or user is not signed in do not show the first row
List of learning path in the second row is LearningPath.all
Use swiper js library to handle swiping (it's already installed in the project). Add a stimulus controller to handle the JS
When writing JavaScript use stimulus best practice that is data-target for element querying and data-action for events
Provide only filter by language (use course's language) for this one
Use our existing site's top bar for user authentication. Ignore the top bar in the provided HTML
Use only tailwind native classes
Design to integrate:
...
זה פרומפט ארוך ולא הדבקתי כאן את כולו כי סיימתי אותו ממש בדוגמת HTML/CSS שעיצבתי עם Gemini למסך בית מקביל, אבל שימו לב לעיקרי הדברים - הפרומפט לוקח דף קונספט בעיצוב שונה לגמרי מהמערכת שלי ואוטומטית מתאים את העיצוב לשאר הדפים במערכת, הוא משלב ספריית צד-לקוח בשם swiper וחוסך לי לחפש את ה API שלה. הפרומפט יצר קובץ HTML, קובץ JavaScript ושינה כמה קבצי רובי, שינוי של כמה מאות שורות סך הכל. אחרי ההרצה עדיין היו תקלות והייתי צריך להמשיך עוד כמה איטרציות של תיקונים ושיפורים אבל הארכיטקטורה של הפיתרון היתה נכונה מההפעלה הראשונה בגלל שדברים השתלבו במבנה הפרויקט הקיים.
2. התאמת עיצוב של כל דפי המשתמשים במכה אחת - התחברות, רישום ושכחתי סיסמה מציגים טופס שנראה מאוד דומה. כשמשנים משהו באחד מהם צריך לשנות אותו גם בדפים האחרים. בפרויקט שלי לא רציתי לכתוב אבסטרקציה לחלק המשותף כי יש סיכוי טוב שארצה לשנות חלק מהמסכים בלי להשפיע על האחרים. ה AI מתמודד עם השכפול בצורה מדהימה. ברגע שאני מבקש שינוי בטופס ומדביק ב Context של שלושת הדפים הוא משנה במכה אחת את שלושתם.1 417
חופש הפעולה של הטייס האוטומטי
הייתם נותנים לטייס אוטומטי לקבוע לאן צריך להגיע?
מה לגבי שינויים במסלול? הייתם נותנים לטייס אוטומטי להטיס את המטוס מדרך אחרת כי הוא חושב ששם יותר בטוח או שיש נוף יותר יפה?
במטוס חלוקת התפקידים בין הטייס האנושי לאוטומטי ברורה לכולם ומהווה Industry Standard. אצל מתכנתים כמו תמיד הסיפור יותר מורכב. אין לנו נוסעים, אין יעד מוגדר מראש ורוב הזמן אנחנו לא בטוחים בעצמנו מה המסלול הטוב ביותר. כן יש לנו טייס אוטומטי יצירתי שמוכן לבצע כל משימה שניתן לו, למרות שלא תמיד על הצד הטוב ביותר.
בשנים הקרובות אנחנו הולכים לבנות מערכת יחסים עם הטייס או הטייסים האוטומטיים שלנו. חלקם יעבדו בצורה אוטונומית לגמרי בתור "חברים בצוות" במסגרת מגבלות ויעדים שנציב מראש. חלקם יעבדו אתנו יותר מקרוב, יתרגמו את המחשבות שלנו לקוד ויאפשרו לנו לחקור רעיונות מהר יותר ולהתקדם בפיתוח מהר יותר. כבר היום אנחנו נאבקים למצוא את האיזון בעבודה עם AI IDEs, מבינים שאי אפשר לתת ל AI לקבל החלטות ומחפשים איך לעבור מרחקים גדולים יותר עם כל פרומפט.
הדרך להגדיר לטייס האוטומטי שלנו את היעד והמסלול היא כתיבת פרומפט, וגם פה בשונה מטייסים רגילים הפרומפט הוא דינמי, חסר פרטים רבים והרבה פעמים לא מצליח להעביר בדיוק את המסר שרצינו (במיוחד כשצריך לעבור מרחקים גדולים).
בוובינר היום אראה מספר פרומפטים שעוברים מרחק גדול. בכל פרומפט נבין את הארכיטקטורה של המערכת, את המשימה לביצוע ואיך לכתוב את הפרומפט כדי שגם ה AI יבין טוב את המשימה. בצורה איטרטיבית נלמד את הבעיות ואת אי ההבנות שיש בינינו לבין הטייס האוטומטי ולאט לאט גם איך לתקן אותן. נתלבט מתי כדאי להמשיך לכתוב פרומפט נוסף ומתי עדיף לקחת צעד אחורה ולשפר את הפרומפט הראשון ואיך לצמצם סיכונים להזיות ול Loop-ים. תחשבו על זה כמו Prompt Engineering מתקדם למתכנתים.
רוצים להצטרף? לא מסובך מלאו את המייל בתיבה בעמוד הבא ואשלח לכם את הקישור לזום במייל חוזר:
https://tocode.ravpage.co.il/tocodeai
נתראה בעשר.
1 417
היום למדתי: הפקודה sendBeacon ב JavaScript
בעיה נפוצה בשליחת אירועים מהדפדפן לשרת היא הציפיות שלנו. אנחנו רוצים לדווח לשרת כשמשתמש עוזב עמוד מסוים כדי לדעת כמה זמן משתמש בילה באותו עמוד, אבל המשתמש מעדיף באותו זמן לצאת מהדף ולא לחכות שנגמור לדווח לשרת שלנו ובטח לא לחכות לשרת שיחזיר תשובה.
דפדפנים נוטים לקחת את הצד של המשתמש בסיפור הזה וכשמנסים לשלוח fetch או XMLHttpRequest ביציאה מהעמוד הדפדפן פשוט לא ישלח את ההודעה. לפי התיעוד ב MDN אנשים השתמשו בכל מיני טריקים כדי לגרום לדפדפן להישאר עוד קצת בעמוד האהוב עליי היה ליצור אלמנט img שה src שלו הוא כתובת השרת לדיווח על יציאה.
פקודת
navigator.sendBeacon היא הדרך של יצרני הדפדפנים לעזור לשני הצדדים: גם לאפשר למפתחים לקבל אירועים כשמשתמשים עוזבים את העמוד וגם לאפשר למשתמשים לעזוב עמודים מהר בלי לחכות לדיווחי הסטטיסטיקות. כך זה עובד:
1. אנחנו מפעילים פקודת navigator.sendBeacon שחוזרת מיד בלי לחכות לבקשת התקשורת.
2. משתמש יכול להמשיך לעזוב את העמוד.
3. כשלדפדפן יהיה זמן הוא ישלח את הדיווח לאתר שלכם.
אם השרת שלכם מצפה לקבל מידע בפורמט JSON תוכלו להשתמש בקוד הבא כדי לשלוח את המידע מהדפדפן לשרת בלי לחכות לתשובה:
const url = 'https://example.com/collect';
const data = {
event: 'pageUnload',
timestamp: Date.now(),
userId: 'abc123'
};
// Convert the JSON object to a string
const jsonString = JSON.stringify(data);
// Convert the string to a Blob with the appropriate MIME type
const blob = new Blob([jsonString], { type: 'application/json' });
// Send the beacon
navigator.sendBeacon(url, blob);
הקוד שולח את המידע בתור blob בשביל לקבוע את ה content-type של הבקשה (מה שגורם לפריימוורק צד שרת בדרך כלל לפענח את ה JSON בצורה אוטומטית). אם זה לא חשוב לכם ואתם מוכנים לשלוח טקסט ולפענח את ה JSON בשרת בעצמכם תוכלו לכתוב גם:
navigator.sendBeacon(url, JSON.stringify(data));
והרבה פעמים תרצו להפעיל את זה כשמשתמש עוזב את העמוד ובשביל זה כדאי להתחבר לאירוע visibilitychange באופן הבא:
document.addEventListener("visibilitychange", () => {
if (document.visibilityState === "hidden") {
navigator.sendBeacon("/log", analyticsData);
}
});
¡Ya disponible! Investigación de Telegram 2025 — los principales insights del año 
