JavaRush /Курси /Claude Code SELF /Як читати лог і доходити до причини

Як читати лог і доходити до причини

Claude Code SELF
Рівень 14 , Лекція 2
Відкрита

1. Що таке лог

Тьома дуже хоче написати агентові: «У грі щось із лічильником, полагодь». Але сам себе гальмує — Льоха вбив у нього дисципліну: думка «щось не так» — не дані для лагодження. Потрібна улика. А її, за словами Льохи, дає лог. Слово знайоме, але що воно означає, Тьома толком не знає — тож ловить Олега, який проходить повз.

— Дядьку Олеже, а лог — це взагалі що? Та простирадло, яке я завжди гортаю й закриваю?

— Простирадло він закриває, — фиркає Олег, зупиняється. — Лог — це щоденник застосунку. Він по ходу роботи записує, що робить: тут запустився, тут порахував, тут спіткнувся. Як чорний ящик у літаку — пише все підряд, щоб потім, якщо щось упало, було по чому розібратися.

— І де цей щоденник подивитися?

— А от тут буває по-різному, — Олег загинає пальці. — Іноді застосунок пише лог у файл на диск — тоді він лежить там, і потім його можна відкрити хоч завтра. Памʼятаєш свій нічний журнал, який пережив збій? Оце лог у файл. А іноді пише в консоль — просто в чорне вікно термінала, прямо на очах. Тести, наприклад, пишуть у консоль: запустили — одразу бачиш, що вийшло. Файл чи консоль — суть одна: застосунок сам розповідає, що з ним відбувається.

Тьома киває. Дратівливе простирадло в голові перестає бути лайкою й стає щоденником: раз застосунок сам записав, де спіткнувся, — значить, там і місце проблеми.

2. Лог тесту і лог падіння — не плутати

— Тільки тримай у голові, — додає Олег, — сьогодні в тебе два різні логи, і змішувати їх не треба.

Він показує на пальцях.

— Перший — лог тесту. Це коли твій перевіряльник відзвітував: чекав три, отримав тридцять, от і FAIL. Це доповідь контролера — що він перевіряв і що не зійшлося. Другий — лог падіння, по-розумному стектрейс, «слід стека викликів». Це коли сам застосунок спіткнувся і записав, у якому місці коду все впало. Контролер каже: «результат неправильний», а стектрейс — «впало ось на цьому рядку». Різні речі: один про підсумок, інший про місце.

— А мені який потрібен?

— Тобі зараз — другий, який тицяє в рядок. Щоб не гадати, де лагодити. Хоча зручно, коли тест пише їх одразу: і «неправильний результат», і «ось де». Зараз знайду пару прикладів у себе й покажу.

3. Стектрейс веде до конкретного рядка

Поки Олег шукає підхожі приклади, Льоха встряє в розмову. Спочатку відтворюємо баг, щоб гра сама написала про проблему. Ганяємо тести, ловимо падіння:

npm test
  ✖ три в ряд дають 3 очки (по 1 за збіг)
    AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:

    30 !== 3                                          ← отримали 30, очікували 3

      at TestContext.<anonymous> (src/bonus-game/score.test.js:8:10)   ← рядок тесту, де перевірка не зійшлася

— Дивись, тут обидві штуки разом, про які тобі Олег казав, — Льоха киває на вивід. — Верх, 30 !== 3 (отримали тридцять, очікували три), — це лог тесту: контролер доповів, значення не зійшлися. А низ, at … (src/bonus-game/score.test.js:8:10), — це слід: точна адреса рядка, де перевірка не зійшлася. src/bonus-game/score.test.js — файл. 8 — рядок. 10 — символ. Іди туди й дивись, що саме перевірялося.

Тьома відкриває score.test.js, рядок 8 — а там усе написано: assert.equal(calcScore(3), 3). Тест викликав функцію calcScore і чекав від неї трійку.

— Тобто лог мені і симптом дав, і адресу, — Тьома подається до екрана. — «Тридцять замість трьох» — це контролер, а рядок тесту називає винуватця на імʼя: calcScore. Не стіна тексту, а драбина: лог веде в тест, тест веде у функцію.

Та саме «страшне простирадло», яке він тижнями гортав і закривав, не дивлячись, на очах перетворюється на карту. Раніше дивився на лог як на лайку, яку треба перечекати. А зараз читає як адресу: будинок, поверх, квартира.

Тьома відкриває src/bonus-game/score.js і гортає до calcScore — не навмання по всьому проєкту, а рівно туди, куди привела драбина. Палець на коліщатко, рядки 7, 8, 9.

Ось вона.

Рядок 9: кожен збіг множиться на константу POINTS_PER_MATCH — і ось вона, вище у файлі: POINTS_PER_MATCH = 10. А має бути 1. Одна цифра. Три збіги замість «плюс три очки» дають «три рази по десять» — от звідки взялася тридцятка, яку він увесь ранок ловив у грі.

— Та ти що, — видихає Тьома. — Уся ця нахабна аркада, що усміхалася й брехала, — це ось ця одна цифра?

Він навіть трохи розчарований, що так просто. Корінь не вгаданий, не вимучений тиканням по файлах — він знайшовся за хвилину, просто по логу.

— І зауваж, — додає Льоха, — ми жодного рядка не вгадували. Лог сам провів від симптому до рядка. Ось тому його не закривають, коли гортають, а читають.

— А тепер фокус, — продовжує Льоха. — Цей самий лог ти не тримаєш у голові й не переповідаєш агентові своїми словами. Ти віддаєш йому саму улику. Дивись, у чому різниця.

❌ так:  у грі очки рахуються неправильно, подивись і полагодь
✅ так:  баг у calcScore (src/bonus-game/score.js:9): 3 збіги дають 30 замість 3,
         константа POINTS_PER_MATCH=10 замість 1. Стектрейс: [вставлено лог].
         Полагодь причину, сусідні зони гри не чіпай.

— Відчуваєш різницю вхідних даних? — Льоха задоволений. — У першому випадку агент піде тицяти навмання, може полізти лагодити відмальовування або перепише не той модуль. У другому — у нього точна улика, і він лагодить адресно. Даси емоцію — отримаєш здогадки. Даси улику — отримаєш роботу по суті.

Тьома повертається до свого ТЗ і переписує рядок дефекту. Зранку він написав розмито: «логіка рахунку бреше». А тепер той самий рядок ужався до точного — файл, функція, рядок, причина:

# було зранку:
ДЕФЕКТ:  3 в ряд нараховує 30 очок замість 3 (логіка рахунку бреше)

# стало після логу:
ДЕФЕКТ:  calcScore (src/bonus-game/score.js:9) — POINTS_PER_MATCH=10 замість 1:
         3 збіги → 30 очок замість 3

Не «щось із рахунком», а файл-функція-рядок-причина. Чим точніший вхід, тим менше шансів, що агент піде лікувати не ту болячку.

4. Перевірку проєктують під конкретний баг

Перед тим як кликати агента лагодити, Льоха пише другу важливу думку — і вона про те, як перевіряти.

— Дивись, — каже він. — Тести бувають різні. Їх у проєкті зазвичай купа — на різні випадки. І тут легко потрапити в пастку: «прогонимо-но я все підряд, авжеж буде зелене». Ганяєш увесь ворох, дивишся на загальне «все пройшло» — і ніби спокійний.

— А що не так? Прогнав усе — значить, усе перевірено.

— Не значить. Серед цього вороху може взагалі не бути тесту на твій баг. Прогнав сотню чужих перевірок, усі зелені — а твій баг із тридцятьма замість трьох жодна з них і не дивилася. Ти зрадів зеленому, а воно про інше. Тому професійний підхід інший: не «прогнати що є», а зробити перевірку саме під свій баг.

— Тобто?

— А ось дивись, у чому різниця. — Льоха розкладає по пальцях. — По-дитячому було б так: «ну проганю тести, гляну, зелене чи ні». Якісь — оптом. А по-дорослому ти спершу запитуєш себе: який саме тест упіймає рівно ЦЕЙ збій? У тебе баг — три в ряд дає тридцять. Отже, тобі потрібен тест, який перевіряє рівно це: «дай лічильнику три збіги — чекай рівно три». Ти його назвав, ти знаєш, що він ловить. І якщо ВІН зелений — ось це вже про твій баг, а не про сто сусідніх.

Тьома киває — тепер зрозуміліше. Перевірка не «прогнати навмання», а зроблена під мету: знаєш, що перевіряєш, знаєш, яка відповідь правильна. Як ТЗ пишуть під задачу, а не «зроби щось».

— Уклалося? — Льоха ніби відчуває, що не до кінця. — Гаразд, слова словами. Зараз побачиш сам, навіщо це. Покличемо агента лагодити, він принесе тобі зелений тест, усе чин чином. А я потім покажу одну штуку, після якої ти на голе «зелене» більше не поведешся. Ось тоді й зрозумієш, чому перевірку треба будувати з головою, а не проганяти оптом.

Тьома знизує плечима і йде кликати агента. Що там за штука — подивимося.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