Блог
Публикации о процессе разработки, решённых задачах и изученных технологиях
Когда старый формат données ломает всю миграцию
Мы дошли до финальной фазы decoupling в **Trend Analysis** — нужно было избавиться от поля `object_id`, которое пронизывало базу данных в шести таблицах. На бумаге казалось просто: дропнуть колонку в миграции, обновить тесты, и всё. На практике это превратилось в охоту за тремя потерянными файлами. Проблема была в том, как я организовал работу. Несколько раундов автоматизированной чистки кода — агенты чинили тесты, переписывали запросы, удаляли старые таблицы. Но когда я делал ревью, оказалось, что агенты во втором и третьем раундах работали на другой ветке (`feat/feed-translate-and-tags`), и их критические правки **production-кода** вообще не дошли до текущей ветки `chore/phase5-final-decouple`. Три файла остались с прямыми ссылками на удаленное поле: **`src/db/queries/event_store.py`** — 12 JOINов по `events.c.object_id`, четыре функции. Агент второго раунда полностью переписал это под новую структуру, но коммит завис на другой ветке. **`src/db/repositories/trend_repo.py`** в методе `materialize()` всё ещё писал `object_id` в VALUES запроса. Агент третьего раунда удалил параметр, но изменение потеряось. **`src/db/queries/trend_linker.py`** пытался читать удалённые колонки из миграции — этот файл я частично восстановил через stash. Тесты кричали: **69 failed, 1020 passed**. Половина ошибок — это падение на попытке обратиться к `object_id`, которого больше нет в схеме. Я переписал все три файла с нуля, но на этот раз держа их в одной ветке и отслеживая каждый коммит. Удалил параметры, переделал JOINы на новые ключи, переписал select'ы. Никакого волшебства — просто старая-добрая пятёрка find-and-replace и понимание того, как данные текут через систему. Финальный прогон: **1169 тестов зелёные**. Версию забампил, коммит в main, и система снова дышит спокойно. Из этого вынес урок: миграции базы данных — не фоновый процесс, это центральное событие. Когда ты трогаешь таблицы, нужно синхронизировать **все** слои приложения за один раз, в одном месте, в одном коммите. Если разбросаешь правки по разным веткам — потеряешь не только код, но и часы отладки. А вот анекдот про миграции: мигрировать с одной архитектуры на другую — всё равно что менять колёса на ходу. На самолёте. 😄
SEO-метаданные для карточки проекта: как мы это сделали
Когда я делал страницу проекта **Borisov AI** на Next.js, выяснилось, что каждый проект должен иметь собственные метаданные для поисковиков и соцсетей. Задача казалась простой, но дьявол, как всегда, был в деталях. Сначала я подумал: «Просто добавлю `generateMetadata` в `page.tsx` проекта и готово». Но потом понял — нужно учитывать локализацию. Если пользователь смотрит проект на русском, в `<title>` должен быть русский текст. На английском — английский. А заголовок проекта приходит из Strapi API, где может быть либо одно, либо другое. Решение оказалось элегантным: вместо дублирования логики я переиспользовал существующий fetch-запрос к Strapi. Next.js автоматически дедублирует одинаковые запросы в рамках одного рендера, поэтому данные проекта загружаются один раз — и для страницы, и для метаданных. Это сэкономило не только код, но и время отклика. Потом пришлось решить, откуда брать изображение для `og:image`. Нельзя же просто взять первую попавшуюся картинку. В каждом проекте в Strapi может быть thumbnail, и я использовал существующую функцию `getStrapiMediaUrl` для его обработки. Если thumbnail отсутствует — падаем на `/og-default.png`, и это работает. Интересный момент с `canonical` и `hreflang` — они нужны, чтобы поисковики понимали, что русская и английская версии одного проекта — это не дубли, а альтернативные локали. Без этого Google может наказать за дублированный контент. **Вот что получилось:** - Per-project `<title>` с названием из Strapi - `<meta description>` из поля `description` API - Open Graph и Twitter Card с изображением - Правильная разметка для мультиязычности Сама реализация — всего ~30 строк в `generateMetadata`, но она охватывает все кейсы: есть проект — есть метаданные, нет проекта — есть fallback. **Факт о Cypress:** оказывается, фреймворк для e2e-тестирования работает похоже на подростка — непредсказуем, требует постоянного внимания и иногда отказывается сотрудничать без явной переконфигурации 😄
Как README потерял справочник и вернул его обратно
Три месяца назад в проекте Speech to Text произошла история, которая напомнила мне, почему техническая документация — это не маркетинг. Всё началось просто: кто-то решил переписать README, сделав его более дружелюбным и компактным. На первый взгляд, идея имела смысл. Один-пейджер вместо стены текста — казалось, это сделает проект более привлекательным для новичков. Но забыли про опытных пользователей, которые полагаются на справочник. После публикации v2.0.9 в наш репозиторий начали поступать вопросы. Где конфиг? Как настроить модель вручную? Что делать, если Whisper начал галлюцинировать на русском тексте? Ответы были в коде, в issues, в старых документах — но не в README. Выяснилось, что при переписи выпало всё самое важное: раздел о конфигурации с примерами `config.json`, инструкции по сборке EXE и публикации релизов, таблицы зеркал для скачивания моделей из Hugging Face. Последнее особенно критично для тех, кто находится за корпоративными фильтрами или в странах с ограничениями: справочник содержал адреса альтернативных репозиториев, включая cascade's Whisper-AI и ONNX дарирующие файлы. Пришлось восстанавливать. Я прошёлся по старым версиям, собрал разделы про использование (пункты меню трея, вкладки Settings), про переопределение конфигурации через реестр моделей, про структуру проекта с новыми компонентами v2.0.9 — pyannote_onnx_lite, wespeaker_onnx, hallucination_filter, text_normalizer. Добавил troubleshooting с советом по Whisper hallucinations и tips по дарирации, упомянул debug_save_audio для отладки. Главное понимание, которое пришло в процессе: README — это не маркетинг. Это справочник, который пользователь открывает на шестой минуте ночи, когда в production что-то сломалось. Он не ищет вдохновляющего слогана, он ищет таблицу, точный пример конфига или команду для отладки. Вводная часть может быть красивой, но справочные разделы должны быть полными и точными. Итог: вернули всё, что было. Теперь README одновременно красивый и полезный — маркетинг в начале, справочник в конце, both на русском и английском. 😄 Совет дня: перед тем как обновить Rails, сделай бэкап. И резюме.