Чем хорош (и чем плох) Typescript: опыт UI-разработчиков

Здравствуйте, меня зовут Александр Черников. Я руковожу разработкой UI проекта «Цифровой корпоративный банк» — обновлённой версии Сбербанк Бизнес Онлайн, интернет-банка для юридических лиц. Мы разрабатываем stand-alone клиент, мобильное приложение и, собственно, web-клиент, о котором и пойдёт речь. В своих статьях я буду делиться ценным опытом нашей команды, а конкретно в этом посте опишу наш технологический стек и остановлюсь на том, почему мы выбрали Typescript в качестве основного языка.

xes98d_jddahgkwwus8rjf76hfo.jpeg

Новую версию Сбербанк Бизнес Онлайн мы пишем 2,5 года. Уже в следующем году мы планируем перевести на него всех корпоративных клиентов Сбербанка.

Итак, начнем со стека. Мы внедрили TypeScript, React, Reflux (legacy), Redux, Bluebird Promise и Bootstrap. Стили пишем на LESS. Все это добро мы собираем с помощью Babel, Webpack и его плагинов. Webpack пока первой версии, но собираемся перейти на вторую. Многие могут спросить: зачем нам Typescript и Babel одновременно? Во-первых, раньше TypeScript не все умел транспилировать, и только недавно сравнялся с Babel по этой функциональность. Во-вторых, TypeScript не умеет кэшировать. А babel умеет хранить готовые ES5 скрипты в папке. Если исходники не поменялись, он сразу берет их оттуда. Когда проект собирается несколько минут, такая экономия времени очень радует.

Стек технологий достаточно свежий. Ребятам приходится вникать сразу в несколько вещей: например, в TS, React, Redux, в сам проект и в термины нашего банка. Из 50–60 человек только 20 процентов работают в штате, остальные подключаются от вендоров и часто меняются.

Как мы справляемся в таких условиях с code-review? Раньше несколько самых опытных разработчиков смотрели код всех команд, была такая небольшая пирамида. Сейчас мы стараемся равномерно распределить по командам. Во многих командах появились так называемые эксперты (хорошо разбираются в проекте, знают, что и где лежит), чтобы не изобретали велосипеды и прочее. Соответственно они review«ят не только ребят из своей команды, но и из других.

Review у нас немного автоматизировано и на pull-request у нас добавляются лейблы, которым нужно соответствовать. Тогда они станут зелеными и ПР автоматически сольется. Лейблы есть разные: Code-style, Expert, Architect, CSS, E2E-test и другие. Если меняются .less файлы — добавляется CSS, если меняется какой-то код ядра или низкоуровневых вещей — добавляется Architect. Чтобы получить Expert, нужно набрать как минимум 2 аппрува экспертов.
И если человек новенький на проекте или не очень силен в JS, тогда его код будет сильно отличаться от того, что было до code-review.

TypeScript и JavaScript


Я застал тот момент, когда многие писали на TS и использовали новые фичи, которые транспилируются в ES5. Но даже тогда мы использовали TS для типизации, для некоего статического анализа кода на ошибки. Да, на JS можно написать код грамотно и правильно, но он тебя не подстрахует так, как TS. Кто-то ставит в минусы, что приходится много писать TS-кода (overhead), т.е. типизация, типы, интерфейсы и др. Когда мы рефакторили «старый» код JS > TS, то выявлялись элементарные ошибки, которые сработают только в runtime. То запятая не там стоит, то точку забыли, то скобки рано закрыли и т.д., не говоря уже про недосягаемый код и неиспользуемые аргументы и пр… Когда система большая и команда не может покрыть всю систему тестами, то TS спасает. При 3000–4000 скриптов вообще трудно представить, как жить без TS.

Конечно, когда мы пишем код на JavaScript, то можем помочь компилятору и писать код, словно у нас типизированный язык: не переопределять переменные, не записывать в них разные типы, возвращать всегда один и тот же тип. Возникает вопрос: если при этом использовать babel.js, есть ли в таком случае смысл в изучении TypeScript?

Мы часто спорим по этому поводу. Некоторые коллеги говорят: «А зачем нам TS? Мы пишем код грамотно и проводим тщательно code-review, отбираем людей на собеседовании, да и вообще джедаи JS». Но ведь человеческие факторы никто не отменял: лень, торопливость, невнимательность. Ничего не мешает подключить TS к вашему JS-коду. Если у вас действительно нет ни одной ошибки, то компилятор ничего не найдет — можете радоваться тому, что у вас отличная команда, и звезды сложились как надо. Но перестраховаться с помощью TS все равно не мешает. Тем более, что и особых затрат это не потребует.

К тому же, в этом году в версии 1.8 в TS сделали удобную фичу. Теперь можно проверить типы в чистом JS — достаточно добавить файлы ».js» в проект и allowJs флаг. Если есть какой-то код, который не хотите проверять, то спокойно его можно игнорировать через аннотацию @ts-nocheck. Во время code-review мелкие баги отловить почти нереально, а TS помогает экономить силы и время. А не то подольешь релизную ветку в develop с конфликтами в 100 файлов… хотел бы я посмотреть, как человек хладнокровно нажмет кнопку MERGE.

TypeScript vs Flow


«А как насчет Flow?» — спросите вы. Мы выбирали между ES6 и Typescript, про Flow тогда никто не знал. Для тех кому интересно, в чем разница их статического анализа кода, могу посоветовать интересный доклад Ильи Климова с конференции HolyJS 2017 Piter, где он сравнивает TypeScript и Flow.

Ложки дегтя


Помимо overhead у Typescript есть еще несколько недостатков:

  1. Существенное замедление сборки проекта. Но это, опять же, исключительно в нашей специфике сборки: Webpack + TS + Babel. У кого такая же конфигурация (± babel), могу посоветовать использовать загрузчик ts-loader обязательно с флагом transpileOnly, а TSC запускать параллельно. А в режиме инкрементальной сборки (--watch), держать 2 процесса отдельно: webpack --watch и tsc --watch.
  2. Возникают проблемы с OutOfMemory ошибками nodeJS, особенно неприятные такие сюрпризы, когда нужно собрать проект и выпустить релиз через 3–4 дня, а быстро решить их не получается.
  3. Необходимость актуализации версий .d.ts для внешних библиотек. Слава Богу, закончилась пора с tsd > typings. И теперь все можно качать сразу через npm > @types. А что если вышла новая версия библиотеки, lodash например, а .d.ts еще нету? Тогда приходится выбирать: дописать самому (в репозиторий или выложить ПР на github в репозиторий DefinitelyTyped) или пока не использовать эту фичу.
  4. Поиск разработчиков с опытом на TypeScript. Это отдельные слезы нашего HR. Насколько мне известно, на рынке у всех сейчас проблема с поиском «продвинутых» frontend-разработчиков, с опытом написания серьезных SPA, Angular | React | Vue, Typescript, Redux и пр.

© Habrahabr.ru