Как и зачем мы переписали Тяжеловато на Тайпскрипт
Переписать Тяжеловато я хотел давно. Дело тут не в том, что «ой, я выучил новые штуки, поэтому старый код фу-фу-фу». Нет, просто поддерживать кодовую базу в том виде, каком она была, стало дорого.
Почему поддерживать код стало дорого
Было несколько причин.
Не было тестов
Из-за этого любое изменение в коде могло привести к чему угодно. Да, зелёные тесты не гарантируют, что ошибок совсем нет, но они помогают исключить уже найденные ошибки.
Не было нормальной архитектуры
Приложение, я напомню, я написал за 2 недели на коленке, там было не до архитектуры. (Ох уж этот дух стартапа!) По-хорошему, после запуска надо было взять пару недель и отрефакторить там всё хорошенько, но что-то (всё?) пошло не так.
Не было документации
Которая бы напомнила, что и как работает, и почему именно так. Казалось бы приложеньице маленькое, что там помнить-то, но нет! Как хранятся даты?.. Это поле стейта за что отвечало? Так, это-то с чем связано? Господи, а это что ещё за хрень? И прочее-прочее-прочее.
Всё это привело к тому, что поддерживать приложение стало долго и дорого. Времени на реализацию фич уходило больше, удовольствия от процесса становилось меньше, а горело под поясницей от ситуации сильнее.
И вот в 2019 году — случилось. Мне бомбануло окончательно, и я начал думать, как это можно изменить.
Как это можно было изменить
Мне было понятно, что если я начну исправлять ситуацию, меня будут преследовать две мысли.
Я это уже делал. Зачем тратить силы на то, что уже сделано?
Вообще-то это здравая мысль — действительно, переписывать ради переписывания нерентабельно. Я хотел найти для себя дополнительные стимулы и интерес. Интересом стали технические ограничения, которые я себе выдумал, и попытка поуправлять процессом разработки. А в дальнейшем, возможно, — реанимация Тяжеловато как проекта.
Технические ограничения — это как задача со звёздочкой в учебнике, вроде смысла особого нет, но выпендриться хочется, ну и как бы дофамин, вот это всё.
Поуправлять разработкой — это передать опыт, попробовать посмотреть на процесс шире, выйти в надсистему. У меня как раз на примете было два человека, кто хотел и мог бы помочь: Виктор Дёмин и Фёдор Кузнецов. Собственно, с ними мы и затеяли весь этот карнавал.
Реанимация проекта — я не то чтобы рассчитывал на это, этот пункт скорее был бонусным. Меньше ожиданий — лучше. Однако, проект ожил.
Не навреди!
Перепись переписью, но самый высокий приоритет во всей этой затее — чтобы по итогу пользователям стало лучше (как минимум — не хуже). Это значило, что нельзя катить в прод недоделанное приложение. Под недоделанным я понимал приложение в любом виде хуже того, что уже на телефонах пользователей.
То есть, нельзя было пофлексить что-то, что уже работало. Нельзя было выпилить фичу просто так, на то должна быть веская причина. И, разумеется, нельзя было просрать пользовательские данные. (Если вдруг что-то пошло не так, напишите, пожалуйста, на support@fuckgrechka.ru.)
Всё это грозило парализовать проект, потому что он начал бы казаться слишком большим. Мы с ребятами решили не «упарываться по-стартаперски», а дать себе бесконечное количество времени. Вот прямо сколько нужно, чтобы написать нормально, столько и берём. Торопиться — запрещено.
Дальше оставалось определить стек и технические ограничения.
Стек и технические ограничения
От Реакта уходить не хотелось. С Ангуляром я так и не подружился, а Вью мне почему-то казался всё ещё сыроватым. Палец отрезать не стали. Оставили Реакт.
Одним из технических ограничений «со звёздочкой» было минимальное количество зависимостей и размер бандла. Вторым — отсутствие классов: у нас только функциональные компоненты.
Второе действительно заставляет думать про отделение бизнес-логики от административной. Хуки помогли не размазывать логику по жизненному циклу компонентов, а собрать её в одной функции — SRP, все дела.
Последним (и по совместительству определяющим ход разработки) ограничением был выбор между двумя стульями: JS или TS. Сейчас расскажу, почему выбрали Тайпскрипт.
Почему выбрали Тайпскрипт
Мне хотелось нормальных типов, а не 0 !== '0'
и вот этого всего. Хотелось проектировать, как нормальный человек, а не писать тонны jsdoc
к каждой функции. Хотелось, чтобы код сам говорил, что он делает, а не прятался за комментариями, которые один хрен устареют и потом сиди-думай, чему верить. В Тайпскрипте всё это в какой-то мере есть.
Типы
Да, присвоить переменной типа string
значение типа number
уже не выйдет — и это прекрасно! Потому что за пределами классической песочницы-туду-листа, я буду путать не string
и number
, а структуры данных и сущности. И если редактор мне подсказывает: «дорогой, у тебя здесь должен быть просто Record
, а не Spend
», то я готов писать хоть на C#.

