Работая с JavaScript и Typescript в качестве полнофункционального разработчика почти два года, я размышлял о том, как работает разработчик в экосистеме JS/TS/Node.js. В этой статье я расскажу о том, что мне действительно понравилось, и о болевых точках, которые я чувствовал.

Плюсы:

Один и тот же язык в стеке

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

Изоморфный код

Повторное использование кода — это здорово. Если вы используете Typescript, вы можете совместно использовать типы во внешнем и внутреннем интерфейсе. Это, пожалуй, мой любимый аспект использования полного стека Typescript. Вы можете смоделировать свой домен с помощью типов Typescript, и ваш бэкенд может использовать эти типы для ввода запросов, ответов, схем базы данных и т. д., в то время как ваш интерфейс может вводить данные, возвращаемые вашим бэкэндом, и данные, которые он отправляет в запросах. Так как они используют общие типы, вы уменьшаете дублирование, а также бесплатно синхронизируете свои типы. Когда вы используете другой язык на бэкэнде, вам нужны два набора типов, и особенно если у вас есть разные разработчики или команды, работающие над фронтендом и бэкендом, если бэкэнд-команда решит обновить API, сложнее убедиться, что нет в результате код клиента сломан.

В дополнение к совместному использованию типов также здорово иметь возможность совместно использовать служебные функции, бизнес-логику и т. д. Например, в проекте, над которым я сейчас работаю, мы можем обмениваться схемами проверки между интерфейсом и сервером. Это позволяет нам проверять формы на внешнем интерфейсе и запрашивать тела на бэкэнде, используя точно такую ​​же логику проверки. Мы не выдавали 422 в течение некоторого времени, и нам дали уверенность, что любые ошибки в форме могут быть отображены пользователю до отправки запроса в наш сервер. В качестве другого примера мы показываем рассчитанные значения пользователям во внешнем интерфейсе на основе их ввода в режиме реального времени, прежде чем они отправят форму. Те же вычисления необходимы на бэкенде, поэтому мы смогли разделить эти функции по всему стеку.

Допускает несколько парадигм программирования

В JavaScript есть функции, которые позволяют использовать как объектно-ориентированное, так и функциональное программирование. Хотя в целом хорошо поддерживать единый стиль программирования в кодовой базе, определенные парадигмы имеют смысл в разных ситуациях. Например, если вы используете хуки React на внешнем интерфейсе, вы можете использовать более функциональный стиль, тогда как объектно-ориентированное программирование часто является хорошей парадигмой при моделировании вашего домена на бэкэнде. Наличие гибкости — это хорошо, в отличие от необходимости заставлять ваш проект соответствовать стилю, основанному на используемом языке.

Синтаксис

