Fri Jan 31 2025
...
Завершена миграция FastComments на TypeScript
! Эта статья содержит технический жаргон
Что нового
В FastComments мы ценим статически типизированные языки. Более конкретно, мне нравятся хорошие системы типов с быстрыми компиляторами. В FastComments мы начали с последнего - или без компилятора. Хотя у нас было два сервиса, написанных на современном Java в течение первого года, основные библиотеки бэкенда и фронтенда были написаны на CJS JS, работающем на Node.
В подготовке к следующему десятилетию разработки мы мигрировали крупнейшие компоненты FastComments на TypeScript.
Это потребовало миграции более 130k строк кода (из которых 100k - это бэкенд) по 1441 файлу, и исправления более 8000 ошибок компиляции.
Это было сделано за две недели.
Заморозка кода - Спасибо
Я хотел бы поблагодарить наших клиентов за понимание любых задержек в исправлении ошибок или релизах функций, так как мы провели двухнедельную заморозку кода для завершения этого обновления. Спасибо!
Исправленные ошибки
Как вы можете себе представить, мы исправили несколько ошибок. Они в основном касались обнаружения спама и кэширования.
Ломающее изменения
- Все конечные точки 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 непосредственно из серверного кода, что было основной мотивацией для этих усилий.
В заключение
Как и все крупные релизы, мы рады, что могли выделить время, чтобы оптимизировать, протестировать и правильно выпустить эти изменения. Дайте нам знать внизу, если вы обнаружите какие-либо проблемы.
Ура!
