1. Красный текст ошибки — это карта
На портале Тёма утыкается в живую красную ошибку. Не строчку из ночного журнала, а ту самую красную простыню текста, что вываливается на экран прямо сейчас, когда что-то падает. Непонятные слова, пути файлов, ничего человеческого. Первый инстинкт у него прежний: закрыть и сделать вид, что не видел, а лучше переслать кому поумнее. Например, Лехе.
— Стоп, — Лёха ловит этот порыв. — Куда закрывать? Ты сейчас улику выбрасываешь.
— Какую улику, это же просто ошибка. Каша из красного текста.
— Это не каша. Это карта места преступления, — Лёха не даёт ему сбежать. — В этой «простыне» точно записано, где и что сломалось. Закрыть её — это как на месте аварии закрыть глаза, чтоб не видеть. Научишься её читать — страх превратится в улику. Давай разберём, она устроена проще, чем выглядит.
И Тёма впервые не закрывает красное, а вчитывается — будто переводит его на человеческий. Не магическое проклятие, а чужой язык, который можно разобрать.
2. Стектрейс: тип, файл, строка
— Эта простыня называется стектрейс, — говорит Лёха. — По-английски stack trace, «след стека вызовов». Звучит страшно, а внутри всего три полезные вещи. Смотри, я вырежу лишнее и покажу скелет.
Он показывает на экране урезанный пример (комментарии — пояснения, в реальном логе их нет):
TypeError: Cannot read properties of undefined (reading 'score') # ТИП сбоя — что пошло не так
at calculateReward (reward-flow.js:30) # ФАЙЛ и СТРОКА — где сломалось
at processClaim (portal.js:23) # кто это вызвал (цепочка)
— Видишь три кусочка? — Лёха разбирает по пальцам. — Первая строка — тип ошибки: что именно пошло не так. Вторая — файл и строка: где это случилось, reward-flow.js, строка 30. Третья и ниже — кто это вызвал, цепочка вызовов: снизу вверх, кто кого звал. И всё. Стектрейс — это прямой указатель: иди в этот файл, на эту строку, смотри, что там происходит.
Тёма всматривается. И ловит, что вместо «сломалось всё, конец» у него впервые появляется нормальная форма мысли:
— То есть это не «всё взорвалось». Это «взорвалось вот здесь, в этом файле, на этой строке».
— Именно. Это навигатор к месту поломки, а не повод закрыть терминал. Как чёрный ящик у самолёта: лента пугающая, но в ней точно записано, где и в какой момент что отказало. Чёрный ящик не выбрасывают— его расшифровывают.
3. Где взорвалось ≠ где заложена мина
Тёма уже рвётся в бой:
— Отлично, понял! Строка 30, файл reward-flow.js. Иду туда, чиню эту строку — и всё?
— А вот тут тормози, — Лёха придерживает. — Самая частая ошибка новичка. Место, где взорвалось, — не всегда место, где заложена мина.
— В смысле? Оно же прямо показывает строку 30.
— Оно показывает, где упало. Это симптом. А причина — корень — может сидеть совсем в другом месте. Смотри: программа упала на строке 30, потому что туда пришло пустое значение. Но пустым оно пришло не отсюда — его кто-то сделал пустым тремя шагами раньше, в другом файле. Починишь строку 30 — заткнёшь симптом, а корень останется, и оно вылезет снова чуть в стороне.
Лёха находит образ:
— Это как дым в салоне самолёта. Дым ты видишь в салоне — это где болит. А горит-то проводка под полом. Тушить дым в салоне бесполезно: пока не починишь проводку, он будет валить снова. Симптом — дым. Корень — проводка.
Тёма медленно кивает.
— То есть, — говорит он, — раньше для меня это была чёрная коробка. Сломалось — пнуть или переслать кому поумнее, других вариантов нет. А тут, выходит, внутри лежат факты. И с этими фактами я сам могу возиться.
— Сам, — отзывается Лёха. — Не пнуть, а прочитать.
4. Две улики: стектрейс и журнал
— Слушай, а тот ночной лог, что я утром читал, — он тут при чём? — вспоминает Тёма. — Там же тоже про эту ночь.
— Очень при чём, — Лёха оживляется. — Это твоя вторая улика, и она совсем другой природы. Смотри, в чём разница. Стектрейс — это место аварии прямо сейчас: вот тут дымит, вот этот файл, эта строка. А ночной журнал — это хроника события: что агент решал делать ночью и в каком порядке. Где отключил тесты, где снёс страницу, где подогнал результат, где не оставил дороги назад.
— То есть один говорит «где болит», а второй — «что происходило»?
— Точно. Стектрейс — как след на снегу там, где упали. Журнал — как запись камеры, кто всю ночь по этому двору бродил. Стектрейс отвечает на «где», журнал — на «что меняли рядом и зачем». И вот тут самое важное: каждая по отдельности полуслепая. Стектрейс покажет место взрыва, но не скажет, кто заложил. Журнал покажет, что агент ночью копался в reward-flow, но сам по себе не докажет, что взорвалось именно из-за этого.
5. Связка двух улик: сначала факты, потом агент
— Тогда как из двух полуслепых улик собрать одну зрячую? — спрашивает Тёма.
— Связкой двух улик, — Лёха явно ждал вопроса. — У тебя их как раз две. Первая — стектрейс на экране: он говорит, где взорвалось сейчас. Вторая — ночной журнал: он говорит, что агент менял ночью в этих окрестностях. По отдельности каждая полуслепая. А вместе — стереокартинка.
— То есть смотрю, где упало, и листаю журнал — что агент трогал рядом с этим местом?
— Вот именно. Стектрейс показал тебе reward-flow.js. Лезешь в ночной журнал, ищешь — что агент делал с reward-flow ночью. Находишь строку «подогнал reward-flow под результат» — и вот он, корень. Не там, где задымило, а там, где он ночью заложил мину. Сопоставил одно с другим — нашёл настоящую причину, а не просто место взрыва.
И тут Тёма сам выкладывает порядок, будто проговаривает себе под нос новое правило:
— Получается так: сначала я сам смотрю на факты — стектрейс плюс журнал. И только потом зову агента чинить. Не наоборот.
— Вот теперь ты говоришь как инженер, — отвечает Лёха. — Потому что если позвать агента без факта на входе — с одним «у меня не работает, почини» — он начнёт гадать. А угадывающий агент в этой ночи как раз и был источником всех бед. Сначала факты. Потом агент.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