FastComments.com Blog

Fri Jan 31 2025
...

Завершена миграция FastComments на TypeScript

! Эта статья содержит технический жаргон

Что нового

В FastComments мы ценим статически типизированные языки. Более конкретно, мне нравятся хорошие системы типов с быстрыми компиляторами. В FastComments мы начали с последнего - или без компилятора. Хотя у нас было два сервиса, написанных на современном Java в течение первого года, основные библиотеки бэкенда и фронтенда были написаны на CJS JS, работающем на Node.

В подготовке к следующему десятилетию разработки мы мигрировали крупнейшие компоненты FastComments на TypeScript.

Это потребовало миграции более 130k строк кода (из которых 100k - это бэкенд) по 1441 файлу, и исправления более 8000 ошибок компиляции.

вау
Скриншот GitHub

Это было сделано за две недели.

Заморозка кода - Спасибо

Я хотел бы поблагодарить наших клиентов за понимание любых задержек в исправлении ошибок или релизах функций, так как мы провели двухнедельную заморозку кода для завершения этого обновления. Спасибо!

Исправленные ошибки

Как вы можете себе представить, мы исправили несколько ошибок. Они в основном касались обнаружения спама и кэширования.

Ломающее изменения

  • Все конечные точки API теперь возвращают статус: 'failed' вместо смеси "failed" и "failure" в качестве значений состояния. "success" остался без изменений.
  • Мы больше не будем по умолчанию использовать первую конфигурацию виджета, если совпадения нет, вместо этого мы вернем конфигурацию системы по умолчанию.

Как это было?

Мы обнаружили, что, как обычно, многие инструменты в экосистеме NPM, помогающие с этой задачей, работали довольно плохо. Поэтому мы использовали LLM для генерации скриптов, чтобы выполнить большую часть работы. Например, мы активно использовали JSDoc, чтобы написать скрипты, которые брали JSDoc и преобразовывали его в интерфейсы TypeScript и определения типов, и правильно аннотировали аргументы функций и типы возвращаемых значений. Мы также использовали эти скрипты для миграции с CJS на ESM, что включало переписывание импортов, экспортов и обнаружение распространенных проблем выполнения, таких как __dirname.

Я упоминал о проблемах выполнения?

Каков TypeScript в 2025 году?

TypeScript - это хороший язык для написания бизнес-логики. Но Java все еще обладает лучшим DevEx. Если Java, Go или Rust компилируются, скорее всего, они будут работать. С TypeScript я могу сделать что-то вроде:

console.log(__dirname);

... и это скомпилируется.

Но это не будет выполняться с современными es модулями. Ваша IDE с радостью даже автозаполнит __dirname, а затем все сломается во время выполнения. Это похоже на Spring DI, но хуже.

Вы также можете делать такие вещи, как:

context.someImportantMethodToCall;

Теперь это "выражение". Это действительное "выражение". На первый взгляд может показаться, что мы вызываем someImportantMethodToCall, но это не так! По крайней мере, моя IDE не предупреждает об этом, и компилятор тоже. Код просто ничего не сделает (если someImportantMethodToCall не является классом getter, в этом случае он вызывается неявно...)

Исправление следующее:

context.someImportantMethodToCall();

Я думаю, что вы можете обнаружить это с помощью чего-то вроде eslint и какого-то правила "без побочных эффектов", но тогда вы подтягиваете еще один большой набор библиотек, чтобы поддерживать их обновленными, и тогда eslint должен будет анализировать вашу всю кодовую базу на каждом сборке, инструменты медленные и так далее - нет, спасибо. Влияние на продуктивность от работы с медленными инструментами, такими как eslint, было более значительным в моей карьере на прошлых работах, чем "прирост" производительности, который я когда-либо получал от мелочей, которые eslint исправляет/предотвращает с отступами и т. д. Теперь выходят более быстрые альтернативы, что замечательно.

TypeScript действительно хорош благодаря таким языковым функциям, как Pick<User, 'username', 'email'>. Это, в сочетании с выводом типов, дает возможность получить типобезопасные результаты запросов из базы данных для подмножеств больших объектов без необходимости определять класс для каждой формы. Pick - это то, чем я удивлен, что Scala не обладает. Объединения типов тоже действительно хороши.

Инкрементные сборки также работают достаточно хорошо, мы только увеличили время сборки в CI примерно на 5 - 10 секунд в среднем, для сборки общей библиотеки, фронтенда и бэкенда.

Хронология разработки

Для тех, кто интересуется, вот как выглядел наш прогресс:

  • День первый: Найдено 5564 ошибки в 362 файлах.
  • День второй: Найдено 4034 ошибки в 239 файлах.
  • День третий: Найдено 3784 ошибки в 191 файле.
  • День четвертый: Найдено 2974 ошибки в 169 файлах.
  • День пятый: Найдено 3000 ошибок в 171 файле.
  • День шестой: Найдено 2916 ошибок в 165 файлах.
  • День седьмой: Найдено 2618 ошибок в 157 файлах.
  • День восьмой: Найдено 2253 ошибки в 109 файлах.
  • День девятый: Найдено 1605 ошибок в 69 файлах.
  • День десятый: Найдено 686 ошибок в 53 файлах.
  • День 11: Пройдены модульные тесты бэкенда.
  • День 12: Начата миграция фронтенда, 3118 ошибок.
  • День 13: Найдено 2172 ошибки.
  • День 14: Найдено 1224 ошибки.
  • День 15: Найдено 498 ошибок.
  • День 16: Все ошибки компиляции исправлены.
  • День 17: Выпущен. E2E тесты проходят. 30 минут простоя из-за неожиданных проблем во время выполнения. :)

Будущее

Мы сделали это, чтобы поддержать разработку на следующее десятилетие. Система теперь настолько велика, что быстрее разрабатывать с системой типов, чем без нее.

Вы также можете ожидать, что наша библиотека TypeScript на NPM улучшится, так как она уже начала улучшаться, поскольку мы теперь используем эту библиотеку в нашем серверном и клиентском коде.

Мы также скоро выпустим сгенерированные клиентские SDK непосредственно из серверного кода, что было основной мотивацией для этих усилий.

В заключение

Как и все крупные релизы, мы рады, что могли выделить время, чтобы оптимизировать, протестировать и правильно выпустить эти изменения. Дайте нам знать внизу, если вы обнаружите какие-либо проблемы.

Ура!