לדלג לתוכן

3.1 הבנת codebase לא מוכר הרצאה

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


למה זה שונה מקריאה עצמאית - orientation vs deep reading

חשוב להבין את הגבול בין שני שימושים שונים:

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

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


פרומפט ראשון: מיפוי ארכיטקטורה - architecture overview

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

> Give me an architecture summary of this project: what layers/modules
  exist, how they communicate with each other, and what are the main
  entry points (server, CLI, cron jobs, etc). Base this on what you read
  in the code and config files, not on the README if it's outdated.

הagent יתחיל בסריקה: package.json או pyproject.toml, קבצי קונפיגורציה, מבנה התיקיות, אולי גם docker-compose.yml אם יש. הוא יבנה תמונה ויחזיר אותה בצורה מובנית - משהו כמו:

Architecture - Order Service (Node.js + Express + PostgreSQL)

├── src/api/       - HTTP layer: routes and controllers
├── src/services/  - business logic, not tied to HTTP
├── src/db/        - data access layer, uses Prisma ORM
├── src/queue/     - async processing via BullMQ + Redis
└── src/workers/   - background processes that consume from the queue

Entry points:
- src/index.ts        - main HTTP server
- src/workers/main.ts - separate worker process, run as an independent process

Typical flow: HTTP request -> router -> controller -> service ->
Prisma -> Postgres. Heavy operations (sending email, billing) are pushed
to the queue and handled in a separate worker.

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

> In which exact files did you see the use of BullMQ and the separation
  between the worker and the main server? Give me exact paths.

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


איפה מטופל X - locating functionality

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

> Where in the code is the user authentication process handled -
  from the moment a login request arrives until a token is issued? Give
  me the chain of files and functions, not just a general answer.

הagent ישתמש בtools חיפוש (grep, glob, קריאת קבצים) כדי לעקוב אחרי השרשרת בפועל - לא לנחש מהזיכרון שלו איך authentication "בדרך כלל" עובד. זה ההבדל הקריטי בין לשאול צ'אט כללי לבין לשאול agent שרץ בתוך הריפו שלכם: הצ'אט ינחש דפוס טיפוסי, הagent קורא את הקוד האמיתי.

תבנית שימושית לשאלות מהסוג הזה:

מה שואלים דוגמת ניסוח
היכן מטופלת התנהגות "איפה מחושב המחיר הסופי של הזמנה, כולל הנחות ומע"מ?"
למה קורה משהו "למה בקשת GET ל-/users/:id מחזירה גם שדה email גם כשהמשתמש לא מחובר?"
מה קורה כשמשתנה תנאי "מה קורה בקוד כשמשתמש מבטל מנוי באמצע מחזור חיוב?"
היכן מוגדר קבוע/הגדרה "איפה מוגדר ה-timeout של קריאות ל-API החיצוני, ואיך משנים אותו?"

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


מעקב אחר בקשה מקצה לקצה - tracing a request

כשצריך להבין תהליך שלם - לא רק "איפה" אלא "מה קורה בכל שלב" - כדאי לבקש מעקב מפורש לאורך הזרימה כולה, עם ציון שורות:

> Trace a POST /orders request for me from the moment it enters the
  server until it's saved in the DB and a response is returned. At each
  step give me: file, function name, and a brief description of what
  happens there. Also flag any asynchronous calls or events emitted
  along the way.

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

1. src/api/routes/orders.ts:14
   router.post('/orders', validateBody(orderSchema), createOrder)
   - validates the request body against the zod schema, before reaching the logic

2. src/api/controllers/orderController.ts:22 (createOrder)
   - pulls the user from req.user (injected by the auth middleware)
   - calls orderService.create(userId, items)

3. src/services/orderService.ts:40 (create)
   - computes the total price via pricingService.calculateTotal()
   - opens a Prisma transaction, creates an Order + OrderItem record
   - after commit, emits an 'order.created' event to the eventBus

4. src/events/handlers/orderCreatedHandler.ts:8
   - listens for 'order.created', pushes a job to the 'send-confirmation' queue
   - this is asynchronous - the HTTP response has already been sent to the user at this point

5. Back in createOrder: returns 201 with the created Order

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

טיפ מעשי: כשמדובר בזרימה שיש בה concurrency, retries, או race conditions אפשריים, בקשו מהagent לסמן אותם במפורש - "האם יש בזרימה הזו נקודה שרגישה ל-race condition, למשל אם שתי בקשות מגיעות באותו הזמן?". הagents נוטים לפספס את זה אם לא מבקשים ישירות, כי הם עונים לשאלה שנשאלה, לא לשאלה שהייתם צריכים לשאול.


עבודה עם ריפו גדול - large monorepo strategies

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

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

> I'm only interested in the packages/billing package. Ignore the rest
  of the monorepo. Within this package, give me an architecture summary:
  what are the entry points, and which other packages in the monorepo
  does it consume (cross-package imports).

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

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

> Search only inside packages/billing/src, not in tests or dist,
  for every place that computes tax on a transaction.

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

> This project has two implementations of payment processing - one
  in src/legacy/payments and one in the new src/payments. Check,
  based on git log and on who calls whom, which one is actually in
  use today and which remains only for backward compatibility.

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


יצירת סיכום onboarding - onboarding summary

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

> Write me a short onboarding document for this project, in a style
  that will help a new developer start working within a day. Include:
  what the project does, how to run it locally, a brief folder
  structure, the 3-4 most important concepts to understand before
  touching the code, and where there are "traps" that aren't obvious
  from the code itself (for example: unwritten conventions, legacy
  code that remains for historical reasons).

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

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


מלכודות נפוצות - common pitfalls

ביטחון עודף על בסיס דגימה חלקית

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

> Search the entire repo (not just the src folder) for every place
  that calls the function legacyCalculatePrice. Give me a full list of
  calls, including in tests and scripts.

בלבול בין קוד פעיל לקוד מת

ריפואים ישנים מלאים בקוד שלא באמת רץ יותר - branch שאף פעם לא מתבצע, קובץ ישן שהוחלף אבל לא נמחק, feature flag שכבוי קבוע. הagent עלול לתאר קוד כזה כאילו הוא חלק פעיל מהזרימה, כי מבחינה תחבירית הוא נראה מחובר. אם משהו נראה מוזר או לא הגיוני, שאלו במפורש: "האם הקוד הזה בכלל מגיע אליו בזמן ריצה, או שהוא dead code?"

הסתמכות על תיעוד לא מעודכן

קובץ README, תיעוד API, ותרשימי ארכיטקטורה ישנים הם מקור מידע פופולרי אצל agents כי הם קלים לקריאה - אבל הם משקרים כשהקוד השתנה בלעדיהם. תמיד שווה להוסיף לפרומפט משהו כמו "בדוק שהתיאור הזה עדיין תואם את הקוד בפועל, לא רק את מה שכתוב בתיעוד".

לקבל תקציר בלי לבדוק אותו בעצמכם

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


סיכום

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