Исправление худшей ошибки, которую когда-либо совершал мир программного обеспечения

JavaScript — это мерзость. Язык, разработанный в спешке за две недели для облегчения динамического программирования веб-страниц, захватил мир, выйдя из-под контроля. С тех пор он заразил серверные бэкенды такими реализациями, как Node.Js, сильно переросшими свою первоначальную цель.

Успех JavaScript нельзя понять вне контекста его поколений. Это этоязык миллениалов. Поколение молодых программистов, которые хотят, чтобы все было легко, которые ожидают мгновенного удовлетворения и к черту последствия, встретили язык, который обещает (каламбур) именно это.

Зачем заморачиваться с дизайном, хорошей архитектурой и строгой типизацией, когда мы можем написать кусок кода, который работает за час, а все неприятные ошибки обнаружить гораздо позже в процессе разработки. Ведь до производства еще год, и к тому времени мы, скорее всего, будем работать в какой-нибудь другой компании.

Дело не в том, что динамические языки плохие, совсем нет (например, Python — отличный язык для науки о данных), а в том, что некоторые из них плохо используются, а JavaScript худший из всех.

Когда вы реализуете веб-приложение с JS на интерфейсе, имеет смысл использовать Node.Js в качестве сервера. Это просто правильный поступок. В основном потому, что именно для этого были разработаны JS и Node.J, то есть для быстрой разработки красивых веб-приложений и веб-сайтов. И мальчик они доставили. Если бы только он остановился там.

Язык программирования похож на электроинструмент. Инструмент должен идеально подходить к выполняемой задаче, иначе вы можете пораниться. Продолжая притчу, вам нужно всегда (!) использовать наиболее подходящий для задачи язык. Серебряная маркировка одного языка, как если бы это был святой Грааль, в лучшем случае неверна, просто глупа.

Тем не менее, JS был и становится Святым Граалем, так что даже такие хорошие учебные заведения, как Стэнфорд, сделали его первым языком выбора для студентов CS. Если бы не такой дрянной язык.

«Я выбрал JavaScript и Node.Js в качестве своего серверного стека, потому что стало проще нанимать программистов, знакомых с этим языком, и я могу использовать их как для фронтенда, так и для бэкенда» (это вы услышите от многих запуск вице-президента по исследованиям и разработкам)

Чтобы понять, где и как возник JS и почему это такая плохая метафора языка общего назначения (для не-веб-приложений), нужно вернуться на десять дней назад в 1995 год.

В 1995 году Netscape Communications наняла Брендана Эйха с целью внедрить язык программирования Scheme в свой Netscape Navigator. Прежде чем он смог приступить к работе, Netscape Communications сотрудничала с Sun Microsystems, чтобы включить в Netscape Navigator более статичный язык программирования Sun Java, чтобы конкурировать с Microsoft за принятие пользователями веб-технологий и платформ.

Затем Netscape Communications решили, что язык сценариев, который они хотели создать, будет дополнять Java и должен иметь аналогичный синтаксис, исключающий использование других языков, таких как Perl, Python, TCL или Scheme. Чтобы защитить идею JavaScript от конкурирующих предложений, компании нужен был прототип. Эйх написал его за 10 дней в мае 1995 года.

Они никогда не предполагали, что он будет широко использоваться вне браузера. Но, как говорится, вскоре это вышло из-под их контроля.

Язык, разработанный для одного случая использования, то есть для обработки асинхронной природы сети, стал де-факто стандартом программирования общего назначения. Но не все программы общего назначения являются асинхронными, и не все системы требуют этого. Не в том, что касается JS.

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

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

Программисты JS скажут вам, что язык прошел долгий путь. Они правы, он прошел долгий путь, добавив функции (например, Promises, Async/Await и т. д.), которые пытаются преодолеть его основные недостатки. Функции никогда не понадобятся, если они сохранят свою первоначальную цель, а линтер не станет последней линией защиты от плохого кодирования.

Новейшие функции JavaScript, такие как обещания, async/await и его линтер, очень похожи на автомобиль, который должен был ездить по дорогам с твердым покрытием, едущий по бездорожью, оснащенный внешней громоздкой трансмиссией 4X4, прикрепленной несколькими лейкопластырями, и намеком на суперклей в сопровождении на эвакуаторе, чтобы вытащить его из сложной ситуации. Едет, но некрасиво.

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

Мягкое убийство Гидры

Религия никогда не исчезнет, ​​пока не появится новая, более привлекательная. То же самое и с тенденциями программирования. Если мы хотим убить JS, нам нужно предоставить заманчивую модель, которая понравится массам, а затем постепенно менять ее, удаляя все плохие функции, переходя на более новую, лучшую модель.

В какой-то степени Microsoft попыталась сделать это с помощью TypeScript.

