לדלג לתוכן

3.2 כתיבת פיצ'ר מקצה לקצה הרצאה

עד עכשיו למדנו איך להשתמש בagent כדי להתמצא בקוד קיים. עכשיו נעבור לשימוש היומיומי המרכזי: לגרום לו לכתוב פיצ'ר חדש, מהבקשה הראשונה ועד קוד שעובד ועבר בדיקות. זו לא פקודה אחת - זו זרימת עבודה שלמה, ומי שמנסה לדחוס אותה לפרומפט יחיד ("תוסיף לי פיצ'ר X") בדרך כלל מקבל קוד שנראה סביר אבל מפספס פרטים שהיו ברורים לו אבל לא הועברו לagent. בהרצאה הזו נבנה זרימה מסודרת: תיאור המטרה, תכנון, יישום בצעדים, סקירת diff, והרצת בדיקות - עם דוגמה מלאה שנעקוב אחריה מקצה לקצה.


למה לא לבקש הכל בבת אחת

הפיתוי הראשון הוא לכתוב פרומפט ארוך שמתאר את כל הפיצ'ר, וללחוץ Enter. זה עובד לפיצ'רים קטנים מאוד. אבל ברגע שהפיצ'ר נוגע ביותר משכבה אחת - למשל גם ב-API, גם בלוגיקה עסקית, גם ב-DB - הagent צריך לקבל החלטות עיצוב (design decisions) שאתם לא ניסחתם במפורש, והוא יקבל אותן לבד, במהירות, בלי לעצור ולשאול. לפעמים ההחלטות טובות. לפעמים הן סותרות משהו שכבר קיים בקוד, או פשוט שונות ממה שהייתם רוצים.

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

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


שלב 1: תיאור המטרה - describing the goal

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

> I want to add the ability to export orders to CSV. The user will hit
  GET /orders/export?from=2026-01-01&to=2026-01-31 and get a CSV
  file with all their orders in the date range. Use the same auth
  layer that already exists on the rest of the /orders routes. Don't add
  a new CSV library if there's already one in package.json.

שימו לב לפרטים: יש נתיב מדויק, פורמט פרמטרים, הפניה מפורשת לאילוץ קיים (auth), והנחיה שמונעת מהagent להוסיף תלות (dependency) מיותרת. ככל שהמטרה מדויקת יותר, כך פחות מקום לניחושים.


שלב 2: תכנון לפני קוד - planning before code

לפני שנותנים לagent לגעת בקבצים, שווה לבקש תכנית. ב-Claude Code זה קורה טבעי דרך מצב התכנון (plan mode) שלמדנו בפרק הקודם, אבל גם בלי מצב מיוחד אפשר לבקש זאת במפורש:

> Before you write code, give me a plan: which files you'll create or
  change, what will happen in each one, and what open questions you have for me.

תגובה טובה נראית כך:

Plan for implementing CSV export:

1. src/api/routes/orders.ts
   - add a new route: GET /orders/export
   - placed before /orders/:id so it doesn't get confused with the dynamic parameter

2. src/api/controllers/orderController.ts
   - new function exportOrders: reads query params,
     calls orderService.findByDateRange, converts to CSV

3. src/services/orderService.ts
   - new function findByDateRange(userId, from, to)

4. use the csv-stringify library - it's already in package.json
   (found in use in src/reports/weeklyReport.ts)

Open questions:
- If from/to are missing, is the default the entire history or a 400 error?
- Which exact columns should appear in the CSV?
- Is there a result size limit (pagination) that needs to be respected here too?

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

> If from/to are missing - a 400 error with a clear message. Columns:
  id, created_at, total, status. No need for pagination,
  the assumption is that the range won't be huge.

שלב 3: יישום בצעדים - incremental implementation

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

> Implement only the first step (the findByDateRange service) and stop.
  I want to see it before we continue to the controller and the route.

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


שלב 4: סקירת diff - reviewing the diff

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

$ git diff --stat
 src/api/controllers/orderController.ts | 24 ++++++++++++++++++++++++
 src/api/routes/orders.ts               |  2 ++
 src/services/orderService.ts           | 14 ++++++++++++++
 3 files changed, 40 insertions(+)
> Show me a full diff of all the changes, file by file, with a brief
  explanation of why each change is needed.

בסקירה, שאלות שכדאי לשאול את עצמכם (ולפעמים גם את הagent):

  • האם ה-route החדש ממוקם לפני /orders/:id? אם לא, Express ינתב /orders/export לתוך ה-handler שמצפה ל-id, וזה יישבר בשקט.
  • האם השאילתה ל-DB מסננת גם לפי userId, לא רק לפי טווח תאריכים? זו בדיוק הנקודה שקל לפספס - פיצ'ר export הוא מקום קלאסי לדליפת נתונים בין משתמשים אם השאילתה לא מכבדת הרשאות.
  • האם הטיפול בשגיאת ולידציה (400 כש-from/to חסרים) באמת קיים, או שהagent שכח אותו?