Синтаксис похож на Java, поэтому он кажется относительно знакомым с самого начала. JavaScript предоставляет изрядное количество синтаксического сахара, так что вы можете быть краткими и многого добиться с относительно небольшим объемом кода, не сильно теряя при этом в удобочитаемости. Я считаю, что он обеспечивает синтаксическую простоту таких языков, как Python, и в то же время имеет много общего со многими другими популярными языками (Java, C#, C, C++ и т. д.).

Элегантная обработка асинхронности

Поскольку сеть по своей природе асинхронна, обработка асинхронности в JavaScript является первоклассной. Синтаксис со временем улучшился: от использования обратных вызовов событий до цепочки промисов и асинхронности/ожидания. Требуется некоторое время, чтобы уложить в голове ментальную модель, необходимую для правильного использования async/await, хотя асинхронность по своей сути сложна, а JavaScript предоставляет хорошую абстракцию, чтобы максимально упростить ее.

Простая архитектура

JavaScript по умолчанию является однопоточным, что упрощает работу с ним. Что касается серверной части, сообщество Node.js обычно предпочитает выполнение параллельной обработки в отдельном узле/службе, хотя у него есть поддержка многопоточного программирования через стандартную библиотеку `child_process`. У вас могут возникнуть проблемы, если вы заблокируете основной поток процессом, интенсивно использующим ЦП, хотя в целом я обнаружил, что простая архитектура Node.js упрощает развертывание, отладку и анализ моих приложений. Если у вас высокая нагрузка на ЦП, Node.js может быть не лучшим вариантом, но для многих веб-приложений на основе CRUD это не проблема.

Архитектура Node.js, управляемая событиями, также хорошо сочетается с моделью HTTP-коммуникаций типа «запрос-ответ». HTTP-сервер из стандартной библиотеки — это просто эмиттер событий, который может генерировать события на основе входящих запросов. Затем у вас могут быть обработчики, прослушивающие эти события и отвечающие на них. Это очень простая архитектура, интуитивно понятная в веб-контексте.

Сообщество разработчиков открытого исходного кода

JavaScript имеет сильное сообщество разработчиков открытого исходного кода. Как правило, я могу найти хорошо поддерживаемый пакет для большинства своих нужд, что избавляет меня от траты времени на разработку внутренних решений и позволяет мне сосредоточиться на более интересных проблемах. Таким образом, разработка с использованием JavaScript кажется очень продуктивной.

Я часто слышу критику, что в сообществе JavaScript много «текучки», т. е. проекты приходят и уходят, а сообщество, похоже, не останавливается на библиотеках. Возможно, это было проблемой в прошлом, но по состоянию на 2021 год, похоже, существует стабильный набор библиотек, на котором остановилось сообщество, по крайней мере, для профессиональных проектов. Некоторые примеры: для внешнего интерфейса вы в основном увидите Angular, React или Vue. Для серверной части вы увидите Express, Nest.js, Fastify или Koa. Для ORM базы данных вы увидите TypeORM, Sequelize, Mongoose или Knex.js. Для проверки вы увидите Joi, Yup или Zod. Для HTTP-клиента вы увидите axios или node-fetch. Короче говоря, я не думаю, что аргумент оттока больше не применим.

Наряду с сильным сообществом открытого исходного кода он получил широкое распространение в отрасли. Это привело к тому, что многие поставщики услуг и программного обеспечения обеспечивают первоклассную поддержку языка JavaScript. Если вы ищете SDK, вы можете быть уверены, что если он существует, то он будет и для JavaScript. Если вы хотите использовать платформу как услугу (PaaS), вы можете быть уверены, что большинство поставщиков предоставят поддержку JavaScript/Node.js. Это упростило обращение и использование сервисов и инструментов.

Первоклассная поддержка JSON

Поскольку JSON является предпочтительным форматом данных в Интернете, приятно использовать язык, в котором он кажется очень встроенным. Нет необходимости в сложной сериализации, поскольку JSON напрямую сопоставляется с объектами JavaScript. Это делает обработку данных для веб-приложений очень интуитивно понятной с помощью JavaScript.

Минусы:

Сложные инструменты

Некоторые инструменты вокруг Javascript стали довольно сложными. Я думаю, это в основном связано с тем, что Javascript запускается в очень многих разных средах, которые поддерживают разные функции языка и имеют разные требования к использованию и ограничения ресурсов. Не говоря уже о хаосе модульной системы, в которой существует несколько конкурирующих стандартов, и вам часто приходится переключаться между одним или другим. Понятно, что Javascript как язык пытается поддерживать множество различных вариантов использования, и это проблема, которой нет у большинства других языков бэкенда. Я недавно играл с Golang, и простота набора инструментов завидна по сравнению с Javascript. Имейте в виду для перспективы, когда вы читаете следующие несколько абзацев, что эквивалентом в Golang является «go build».

Что касается внешнего интерфейса, вам нужно связать свои активы с помощью чего-то вроде Webpack. Вам также может понадобиться преобразовать свой код в более раннюю версию ECMAScript с помощью Babel, если вы поддерживаете старые браузеры. Если вы используете React, вам также необходимо преобразовать JSX в JS. Если вы используете Typescript, вам необходимо скомпилировать TS в JS. Вы также можете заняться разделением кода и другими настройками сборки, которые могут забросить вас глубоко в кроличью нору Webpack.

Процесс сборки внешнего интерфейса и сборки сам по себе сложен, но я не хочу уделять ему слишком много внимания, поскольку на данный момент нет никакого способа обойти использование Javascript, если вы создаете умеренно сложное веб-приложение. процесс, как правило, немного проще, но не намного. Как правило, транспиляция в более ранние версии ECMAScript не особо полезна, поскольку вы контролируете, в какой среде будет работать ваш серверный код. Однако довольно часто сервер Node.js объединяется с инструментом сборки Typescript CLI или с Webpack (или другие менее популярные инструменты).

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

Инструменты могут быть медленными

Javascript — достаточно быстрый язык для своих вариантов использования, но это не мой первый вариант для написания важных инструментов разработки. Тем не менее, естественно, большая часть инструментов в сообществе Javascript/Typescript/Node.js была создана с помощью Node.js. Сюда входят такие популярные инструменты, как Webpack, Babel, ESLint, TSC, Jest, JSDOM и т. д. Это все инструменты, которые будут использовать большинство кодовых баз Javascript в дикой природе, и, по моему опыту, они довольно медленные.

Создание серверного приложения Node.js среднего размера с помощью Webpack обычно занимает более 30 секунд. Это складывается, если вы собираетесь запускать свою сборку в CI. Были предприняты попытки улучшить инструменты сборки с помощью таких проектов, как ESBuild (https://github.com/evanw/esbuild), написанных на Golang. Тенденция использования системных языков для создания инструментов Javascript может значительно улучшить ситуацию, но может пройти год или два, прежде чем они получат широкое распространение. На данный момент Webpack, Babel, TSC и т. д. сильно встроены в экосистему.

Языковые особенности

Javascript, как известно, довольно причудливый язык. Такие вещи, как `typeof null === “object”`, выделяются в моей голове. Как правило, со временем он улучшался, но в языке были оставлены некоторые особенности для обеспечения обратной совместимости. Честно говоря, причуды не слишком сильно повлияли на мой опыт. Но иногда вы сталкиваетесь со странностями, которые может быть трудно отладить, если вы не знаете, что ищете.

С Typescript, поскольку он является надмножеством Javascript и компилируется в Javascript, он должен поддерживать совместимость с особенностями Javascript и изменять свое поведение, чтобы приспособиться. Из-за этого я столкнулся с очень странным поведением в Typescript. Вот пример: https://github.com/microsoft/TypeScript/issues/46927. Попытка типизировать динамический язык по своей сути сложна и не идеальна. Таким образом, даже при использовании Typescript вы никогда не чувствуете, что получаете полную безопасность типов.

Заключение

В целом, я считаю Javascript/Typescript отличным языком и экосистемой для создания полнофункциональных веб-приложений. Он очень хорошо подходит для большинства случаев использования. Где я мог бы не рекомендовать это для приложений, где:

  • Производительность имеет первостепенное значение
  • Рабочая нагрузка интенсивно использует ЦП
  • Кодовая база станет большой, со многими разработчиками/несколькими командами. Медленный инструментарий может быть препятствием (по крайней мере, на данный момент, пока он не улучшится).

Надеюсь, вы нашли это полезным! Вы можете найти меня на Linkedin по адресу https://www.linkedin.com/in/taylormclean/. Не стесняйтесь обращаться, если у вас есть какие-либо вопросы или вы хотите поболтать.