TypeScript был впервые обнародован в октябре 2012 года после двух лет внутренней разработки в Microsoft. TypeScript возник из-за недостатков JavaScript для разработки крупномасштабных приложений как в Microsoft, так и среди их внешних клиентов. Проблемы, связанные со сложным кодом JavaScript, привели к спросу на специальные инструменты для упрощения разработки компонентов на языке.

Разработчики TypeScript искали решение, которое не нарушало бы совместимость со стандартом и его кроссплатформенную поддержку. Зная, что текущее стандартное предложение ECMAScript обещало будущую поддержку программирования на основе классов, TypeScript основывался на этом предложении.

Это привело к компилятору JavaScript с набором расширений синтаксического языка, расширенному набору, основанному на предложении, который преобразует расширения в обычный JavaScript. С точки зрения непрофессионала, TypeScript — это JavaScript с типизацией во время компиляции.

Сначала это было воспринято холодно, позже было воспринято нерешительно, но оно набирает обороты. Программисты JS, для которых акт объявления типа был чем-то, что Мафусаил делал в Java, когда они были вскормлены, постепенно смирились с тем фактом, что на самом деле может быть эффективнее потратить несколько секунд на объявление типа. , вместо того, чтобы искать ошибки в своей производственной среде воскресным утром, когда она дала сбой и сгорела из-за упущенной строковой переменной даты, интерпретируемой как целое число.

Каким бы хорошим ни был TypeScript, он по-прежнему поддерживает исходную метафору async/await на основе промисов, жестко встроенную в его базовый JS.

Мы должны сделать лучше, чем это.

Помимо JavaScript

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

Ответ на этот основной вопрос даст нам соответствующие компромиссы, на которые нам придется пойти во время его разработки. Поскольку JS стал стандартом для многих высококлассных серверных бэкэндов (иногда его называют системным языком), было бы разумно сосредоточить нашу замену JS на той же проблемной области.

Итак, мы стремимся разработать язык программирования на стороне сервера, метафоры которого достаточно легки, чтобы не обременять программиста-миллениала слишком большими синтаксическими издержками, который допускает (но не навязывает) шаблоны ООП, обеспечивает проверки во время компиляции, отсекая потенциальные ошибки. в зародыше, эффективно (и безопасно) многозадачность и распределяет выполнение, обеспечивая мягкую миграцию с JS.

Довольно высокий заказ.

Одним из вариантов может быть использование существующего языка, такого как Python или Go, или даже Rust. Однако они будут автоматически отвергнуты культом JS точно так же, как каждая новая религия отвергнута существующими.

Другой вариант, по пути, по которому в то время пошли TypeScript и C++, — создать расширенный язык, который сохраняет внешний вид предыдущего, добавляя при этом необходимые метафоры.

В случае TypeScript код TS транспилируется в JS, в то время как более старый C++ использовал аналогичный, хотя и не такой же, подход, сохраняя базовый компоновщик C и большую часть синтаксиса C (программисты-ветераны могут помнить компилятор Cfront, который преобразовывал C++ в C так же, как TS делает для JS). Однако это скорее исправление, чем полноценное решение, так как оно сохраняет языковые метафоры, от которых мы хотели бы избавиться, чтобы достичь цели расширения.

От этого никуда не деться. Нам нужен новый язык. Тот, который удовлетворяет вышеуказанным требованиям (для эффективного, крупномасштабного и безопасного программирования на стороне сервера), обеспечивая при этом плавный и привлекательный путь перехода с JS. Скорее всего, это будет комбинация Python и Go с оттенком Rust и удобная краткая синтаксическая нотация (мы не будем подробно описывать такой язык в этой статье — скорее, в следующем). описание этого нового предложенного языка).

Что касается путей миграции, у нас есть ровно два варианта.

Либо создайте компилятор, который берет существующий JS-код, легко конвертируя его в новый язык (ничего короче этого не будет достаточно, поскольку никто в здравом уме не захочет выбрасывать огромную существующую кодовую базу JS, и это правильно). Или предоставьте среду выполнения, которая запускает код JS вместе с модулями на новом языке с соответствующими связующими API, чтобы обеспечить взаимодействие между языками, чтобы новый код работал без проблем с модулями JS, заменяя его с течением времени (можно даже представить себе простое в использовании). Компилятор времени, который компилирует модули JS, динамически загружаемые в такую ​​среду выполнения).

После того, как мы реализовали вышеизложенное, не было бы причин продолжать использовать JS, и стадо программистов, использующих его сейчас, будет медленно адаптироваться к новому языку, сохраняя при этом свои инвестиции в старые кодовые базы JS (во многом подобно процессу медленной миграции нового модули в TypeScript, сохраняя при этом старые кодовые базы JavaScript). Потому что это просто имело бы смысл.

И Гидра может покоиться с миром.