
Почему для отображения кнопки, увеличивающей счетчик, нужен JavaScript-фреймворк, система сборки, бандлер и папка node_modules, которая весит больше, чем бортовой компьютер «Аполлона-11»?
Ответ прост, и мы тридцать лет его избегаем: веб сломан.
Не для документов — для них он подходит. Он сломан для приложений. А нас нанимают создавать именно приложения.
Стек на костылях
Веб был создан для просмотра документов. Связанных документов. Тим Бернерс-Ли (Tim Berners-Lee) — британский ученый, который изобрел Всемирную паутину в 1989 году, работая в CERN (Conseil Européen pour la Recherche Nucléaire — Европейская организация по ядерным исследованиям), — хотел, чтобы физики обменивались статьями с кликабельными ссылками. Вот и все.
HTML не задумывался как фреймворк для приложений. Он должен был размечать текст. Можно было стилизовать его встроенно — тегами <font color="blue">, атрибутами bgcolor, вложенными таблицами для верстки — но смешение контента и представления делало разметку нечитаемой. Поэтому мы добавили CSS, чтобы разделить их. Когда нам понадобилось, чтобы документы выполняли определенные действия, мы прикрутили JavaScript — язык, который, как известно, был разработан за десять дней.
А потом нам потребовалось еще больше! Настоящие приложения. Управление состоянием. Компоненты. Маршрутизация. Поэтому мы добавили jQuery, затем Backbone, затем Angular, затем React, затем Vue, затем Svelte, затем Solid, затем Qwik, затем все то, что выпустили на этой неделе.
Каждый слой — это заплатка на «прорехах» слоя под ним, и каждое добавление обнажает сложность, которую невозможно было абстрагировать.
Алан Кей (Alan Kay), ученый в области компьютерных наук, изобретатель объектно-ориентированного программирования и пионер графического интерфейса, высказался прямо в интервью ACM Queue:
«Интернет создан настолько хорошо, что большинство воспринимает его как природный ресурс, вроде Тихого океана, а не что-то искусственное. Когда в последний раз технология такого масштаба была настолько безошибочной? По сравнению с ней, веб — просто шутка. Веб создали дилетанты».
Интернет — это инженерные системы: TCP/IP, маршрутизация пакетов, DNS — инфраструктура, которая позволяет компьютерам находить друг друга и коммуницировать. Его тщательно проектировали десятилетиями, и он работает без перерыва с 1969 года. Веб — это приложение, работающее поверх интернета: HTTP, HTML, браузеры. Смысл слов Кея в том, что лежащая в основе сеть — это чудо, а то, что мы построили сверху — дело рук дилетантов.
Кей указал на коренную проблему: «Вам хочется, чтобы он [веб-браузер] стал мини-операционной системой, а люди, которые его разрабатывали, ошибочно полагали, что создают приложение». Браузер должен был стать платформой для запуска программ. Вместо этого, его сделали для отображения документов — и с тех пор мы занимаемся его доработкой.
Тест на иконку
Хотите увидеть эту дисфункцию в миниатюре? Попробуйте отобразить цветную иконку.
React (с использованием react-icons):
import { FaStar } from 'react-icons/fa';
// Надеюсь, SVG использует currentColor внутри
<span style={{ color: 'blue' }}>
<FaStar />
</span>
Но что, если в SVG-файле жестко прописаны параметры заливки? Тогда вам понадобится кастомный компонент, инструмент SVGR в пайплайне сборки или придется встраивать весь SVG-код вручную и переопределять атрибуты.
Vue:
<template>
<svg-icon name="star" class="icon-blue" />
</template>
<style>
.icon-blue {
color: blue; /* Возможно, сработает? Зависит от реализации SVG */
}
.icon-blue >>> path {
fill: currentColor; /* Глубокий селектор (устарел) */
}
</style>
Angular:
import { DomSanitizer } from '@angular/platform-browser';
// Обход безопасности для встраивания SVG напрямую
this.iconHtml = this.sanitizer.bypassSecurityTrustHtml(svgString);
/* Использовать инкапсуляцию для стилизации */
::ng-deep svg path {
fill: blue !important;
}
Web Components:
// Shadow DOM усложняет внешнюю стилизацию, а не упрощает ее
class MyIcon extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
// Необходимо явно предоставлять кастомные CSS-свойста
// или использовать селекторы ::part(),
// или просто отказаться от инкапсуляции полностью.
}
}
Четыре экосистемы. Четыре разных ритуала. Все хрупкие. Все требуют, чтобы вы понимали детали реализации того, как работают SVG, как работает специфичность CSS, как работает инкапсуляция вашего фреймворка — и как все это отказывается работать вместе.
А теперь SwiftUI:
Image(systemName: "star.fill")
.foregroundColor(.blue)
И Jetpack Compose (Android):
Icon(
Icons.Default.Star,
tint = Color.Blue
)
Две строки. Без сборки. Без CSS. Без конфликтов специфичности. Без обхода путей безопасности. Без костылей для инкапсуляции. Color — это свойство, потому что так и должно быть — эти платформы создавались для сборки приложений с нуля.
Дело не в том, что Apple или Google более инновационны. Это закономерный итог, когда ты проектируешь систему для приложений изначально, а не пытаешься переделать программу для просмотра документов.
Стандарт, который не стал таковым
Если вы в этой индустрии достаточно давно, вы помните, какие надежды возлагались на Web Components.
W3C (World Wide Web Consortium — Консорциум Всемирной паутины) посмотрел на хаос в сфере фреймворков — React против Angular против Vue против Ember против всего остального — и сказал: «Мы это исправим. Мы создадим стандарт. Custom Elements [пользовательские элементы — набор технологий, которые позволяют разработчикам создавать повторно используемые пользовательские элементы с собственными HTML-тегами и функциональностью]. Shadow DOM [теневая DOM — технология, которая позволяет создавать инкапсулированные DOM-деревья внутри элементов]. HTML Templates [шаблоны структуры страниц, стили и базовые элементы дизайна для веб-сайтов]. Нативные компоненты, благословленные самими спецификациями».
Набор технологий Web Components должен был положить конец конфликтам фреймворков. Стандарт, который заменит их все.
Знаете, что произошло? Web Components стал одним из них.
Разработчики на React не перешли на него. Vue продолжил расти. Появился Svelte. Фреймворки никуда не делись — разработчики просто добавили совместимость с Web Components как пункт в их документации. «Стандарт» стал еще одной альтернативой в и без того перегруженном ландшафте.
Почему? Потому что набор технологий Web Components не решал реальную проблему. Реальная проблема — не в том, «какую модель компонентов выбрать», а в том, что мы создаем приложения внутри программы для просмотра документов, у которой нет встроенных понятий компонентов, состояния или интерактивности. Web Components прикрутили модель компонентов к платформе, которая для этого не создавалась. Знакомая ситуация?
Сценарий повторяется: выявить симптом, наложить заплатку, объявить победу, наблюдать, как проблема продолжает напоминать о себе.
Бег на месте как доказательство
Вот аргумент, который вы часто услышите: «Так эволюционирует программное обеспечение. Со временем мы совершенствуем инструменты. Итерации — нормальное явление в сфере ПО».
Это неверно.
Представьте, что вся строительная индустрия решила строить небоскребы, ставя садовые беседки друг на друга. Каждый год появлялась бы новая «фреймворк-система для укладки беседок» — улучшенные скобы, лучшее распределение нагрузки, инновационный раствор. На конференциях спорили бы о вертикальной и горизонтальной архитектуре. Никто не задался бы вопросом: почему мы вообще укладываем беседки?
Такова веб-разработка.
Взгляните на генеалогию фреймворков. jQuery появился, потому что прямое управление DOM было мучительным. Backbone и Angular появились, потому что спагетти-код на jQuery стало невозможно поддерживать. React появился, потому что Angular был слишком сложен — он предложил более простую ментальную модель с односторонним потоком данных. Vue появился, потому что Эван Ю (Evan You) хотел избавить «эффективные части Angular» от тяжеловесной механики. Svelte появился, потому что Рич Харрис (Rich Harris) счел накладные расходы React на виртуальную DOM излишними. Solid появился, потому что Райан Карниато (Ryan Carniato) хотел создать модель React без затрат на повторный рендеринг.
Каждый фреймворк — реакция на сложность предыдущего фреймворка. А не на недостатки платформы. Каждый последующих накладывают заплатки на заплатки предыдущего. Это бесконечный регресс управления симптомами, где каждое «решение» вводит новую сложность, которая порождает следующее «решение».
Фред Брукс в своей знаковой статье 1986 года «No Silver Bullet» («Никакой панацеи») различал существенную сложность (присущую самой решаемой проблеме) и случайную сложность (тот хаос, который мы создаем своими инструментами и выбором). Веб-стек — это памятник случайной сложности. Проблема «показать цветную иконку» имеет тривиальную существенную сложность. А четыре разных ритуала фреймворков, требуемых для ее решения — чистая случайная сложность.
Рич Хикки, создатель языка программирования Clojure, отточил эту мысль в своем резонансном выступлении «Simple Made Easy» («От простого к легкому»). Он заметил, что разработчики хронически путают понятия «легкое» (знакомое, доступное) и «простое» (не запутанное, не зависящее от чего-то). Мы хватаемся за сложные инструменты, потому что они нам знакомы, а потом удивляемся, почему наши системы становятся неподдерживаемыми. «Если вы сосредоточитесь на легкости, — предупреждал Хикки, — сможете стартовать с максимальной скоростью, но в итоге сложность вас убьет».
Подумайте, что мы воспринимаем как норму:
- чтобы кнопка, обновляющая число, требовала загрузки сотен килобайт JavaScript;
- «гидратация» — отправка UI дважды: один раз как HTML, второй раз как JS — считается стандартной архитектурой;
- инструменты сборки сложнее, чем сами приложения;
- целая дисциплина под названием «веб-производительность» посвящена тому, чтобы заставить платформу чуть менее плохо делать то, что она изначально делать не должна.
Это не нормально. Мы просто притворялись, что это нормально, так долго, что перестали ужасаться.
Что мы упускаем, если осваиваем только веб
Если вы осваивали программирование, создавая веб-сайты (а по статистике, скорее всего, так и есть), то можете не осознавать, насколько это все странно. Вы никогда не сталкивались ни с чем другим. Эта дисфункция — ваша исходная точка.
Позвольте описать другую сферу деятельности.
В SwiftUI или Jetpack Compose вы объявляете свой UI. Состояние встроено в язык — @State, @Binding, @Observable в Swift; remember, mutableStateOf в Kotlin. Когда состояние меняется, UI обновляется. Никакого сравнения виртуальных DOM. Никаких правил хуков для запоминания. Никаких массивов зависимостей useEffect для отладки в два часа ночи.
Компоненты — это просто структуры или функции. Вы не импортируете фреймворк, чтобы иметь компоненты — так работает сама платформа. Стили — это не отдельный язык, добавленный задним числом; это методы ваших представлений. Верстка — это не CSS Grid против Flexbox против флоатов против хаков position: absolute; это VStack, HStack, ZStack — контейнеры, которые делают то, для чего предназначены.
Там нет шага сборки. Нет конфигурации webpack. Нет встряски деревьев. Нет разделения бандлов. Нет черной дыры node_modules. Вы пишете код. Запускаете его. Он работает.
Это не утопия — у SwiftUI свои причуды, у Compose своя сложность обучения. Но обратите внимание на то, чего нет: постоянного ощущения, что вы боретесь с платформой. Гор абстракций между вашим замыслом и машиной. Сложностей инструментов, которые существуют исключительно для обхода ограничений платформы.
Отсутствующая сложность — вот как ощущается «спроектированность под задачу». Большинство веб-разработчиков никогда этого не испытывали.
Ловушка нормализации
Вот в чем настоящая опасность: пока мы считаем это нормой, мы не сможем от этого избавиться.
Философ Томас Кун (Thomas Kuhn) изучал, как происходят научные революции — и почему они так долго длятся. Его ключевое наблюдение заключается в следующем: ученые, работающие в рамках парадигмы, буквально не могут увидеть ее ограничений. Парадигма определяет, что считается легитимной проблемой, а что — допустимым решением. Аномалии объясняются или игнорируются. Только когда аномалии накапливаются до уровня кризиса, парадигма рушится — и даже тогда старые адепты редко обращаются в новую веру. Они просто в конце концов вымирают.
Кун описывал физику, но это относится и к веб-разработке. Смена фреймворков, взрывной рост инструментов сборки, хаки производительности — это аномалии. Это признаки того, что парадигма разрушена. Но поскольку мы внутри парадигмы, мы интерпретируем признаки разрухи как обычные проблемы, требующие обычных решений. Компоненты React Server. Архитектура «островов». Возобновляемость. Все это умно. И все это те же сложные обходные пути для программы просмотра документов, которая никогда не должна была стать платформой для приложений.
Философ Славой Жижек (Slavoj Žižek), опираясь на Алена Бадью (Alain Badiou), выявил этот паттерн в позднем капитализме: «шумно разрекламированная «перманентная революция», которая на деле является лишь клише «чем больше вещи меняются, тем больше они остаются теми же». Бадью называл это «одержимостью новизной и перманентным обновлением форм».
Это вся экосистема JavaScript в одном предложении. От React к Vue, к Svelte, к Solid — перманентное обновление форм, оставляющее нетронутой базовую дисфункцию.
Психоаналитик Эрих Фромм высказал схожее наблюдение о самой реформе: «Есть реформа и реформа; реформа может быть радикальной, то есть идущей к корням, или поверхностной, пытающейся латать симптомы, не затрагивая причин. Реформа, которая не является радикальной в этом смысле, никогда не достигает своих целей и в конечном итоге приводит к противоположному результату».
Смена фреймворков — это поверхностная реформа. Она латает симптомы — многословность, производительность, опыт разработчика — не касаясь причины: мы создаем приложения в программе для просмотра документов.
Споры, которые мы ведем — React против Svelte, SSR против CSR, монорепозитории против полирепозиториев — это споры об оптимизации внутри сломанных ограничений. Они исключают более важный вопрос: а должны ли мы вообще принимать эти ограничения?
Что дальше?
Я не собираюсь предлагать что-то взамен. Это было бы преждевременно — и, вероятно, ошибочно. Правильный шаг — не бросаться к решению, которое просто унаследует все заблуждения сломанной парадигмы.
Но я должен признать сложную проблему: дисфункция веба и его открытость, возможно, неотделимы друг от друга. Каждая «спроектированная под задачу» альтернатива контролируется владельцем платформы — не только язык, но и канал распространения. Swift — общедоступный ресурс, но App Store — нет. Kotlin — общедоступный ресурс, но Google Play контролирует распространение на Android. Веб, при всей своей неразберихе, подлинно нейтрален к вендорам: любой может запустить сервер, любой может создать браузер, никто не владеет платформой.
Любой преемник веба должен решить обе задачи: целевой дизайн и нейтральное к вендорам распространение. Это проблема, которую еще никто не решил.
Но мы даже не сможем начать ее решать, пока делаем вид, что текущее положение вещей приемлемо.
Правильный шаг проще: перестать делать вид, что это приемлемо.
Назовем вещи своими именами. Веб — программа для просмотра документов, которую мы три десятилетия пытаемся превратить в платформу для приложений. Постоянная чехарда — не прогресс. Конфликты фреймворков — не инновации. Это симптомы.
Как только мы действительно признаем проблему — как только перестанем воспринимать стек на костылях как нечто естественное, — создадим пространство для подлинно иного мышления. Не «какой JavaScript-фреймворк лучший», а «почему мы вообще пишем на JavaScript». Не «как оптимизировать гидратацию», а «почему гидратация существует».
Как могло бы выглядеть универсальное, открытое, связанное ПО — великий дар веба — без стека на костылях? Как добиться нейтрального по отношению к вендорам распространения без браузера-как-программы-для-документов? Вот те вопросы, которые мы даже не можем задать, пока заняты спорами о стратегиях гидратации.
Веб дал нам нечто необыкновенное: универсальное, открытое, связанное ПО, которое работает везде. Это важно. Но мы можем чтить то, что нам дал веб, признавая при этом, что текущий стек — это хаос.
Первый шаг — произнести это вслух.
Веб сломан. Хватит делать вид, что это не так.
Читайте также:
- 10 концепций бэкенда, незнание которых выдает слабого сеньор-разработчика
- Библиотека Three.js: разработка веб-приложений и игр с 3D-графикой
- Факты о веб-сайтах в 2018 году (и почему токенизация стала отличной идеей для этой отрасли)
Читайте нас в Telegram, VK и Дзен
Перевод статьи Kevin Muldoon: The Web Is Broken