> Show me exactly where in the code you wrote it's verified that
  from/to are valid, and 400 is returned if not.

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


שלב 5: הרצת בדיקות - running tests

קובץ diff שנראה נכון עדיין לא אומר קוד שרץ. מבקשים מהagent להריץ את חבילת הבדיקות, ואם אין בדיקות רלוונטיות לפיצ'ר החדש - לכתוב אותן (נרחיב על כתיבת בדיקות בהרצאה 3.5):

> Run the existing test suite and show me the full output. If
  there's no test for the new route, write one: a valid call returns
  CSV with the correct rows, missing from/to returns 400, and a user
  cannot see another user's orders.
$ npm test -- orders.export

 PASS  src/api/__tests__/orders.export.test.ts
  GET /orders/export
    PASS: returns CSV with the orders in range (42 ms)
    PASS: returns 400 when from/to are missing (8 ms)
    PASS: does not return another user's orders (15 ms)

Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total

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


בחירה בין כמה גישות מימוש - choosing among design options

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

> There are a few ways to implement the CSV export: (1) fetch all
  the orders into memory and convert to CSV at once, or (2) use
  streaming - write row by row while fetching from the DB.
  Give me a comparison table: pros, cons, and when each approach
  fits better in the context of this project.

תשובה טובה תיראה בערך כך:

| Criterion         | Full load to memory      | Streaming               |
|--------------------|---------------------------|--------------------------|
| Code simplicity    | High - easy to write      | Medium - requires        |
|                    | and test                  | handling the data flow  |
| Memory usage       | Grows with order count    | Constant, independent   |
|                    |                           | of the amount            |
| Fits when...       | Short date range,         | Long ranges, possibly    |
|                    | reasonable order count    | thousands of orders      |

In this project: there's no pagination limit on the range (as agreed
in planning), meaning a user can request a full year. Full load
into memory could be problematic in that case. Recommend streaming,
even though it adds a bit of complexity.

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

> Is there already another endpoint in the project that generates a
  downloadable file (not JSON)? If so, implement this export in the exact same pattern.

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


דוגמה מלאה: מקצה לקצה - the full worked example

בואו נראה איך זה נראה ברצף אחד, כפי שהיה קורה בפועל:

1. > [Goal] I want to add the ability to export orders to CSV...

2. > [Planning] Before you write code, give me a plan...
   < [agent returns a plan with open questions]

3. > [Answers] If from/to are missing - a 400 error...

4. > Implement the full plan.
   < [agent writes 3 files]

5. > Show me a full diff, file by file, with an explanation for each change.
   < [review - we find that the query doesn't filter by userId!]

6. > Note - findByDateRange doesn't take userId and doesn't filter by it.
   Fix it, and add a test that verifies a user can't see another user's orders.
   < [agent fixes it, adds the parameter, adds a test]

7. > Run the entire test suite (not just the new ones) and show me
   that nothing broke.
   < [all tests pass]

שימו לב לצעד 6: זה בדיוק הרגע שבו סקירת diff תפסה בעיה אמיתית - שכחת סינון לפי משתמש, שהיא באג אבטחתי קלאסי (broken access control). אם היינו מדלגים על שלב הסקירה ורצים ישר להרצת בדיקות, סביר שהבדיקות שהagent היה כותב מלכתחילה גם הן היו "שוכחות" לבדוק את התרחיש הזה, כי הן נכתבו מאותה הנחת יסוד שגויה.


מלכודות נפוצות

מלכודת איך מתגלה מה לעשות
דילוג על שלב התכנון בפיצ'ר גדול הagent כותב קוד שסביר אבל מבנה שונה ממה שציפיתם תמיד לבקש תכנית לפני יישום בפיצ'רים שנוגעים ביותר משכבה אחת
קבלת "בוצע" בלי diff לא רואים בעצמכם מה השתנה בפועל לבקש git diff ולעבור שורה-שורה, לא להסתפק בתיאור מילולי
בדיקות שנכתבו מאותה הנחה שגויה כמו הקוד הבדיקות עוברות אבל לא מכסות את המקרה הקריטי (כמו הרשאות) לדרוש במפורש בדיקות לתרחישי אבטחה/גבול, לא רק ל-happy path
התעלמות משאלות פתוחות של הagent הagent מנחש ומחליט לבד, לפעמים שגוי לענות במפורש על כל שאלה שהagent שואל בתכנית לפני שממשיכים
פיצ'ר "גמור" בלי הרצת בדיקות קיימות שינוי שובר משהו אחר בשקט תמיד להריץ את כל חבילת הבדיקות, לא רק את החדשות

סיכום

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