16.09.2026 · базы данных
Ручка списка заказов тормозила, и я был уверен, что виноват классический N+1: на каждый заказ отдельный запрос за пользователем. Включил лог запросов, приготовился ловить сотни строк — а там их было три.
Проблема оказалась в одном из этих трёх. Запрос за позициями заказов возвращал десятки тысяч строк, потому что джойн потерял условие по дате и тянул всю историю. Приложение потом честно фильтровало это в памяти. То есть база и сеть работали, а время утекало на сериализацию того, что всё равно выбрасывалось.
-- было: план показывал Seq Scan на миллионы строк
EXPLAIN ANALYZE
SELECT * FROM order_items oi
JOIN orders o ON o.id = oi.order_id
WHERE o.user_id = 42;
-- забыто: AND o.created_at >= now() - interval '30 days'
Мораль для меня простая: прежде чем оптимизировать количество запросов, посмотри на их содержимое. Один жирный запрос легко перевешивает сотню мелких.
postgresqlпроизводительностьотладка
02.09.2026 · надёжность
Большинство HTTP-клиентов, если не задать таймаут явно, ждут ответа вечно. В нормальный день этого не видно. Проблема всплывает, когда внешний сервис начинает отвечать медленно, но не падает: соединения копятся, пул исчерпывается, и через минуту лежит уже твой сервис, а не чужой.
Любой вызов по сети может зависнуть. Если ты не решил, сколько готов ждать, за тебя это решит худший день в году.
Теперь я завёл правило: у каждого сетевого вызова есть явный таймаут и понятное поведение при его срабатывании. Иногда это ретрай, иногда — отдать кэш, иногда — честно вернуть ошибку. Главное, чтобы это было решением, а не случайностью.
client := &http.Client{
Timeout: 3 * time.Second, // не оставляем на самотёк
}
сетинадёжностьgo
21.08.2026 · практика
Хороший лог пишется не для того момента, когда всё работает, а для того, когда что-то сломалось и ты смотришь на него первый раз за полгода, невыспавшийся и без контекста. С этой мыслью я и стал их писать иначе.
Три вещи, которые помогли больше всего:
1. Один идентификатор запроса через все сервисы —
иначе события не собрать в цепочку.
2. Логировать не «что-то пошло не так»,
а конкретные значения: id, статус, длительность.
3. Уровни всерьёз: ERROR — то, на что будят человека.
Всё остальное — INFO или ниже.
С тех пор разбор инцидентов стал занимать минуты, а не часы. Никакой магии — просто логи наконец отвечают на вопрос «что произошло», а не «что-то произошло».
наблюдаемостьэксплуатация
05.08.2026 · мнение
За последние годы я всё реже выбираю новое и всё чаще — проверенное. Не потому, что новое плохое, а потому что у скучных инструментов есть недооценённое свойство: про них уже всё написано. Любая ошибка, с которой ты столкнёшься, скорее всего, восемь лет назад разобрана в чьём-то ответе на форуме.
Новизну я теперь трачу осознанно: беру одну незнакомую технологию на проект, а не пять сразу. Тогда, если что-то ломается, я хотя бы знаю, где именно искать причину.
архитектурамнение
Об авторе
Бэкенд-инженер, пишу в основном на Go и Python, живу где-то между базой данных и очередью сообщений. Этот блог — место, куда я складываю разобранные баги и выводы, чтобы не наступать на те же грабли дважды.
Всё здесь — личный опыт и личное мнение, а не истина в последней инстанции. Пишу, когда есть о чём.