Цикл обратной связи короче, чем с JS, потому что TS проверяет мой код, пока я его пишу, и ошибку я увижу гораздо раньше.
Автоматическая документация
Идеальная документация — это та, которой нет, а её функция выполняется. Типы, интерфейсы и сигнатуры функций — это и есть такая документация.
Мы, люди, пользуемся именами, чтобы ссылаться на явления и сущности — нам так удобнее думать. Когда сущности в коде названы в соответствии с предметной областью, код читать становится проще.

Ещё Тайпскрипт позволяет использовать тип-алиасы для примитивов. Например, DayStartTimeStamp
— тип, который описывает временную метку в UTC, отсылающую к началу определённого дня.
Это алиас для обычного number
, просто он назван понятно. Я мог быть указать где-то в комментарии, что startDate
указывается в миллисекундах по UTC… но если у меня есть возможность указать это прямо в коде — то я лучше так и сделаю.

Код, покрытый типами, алисами и интерфейсами можно писать, как предложение. Вот функция, которая проверяет, находится ли переданная запись внутри заданного промежутка времени.

А вот так эта функция потом используется:

Понимать такой код потом получается быстрее и менее напряжно.
Архитектура
А этот параграф — ода интерфейсам. Если вы однажды упоролись по SOLID, то обратной дороги уже нет, проектировать систему без абстракций становится больно.
Интерфейсы помогают продумывать отношения между сущностями. Это настолько офигенно, что за первые пару дней я не написал ни строчки продуктового кода — только интерфейсы, типы и сигнатуры функций.
Тесты и рефакторинг
Для разработки мы выбрали методологию TDD. Здесь Тайпскрит тоже пришёлся кстати, потому что имея типы и интерфейсы проще создавать (или генерировать, кому как больше нравится) стабы и моки.
В рефакторинге же самое кайфовое — использовать встроенные инструменты IDE: rename symbol, extract function и прочее. Мне не нужно беспокоиться, переименовал ли я все сущности в проекте — об этом позаботится IDE. Моё дело — подобрать правильное название, дальше — пусть потеют роботы.
Минусы
Самый жирный минус Тайпскрипта — он требует времени. Много. Дополнительного. Времени.
Оно будет уходить на то, чтобы покрыть функции и методы типами, привести в соответствие с типами все аргументы, понять, почему какой-то тип не работает для метода из сторонней библиотеки. (Здесь шутка про «нельзя просто так взять и написать быстрый черновик функции, не используя any
».)
Второй минус, чуть поменьше, — не у каждой библиотеки есть описание для Тайпскрипта в DefinitelyTyped. Основные решения там есть, конечно, но для менее известных библиотек описаний может не быть. Например, для clsx его не было.
Если вы проводили по 5 часов за тем, чтобы покрыть типами стороннее API, вы понимаете эту боль.
Окей-окей, а когда обновление-то?
А оно в продакшене уже 🙃
- Если вы пользуетесь веб-версией, то скорее всего, приложение на телефоне обновилось само.
- Обновление для Android появилось в магазине пару недель назад.
- Обновление для iOS появится совсем скоро.
Апргейд версии должен был пройти гладко и без потерь, но пишите, как-оно-что. Вдруг мы всё-таки что-то поломали по пути.
Ссылки
О приложении:
Скачать БЕЗ РЕГИСТРАЦИИ И СМС:
Крутые ребята:
Хвастаюсь книгами:
Всякое-техническое: