Мысли об экосистеме JavaScript, её настоящем и немного о будущем

Что было, что будет, чем сердце успокоится

Sergey Aksenov
6 min readFeb 8, 2017

В связи с усталостью от отдыха и невозможностью себя особо чем-то занять в зимней Москве, а также для поддержания навыка изучения новых технологий, погрузился практически с нуля на несколько дней в волшебный мир JavaScript в его клиентской и серверной ипостасях. Нижеследующий текст написан больше для структурирования собственных мыслей и ощущений, но может быть полезен “юношам, обдумывающим житьё”, ибо первое впечатление часто самое верное.

Сначала немного истории. JavaScript родился в 1995 году в рамках браузера Netscape 2.0 как язык, призванный придать динамики веб-страницам: анимация, изменение поведения элементов при наведении мыши — то, к чему мы все сегодня привыкли. Прототип его был написан за 10 дней, что заметно и по сию пору (см. с 1:20). Некоторое время, будучи в бете, он назывался LiveScript, но потом кто-то решил сыграть на тогдашней популярности Java, и понеслось.

Новшество поддержал Microsoft и ещё пара ныне мёртвых или поглощённых компаний, но все они решили делать собственные версии, с индивидуальными перделками и свистелками. В результате на рынке появилось несколько диалектов с разными названиями и слегка совместимых между собой. Это был первый звонок.

Ребята из Netscape быстро попытались включить задний ход, буквально через год, в 1996 выпустив совместно с Европейской Ассоциацией Производителей Компьютеров (штоа?) стандарт под названием ECMAScript, но никто не мог произнести это сочетание букв, поэтому язык так и называют JavaScript, несмотря на то, что к Java он отношения как не имел, так и не имеет. (здесь анекдот о морской свинке) До 1999 года работы по стандартизации кипели, были выпущены несколько версий умных устанавливающих документов, после чего на развитие языка был забит массивный нержавеющий болт.

Здесь стало ясно, что у языка нет единого хозяина и бенифициара, поэтому каждый стал развивать свою версию кто в лес, кто по дрова. Главной проблемой развития стала необходимость поддержки изменений во всех браузерах. Логично, что если Opera, Chrome и FireFox поддержали какое-то нововведение, а Internet Explorer — нет, то использовать это нововведение всё равно нельзя, ибо тогда сайт не будет работать у какого-то заметного количества посетителей. Поэтому были придуманы polyfills — библиотечки-прокладки, имитирующие поддержку новых фич в старых броузерах. Это был второй звонок.

К 2008 году сложившееся вокруг языка сообщество (в основном производителей браузеров) собралось с духом и решило хоть как-то стандартизировать то, что было нагенерено за эти 10 лет (правда, они пытались делать это и в процессе, но не осилили). Но было поздно: третьим и последним звонком стал Node.js — сервер на JavaScript, и спаренный с ним менеджер зависимостей npm. Зачем были созданы они — для меня до сих пор загадка. Слышал версию о том, что это было придумано с целью дать возможность фронтендерам приложить свои знания JavaScript на бэкэнде, но мне она кажется настолько сомнительной, что даже и не знаю. Кстати, они же стали последним гвоздём в крышку гроба попыток перестать использовать название “JavaScript”, и вообще всё, содержащее слово “Java”. Теперь каждый второй проект вообще хостится на специальном домене js.org.

В итоге стандарт был принят в 2009-м, и эта версия (её называют ECMAScript v5 или коротко ES5) к 2011-му более-менее поддерживалась большинством браузеров. Однако злоключения языка на этом не прекратились: разброд и шатания снова начали накапливаться, и стало ясно, что единственный способ бороться с расползанием червей из банки — это брать каждый раз банку на размер больше.

Новым драйвером прогресса стали фронтенд-фреймворки, AngularJS (с тех пор вышла новая, несовместимая с первой вторая версия) и React, соответственно в 2010 и 2013 годах. Они были прикольные и позволяли создавать работающие прямо в браузере довольно развесистые приложения, вполне сравнимые по функционалу с приложениями как десктопными, так и мобильными, набравшими к тому времени популярность.

Благодаря развитию этих и некоторых других фреймворков, к 2014 году экосистема снова превратилась в адскую смесь несовместимых диалектов, прокладок для обеспечения совместимости между ними и т.п. Поскольку прицепить любую прокладку стало можно одной командой npm install, все начали делать это, не включая мозг. Поскольку npm автоматически скачивал все используемые нужным пакетом другие пакеты — каждый его вызов приводил к увеличению объёма кода в геометрической прогрессии. (здесь анекдот про пакет в пакете с пакетами) На сегодня, например, даже простые примеры типа “а сейчас я покажу, как нажимать на кнопочку в React” тащат за собой от 20 до 30 мегабайт (!!) кода зависимостей. Для сравнения, полноценный RESTful-бэкэнд на PHP с аутентификацией, авторизацией, ORM, MVC и юнит-тестами (!) ограничивается 5–10 мегабайтами внешних пакетов, хотя механизм автоматического подключения зависимостей там в целом аналогичный.

История повторялась: сообщество попыталось загнать все новинки в очередной стандарт (процесс стандартизации ES6 начался в 2014 и закончился в 2015), но было поздно и космос породил очередное хтоническое чудовище: появился штопаный монстр под названием Babel. Если вкратце, то это компилятор программ из более новых версий JavaScript в более старые, чтобы они хоть как-то стабильно работали в реальном мире, попутно максимально сокращая их размер, чтобы ускорить загрузку. Выглядит результат его работы обычно как-то так:

Я в последнее время не вижу ни одного более-менее серьёзного проекта на JavaScript, чтобы там не использовался Babel. Откуда я лично делаю следующее заключение: JavaScript в том виде, как он появился в 1995 и пытался развиваться до 2005, окончательно и бесповоротно мёртв. Он по сути стал языком низкого уровня, как байт-код, а пишут теперь на более высокоуровневых языках, типа ES6, ещё не стандартизированном ES7, JSX (внутренний диалект React, позволяющий, ко всему прочему, смешивать JavaScript c собственным диалектом (x)HTML в произвольных пропорциях), CoffeeScript, TypeScript (очередное порождение Microsoft) и т.п.

(тут я хотел сделать отступление про asm.js, но решил, что он заслуживает отдельного рассказа)

В общем, перед нами типичный пример как делать не нужно: сваять что-то на коленке за неделю, отрелизить, чтобы утереть нос конкурентам, дальше сражаться с этими конкурентами, которые пытаются компенсировать отставание на старте, не думать про документацию и стандартизацию, получить расползающуюся кучу плохо пахнущей субстанции, тратить колоссальные усилия на тщетные попытки сгрести её обратно, игнорировать складывающееся вокруг комьюнити, обнаружить в какой-то момент, что комьюнити стало в ответ игнорировать тебя и у него неплохо получается, бегать вокруг с криками “ребята, давайте жить дружно!”, и в итоге накрыть кучу брезентом и начать насыпать поверх него новую кучу, в надежде, что в этот раз всё будет лучше.

Ну-ну. В ближайшее время нас, очевидно, ждёт новый виток этой вакханалии, поскольку на JavaScript понемногу получается писать мобильные и десктопные приложения, и это выходит намного, намного дешевле, чем нанимать программистов на Java, С++ или С#. При соответствующем, разумеется, снижении качества и повышении прожорливости к ресурсам, ну да кого это в наше время волнует?

Итого, сегодняшние типичные проекты на JavaScript и производных от него языках характеризуются:

  • сумасшедшим количеством кода в зависимостях. Они постоянно обновляются, поэтому если не придерживаться конкретных версий — всё будет постоянно ломаться. Увеличиваясь в размерах, проект одновременно оказывается привязан к старым версиям пакетов, и чем дальше — тем дороже миграция;
  • как следствие, часто разработать новый модуль проще, чем использовать существующие. Количество модулей, выполняющих одинаковые функции, увеличивается быстрее, чем их авторам надоедает их поддерживать;
  • как следствие, каждую задачу можно решить минимум двумя, а как правило тремя-четырьмя способами. Какой из них более правильный, какой пакет выживет в перспективе 2–3 лет — каждый раз приходится гадать на кофейной гуще (pun intended);
  • как частичное следствие — адóвые танцы с бубном для разделения конфигураций окружений на рабочее и боевое, ибо это можно сделать примерно пятью способами и каждый разработчик считает именно свой правильным. Конфигурации между собой несовместимы, часто эффекты, которые вызываются костылями для одних решений, невозможно повторить в других;
  • разработчики в массе своей кладут с прибором на стандарты. Прокладки, полифиллы и Babel привели к тому, что в рамках одного файла можно смешивать синтаксисы разных версий и диалектов языка. В итоге когда в “больших” пакетах кто-то вдруг решает последовать стандартам, мелкие пакеты, зависящие от них, от этого ломаются (будто было мало, что они ломались сами по себе);
  • как следствие, качество кода мало кого волнует, потому что единого понимания, что есть качественный код — нет ни у кого. Принцип “хуяк-хуяк — и в продакшн” доминирует, спагетти-код является нормой, исключения лишь подтверждают это правило;
  • как следствие из всего предыдущего, совершенно невозможно организовать более-менее масштабную командную разработку. При числе разработчиков в три и более нужен выделенный четвертый человек, который не будет писать код, но будет заниматься исследованиями, тестированием новых версий пакетов, написанием и постоянным редактированием регламентов и манифестов, слежением за их соблюдением, организацией коммуникации между участниками команды;

В итоге совершенно неудивительно, что более-менее приличные крупные проекты на серверном и/или клиентском JS редки, как золотые самородки, оценки сроков первоначального запуска (по отзывам знакомых CTO и аналитиков) промахиваются в разы, оценки внедрения новых фич даже (или правильно будет сказать — в особенности) по чётко сформулированным бизнесом требованиям промахиваются на порядки.

Что с этим всем делать и как в этом всём жить — большой вопрос и тема для отдельного исследования. Пока резюме — avoid the moor in those hours of darkness when the powers of evil are exalted.

--

--