Три Больших Лжи о JavaScript

Привет, Хабр! Представляю вашему вниманию мой перевод статьи "The Three Big Lies About JavaScript" автора Richard Kenneth. Данная статья была написана в мае 2016 года, однако ее актуальность, на мой взгляд, не исчезла. Я начинающий программист, поэтому возможны ошибки в плане «понимания». Итак…

Три Больших Лжи о JavaScript


Есть два варианта лжи: ложь, которую мы говорим другим, и ложь, которую мы говорим себе, что бы оправдать ее
Есть три больших лжи, которые JavaScript поклонники говорят мне снова и снова.

Ложь#1


JavaScript – это самый неправильно понимаемый язык программирования в мире.
Люди не знают, как правильно им пользоваться, и поэтому они постоянно попадают во всевозможные неприятности. И это ложь, потому что в JavaScript нет ничего непонятного.

Это заурядный императивный / процедурный язык программирования с небольшим количеством функциональных возможностей программирования (ФП) и спорной “объектно-ориентированной” функцией, называемой прототипами объектов. И что же здесь особенного?

В основном, все проблемы, возникающие при использовании JavaScript, являются виной только людей, которые его используют: они невежественны, они ленивы, они привыкли к тому, как программирование выполняется на Java или Python.Чего же они не знают? Функционального программирования?

Почему же тогда люди не ошибаются при использовании других языков ФП, таких как C#, Clojure, Dart, Elm, Erlang, F#, Julia, Haskell, Scala и Scheme? Функциональное программирование является достаточно хорошо понятной парадигмой в IT-индустрии. Так что же тогда делает JavaScript, таким особенно проблематичным в этом отношении?

Может быть, люди не достаточно осведомлены о прототипах объектов. В таком случае, прочитайте «What JavaScript’s Object Prototypes Aren’t». Прототипы, конечно же, не годятся для разработки программного обеспечения. Они не являются особенно высоким уровнем абстракции программирования. Прототипы — это в основном прославленные хэш-таблицы, довольно таки низкий уровень и это то, что я называю «кирпичиками» для реального объектно-ориентированного программирования (class-based OOP). Люди могут не понимать, как использовать прототипы объектов, но зачем вам учиться “укладывать кирпичи”? Это не заслуживает Ваших усилий.

Да, я понимаю. Прототипы очень гибкие. Они не обладают всеми “ритуалами”, на которых стоит классическое ОПП. В этом смысле они забавны в использовании. Но они не масштабируются хорошо для больших приложений, и поэтому люди возвращаются к классам. Если бы прототипы были таким полезным приемом, вы бы видели его адаптацию везде, потому что прототипы могут быть смоделированы на языках, основанных на классах, так же, как классы могут быть смоделированы на языках, основанных на прототипах. И это то, что JavaScript программисты не могут уяснить.

Ложь#2


Асинхронное программирование — ключевая сила JavaScript. Что же, давайте сначала поймем, почему асинхронное программирование вообще существует в JavaScript.

Для разработки графического интерфейса пользователя (GUI) цикл событий является — de rigueur (обычной вещью), будь то в Windows, или X Window, или OS X's Cocoa, или веб-браузере. Все они обрабатывают события пользовательского ввода асинхронно. Означает ли это, что асинхронное программирование также является силой C++ или Objective-C? Циклы событий (с асинхронными библиотеками) также использовались в Python и Perl и Tcl. Тогда, я полагаю они все обладают силой асинхронного программирования? (Я смеюсь, когда люди используют несуществующее слово “asynchronicity” (асинхронный — это прилагательное, описывающее объекты или события, которые не координируются во времени).

JavaScript, так же использует цикл событий и асинхронную обработку для поддержки пользовательского интерфейса веб-браузера. Разве это делает его великим языком?

И теперь эта модель вычислений, сделала Node.js довольно популярным на стороне сервера, где он используется для разработки, не связанного с GUI, т.е. для высокопроизводительного параллелизма. Node очевидно, полезен для многих приложений, но вряд ли он захватит мир параллелизма. Недавние события, показывают ограничения Node.js. И да, это должно убедить всех использовать только JavaScript.
Цикл событий был описан как «параллелизм бедняка.
Сторонники Node любят снова и снова показывать одни и те же примеры крупных предприятий (PayPal, Netflix, Walmart, Uber, и т.д.). Что же для каждого Node.js примера можно сопоставить в ответ?  — сотни примеров Java? Java зарекомендовала себя бесчисленное количество раз для разработки в enterprise. Вот почему это является отраслевым стандартом. Node.js же, еще не доказал себя. Мы не знаем на самом деле, сколько корпораций пытались использовать Node.js и в итоге отказались от него. Мы понятия не имеем, каков реальный показатель успеха Node.js проектов. Для enterprise, выбор в сторону Node.js, все еще является риском.
Я уверенно предсказываю, что Go вытеснит Node в будущем, как только он нарастит свою экосистему фреймворков и пакетов. Его траектория неоспорима.
Такие языки, как Go и Erlang/Elixir, могут легко превзойти Node в большинстве сценариев параллелизма. Даже модель цикла событий / асинхронности не является устойчивой в долгосрочной перспективе. Мы должны быть заинтересованы в использовании реальных языков параллельного программирования, если нашей целью является максимальная производительность. Зачем идти на компромисс с JavaScript.

Ложь#3


JavaScript является самым популярным языком программирования в мире.

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

JavaScript является единственным нативным языком для веб-браузера, поэтому это самый прямой путь для написания браузерного приложения. Большинство разработчиков, однако, презирают этот язык и, если бы у них действительно был бы лучший выбор, они бы его сделали. Вы сами можете убедиться в этом, если поищете в интернете (форумы, социальные сети, веб-сайты и т.д.) мнения людей касательно JavaScript. Существует множество длинных списков WATs и WTFs о JavaScript, которые вы не найдете для любого другого языка, за исключением PHP. Что мы знаем наверняка, так это то, что очень популярен web, а не JavaScript.

Большинство основных языковых рейтинговых индексов не указывают на то, что JavaScript — самый популярный язык программирования. Даже ни вторая, ни третья, ни четвертая позиция. Согласно IEEE Spectrum (Американский журнал) – это #8 место, PYPL #5, TIOBE #7, CodeEval #6. Redmonk (аналитическая компания) использует статистику Github, которая показывает сильно завышенное число для JavaScript, именно потому, что веб-приложения, написанные на любом языке, должны иметь хотя бы немного JavaScript`а для работы в браузере; тут без вариантов. Поэтому Redmonk не в состоянии дать объективный рейтинг аномалии JavaScript`а; иным образом, самый популярный язык – это Java.

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

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

Правда


Позвольте мне быть предельно ясным: JavaScript не является хорошим языком программирования для разработки программного обеспечения. JavaScript был разработан быть легким, свежим скриптовым языком для веб-браузера. Как таковой, он был сделан, чтобы быть гибким и чрезвычайно прощающим, со слабой типизацией. Он даже не имеет правильного целочисленного типа или правильного типа массива. Что это за язык!?

Слабая типизация, это Ахиллесова пята языка программирования, с помощью которого разрабатывается программное обеспечение. Хоть это и делает написание быстрых простых сценариев для веб-браузера очень легким, это же и работает против вас, когда вы пишете большие приложения, которые требуют безопасности и надежности. Вот почему большинство основных языков обычно строго типизированы (не путать со статически типизированными). И это очень, очень важно!

Слабая типизация и вытекающее из нее произвольное принуждение демонстрируют полное отсутствие языковой дисциплины. Это объясняет большую часть списка WATs и WTFs

порождённая JavaScript`ом. (далее, автор приводит ссылки на онлайн ресурсы, где приводится список “бородавок” JavaScripta).
Поделиться публикацией

Комментарии 95

    +13
    Думаю не стоит все таки быть категоричным. Если руки растут с нужного места, то и на Javascript вы сделаете хороший продукт. В жизни видел много как отличных так и ужасных реализаций на Javascript/Java/Python/PHP.

    По поводу типизации, в мире JS есть typescript. Конечно это не язык, а всего лишь надстройка. Но и она помогает, даже очень сильно помогает, с типизацией.

    Думаю, самый лучший итог статьи, на мой взгляд — развивайтесь. Будьте лучшим в том языке, который вам нравится. И вы сможете реализовать задачи любой сложности.
      0
      Если руки растут с нужного места, то и на Javascript вы сделаете хороший продукт.

      Полувековая мировая практика программирования доказывает, что даже пряморукие программисты нередко косячат хотя бы из-за банальной невнимательности. Сишный подход «программист умнее компилятора» оказался неработоспособным. Хороший современный язык программирования должен минимизировать вероятность появления ошибок независимо от пряморукости программистов. Хорошим примером является Rust, где ошибочный код в большинстве случаев просто не скомпилируется (ещё остаётся возможность налажать в каких-нибудь unsafe-блоках, но на то они и unsafe). Антипримером служит Си, где даже опытные разработчики умудряются что-нибудь упустить, а ошибки потом живут годами незамеченными (надеюсь, рассказывать про Heartbleed и тыкать в блог PVS-Studio не надо?). Typescript это хорошо, но чистый Javascript со своими странностями (странности можно вызубрить, но они останутся странностями) всё же очень способствует появлению ошибок независимо от положения рук, невнимательность и «нужно сделать вчера» никто не отменял.

        0
        Сравнивать компилируемые и интерпретируемые языки неправильно.
        А по поводу того, как всемогущий компилятор защищает от ошибок, неплохо написано тут:
        medium.com/javascript-scene/the-shocking-secret-about-static-types-514d39bf30a3
          –1
          Сравнивать компилируемые и интерпретируемые языки неправильно.

          Это лишь сильнее намекает на то, что нужность интерпретируемых языков как минимум сомнительна. Сами поглядите: над интерпретируемым (JIT-компиляцию не считаем) джаваскриптом народу пришлось накрутить компилируемый Typescript. В моём любимом утином питончике тоже уже пытаются сбоку прикрутить статическую типизацию в виде MyPy и Pyright. Это ж всё неспроста.


          как всемогущий компилятор защищает от ошибок

          Никакой язык программирования и никакой компилятор не сможет защитить от логических ошибок. Уж это должен каждый понимать и без всяких статей. Никакой язык программирования, даже Rust, не освобождает от необходимости тестирования.

            0
            Это лишь сильнее намекает на то, что нужность интерпретируемых языков как минимум сомнительна.

            Кому намекает? Мне не намекает.

            Сами поглядите: над интерпретируемым (JIT-компиляцию не считаем) джаваскриптом народу пришлось накрутить компилируемый Typescript.

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

            Никакой язык программирования и никакой компилятор не сможет защитить от логических ошибок.

            В статье по ссылке есть статистика плотности ошибок. И везапно js, который со всех сторон плохой, нелогичный и т.д. и на ненужность которого вам что-то намекает, там далеко не в «лидерах». Почему? Может потому, что у многих людей в голове укоренилась ложная уверенность во всесильность компилятора? Если код хорошо покрыт тестами, абсолютно все равно, какая там типизация.
              –1
              Мне не намекает.

              Сочувствую.


              огромному количеству людей он, просто напросто, не нужен.

              Тем хуже для качества ПО. Мне тут тоже остаётся только посочувствовать этим людям.


              замедляет скорость разработки

              Да, современные программисты жертвуют качеством ради скорости. И это очень-очень печалит меня. В общем-то, я уже неоднократно ныл об этом на Хабре.


              Если код хорошо покрыт тестами, абсолютно все равно, какая там типизация.

              Хорошая типизация способна сильно облегчить тесты. Зачем проверять тестами те вещи, которые по-хорошему должны вызвать просто ошибку компиляции? (Очень хорошая типизация, говорят, способна отловить даже некоторые логические ошибки, но это для гуру, лично я так ещё не научился.)


              И, кстати, здесь же наблюдается противоречие с вашим предыдущим утверждением. Написание тестов на каждый мелкий чих, очевидно, тоже требует времени и неизбежно замедляет скорость разработки. Опять же, или качество (больше типов или больше тестов), или скорость (фигак-фигак и в продакшен, TypeError'ы пофиксим потом) — третьего не дано.

                0
                > Зачем проверять тестами те вещи, которые по-хорошему должны вызвать просто ошибку компиляции?

                Можете привести наиболее показательный, с вашей точки зрения, конкретный пример?
                  –1

                  Банальнейшая передача строки в функцию, принимающую число. Или наоборот.


                  Банальнейшая попытка обращения к переменной, которая может быть null или undefined, без проверки на null или undefined.


                  Банальнейшее присваивание какого-то значения в несуществующее поле объекта из-за опечатки.


                  Неужели не очевидны даже такие простые вещи?

                    –1
                    Неудачные примеры, если не углубляться в эзотерику, в таких случаях отвалятся самые обычные тесты.
                    Кстати, в программировании конкретным примером считается код. Можете привести юнит-тест (в виде кода), который был нужен и перестал быть нужен в результате типизации?
                      0

                      Это НЕ должно проверяться тестами! Это должно проверяться компилятором задолго до запуска тестов.


                      Да даже не компилятором — IDE при наличии типов может подчеркнуть ошибку сразу после ввода. Тесты здесь — костыль, подпирающий отсутствие нормальной типизации в javascript.


                      Можете привести юнит-тест

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

                        –1
                        > Это НЕ должно проверяться тестами!

                        Так и не нужно. Обычные тесты, а не какие-нибудь «типизирующие», прекрасно отлавливают неверные значения.
                        Если функция формирует неверный объект, тест это поймает, включая опечатки, а типизация поймает только часть случаев.
                        Вы утверждали, что можно сэкономить на тестах при внедрении типизации.

                        > IDE при наличии типов может подчеркнуть ошибку сразу после ввода. Тесты здесь — костыль

                        Тесты — это тесты. Рационально ли дублировать функциональность тестов типизацией?
                        У самой типизации очень ограниченная область применения, например, в качестве костыля для какой-нибудь плохонькой IDE.

                        > обозначенные мной выше банальнейшие примеры.

                        Данные примеры не подтверждают высказанную вами точку зрения.
                          +3
                          а не какие-нибудь «типизирующие»

                          Без типов вы обязаны написать набор именно «типизирующих» тестов:


                          • передать в функцию неправильный тип (строку вместо числа и т.п.) и убедиться, что она возвращает правильную ошибку, а не мусор в результате;
                          • разновидность предыдущего: передать в функцию массив со значениями смешанных типов, в том числе недопустимых, и убедиться, что будет возвращена ошибка и что никакие побочные эффекты, которые могли успеть отработать, не угробят остальную программу;
                          • если функция принимает аргументы с взаимосвязанными, но заранее не определёнными типами (два аргумента одинакового типа для последующего их сравнения внутри функции, например), то убедиться, что функция самостоятельно проверяет типы и не сравнивает объекты разных типов, возвращая при этом мусор;
                          • передать в функцию null и опять же убедиться в правильности ошибки, а также убедиться, что null в обязательном аргументе не проигнорирован;
                          • передать в функцию значение, выходящее за пределы допустимого диапазона, и убедиться, что будет соответствующая ошибка, а не игнорирование или мусор;
                          • остальное сами придумаете по аналогии, если вы опытный программист.

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


                          можно сэкономить на тестах при внедрении типизации.

                          Да, вот я выше расписал, на чём можно сэкономить.


                          Рационально ли дублировать функциональность тестов типизацией?

                          Дублировать — нет. Использовать типы вместо «типизирующих» тестов — да. Чем раньше ошибка будет поймана, тем дешевле её исправление. Об этом написано в любой нормальной книге по программированию — у Стива Макконнелла тоже, например. Зачем запускать тесты и тратить на них драгоценное время, если IDE, опираясь на типы, может подчёркивать ошибки в реальном времени?


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

                          Вы просто не умеете в нормальную типизацию и решили скатиться в демагогию, и здесь мне остаётся только посочувствовать и посоветовать изучить в образовательных целях какой-нибудь язык с развитой системой типов, вроде того же Rust, Scala или Haskell (список неполный).


                          Данные примеры не подтверждают высказанную вами точку зрения.

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




                          Кстати, если «обычный» тест упал, то нужно ещё посидеть и разобраться, почему он упал. Тест может только сказать, что результат неправильный, а почему он неправильный — это надо взять в руки отладчик, прошагать, полчаса тупить и ничего не понимать и лишь после перекура умудриться заметить то место с едва заметной опечаткой в названии ключа, из-за которого ключ посчитался несуществующим и выполнилась ветка для значения null.


                          При наличии типов компилятор или IDE выкинет ошибку сразу после написания кода и ткнёт стрелочкой сразу же в ту самую опечатку. И, может, даже подскажет «Did you mean [слово-без-опечатки]?»

                            0
                            > передать в функцию неправильный тип (строку вместо числа и т.п.) и убедиться, что она возвращает правильную ошибку, а не мусор в результате;

                            Это вы уже в режим defensive programming впали. Заметная часть кода может работать и при динамической типизации из расчёта, что типы данных переданы правильные, а проверки выполнять только на границах зон ответственности. Остальное выполнят обычные тесты или статический анализ.

                            Disclaimer: я говорю про общий подход, а не про специфику Javascript. Но и вы начали говорить про «в общем». В случае JS, к динамичности типизации добавляется её слабость, или возможности типа «неверный ключ => вернулось undefined», тогда нужны проверки на границе таких сомнительных мест.

                            > Что ж, мне остаётся только посочувствовать вашему ограниченному кругозору. Наберётесь опыта в программировании, набьёте кучу шишек, замучаетесь писать «типизирующие» тесты на каждый мелкий чих — поймёте, что защитники статической типизации были правы.

                            Я имею такой опыт и несколько раз переходил от статической типизации к динамической и наоборот. И как раз по своему опыту говорю, что вы правильно определяете, но таки преувеличиваете проблему. Супердефензивные подходы — перегиб, который не окупается.

                            С другой стороны, на взгляд оценив свои последние работы на Python, пришёл к выводу, что его динамичность (не только в типизации, а и в, например, невозможности надёжно проверить называние поля объекта) приводит к замедлению работы программиста примерно в 2 раза. Это цена того, что голова, занятая подробностями типа «как нам добраться до этого свойства, какого оно типа и как нам его сюда сохранить?» (меньше зависящие от языка), перестаёт следить за деталями типа «тут написал uA вместо uaA», и выясняется это только в тестах, если выясняется (в моём случае ещё и оказалось, что эта опечатка в коде обработки очень редкого случая, обычно вызванного обгоном между параллельными участниками, и тут ещё надо суметь придумать тест, который бы эту ситуацию воспроизвёл).

                            Поэтому — польза от статической типизации, да, есть. Но не надо её радикализировать.

                            > Зачем запускать тесты и тратить на них драгоценное время, если IDE, опираясь на типы, может подчёркивать ошибки в реальном времени?

                            Тут +100. И одно из важных свойств языка — позволять подобные возможности IDE, статических анализаторов и т.п. — по максимуму. Но что Python, что Javascript здесь словно специально строятся так, чтобы позволять подменить в рантайме вообще всё.

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

                            Статическая и сильная типизации сокращают количество таких случаев, да, заметно (в разы). Но полностью это тесты не заменяет. Точно так же можно и при полной статике вместо kptfa вызвать ktpfa и тупить полчаса, не видя разницы, и при динамике можно делать названия ключей такими, чтобы в них были видны опечатки. Второе сложнее и дороже, да.
                              0
                              из расчёта, что типы данных переданы правильные

                              Ага, но это вполне проверяется статической типизацией при наличии соответствующих задаче интерфейсов/трейтов


                              Точно так же можно и при полной статике вместо kptfa вызвать ktpfa и тупить полчаса

                              Тоже ага, но в случае статики программист, доверяя компилятору и зная, что ошибка абсолютно точно где-то здесь, психанёт, сотрёт слово и напишет его заново всего за пять минут)

                                0
                                > Ага, но это вполне проверяется статической типизацией при наличии соответствующих задаче интерфейсов/трейтов

                                Так и статическим анализом — тоже. Если foo() гарантировала, что x будет целым, то при вызове bar(x) не нужна ещё одна проверка в bar.
                                Современные анализаторы на такое вполне способны, причём с выводом типов — они могут не ждать декларацию типа «x должно быть целым, или трава не расти», им достаточно увидеть, что x присвоено int(xs).
                                Возможность статически дописать то же самое — полезна, и местами необходима (при интерфейсе с чем-то внешним), но не единственна.

                                В этом смысле оба крайних подхода — полная статика и полная динамика — чрезмерны. Полная статика приводит к тяжёлым громоздким конструкциям там, где нужна динамика, и не делает всё равно многого полезного (как вывести, например, что x не может быть больше 1000). Полная динамика приводит к тому, что нет возможности даже явно подсказать, где надо, конкретный тип и потребовать его выполнения иначе, чем тупыми assert/raise.

                                > Тоже ага, но в случае статики программист, доверяя компилятору и зная, что ошибка абсолютно точно где-то здесь, психанёт, сотрёт слово и напишет его заново всего за пять минут)

                                Это уже другой вопрос — зависит от типа программиста и метода его работы.
                                Хорошо, конечно, иметь возможность писать порциями по 1 функции на 10 строк, которая заранее обложена тестами по TDD, но, например, разработку сложного алгоритма таким методом не взять.
                                  0
                                  Так и статическим анализом — тоже.

                                  Статическому анализу нужны исходники. Если bar является частью проприетарной библиотеки и этот самый bar никак не декларирует, что аргументы должны быть числами (или что аргументы должно быть возможно сложить друг с другом с получением результата в виде того же типа, не суть), то статический анализ не сможет заглянуть внутрь скомпилированного bar и окажется бессилен. Python-модули, написанные на сишечке (а их хватает), так уже не проверить, например; разработчики MyPy сидят и ручками проставляют типы для сторонних библиотек (в том числе и сишных), чтобы их статический анализ мог работать. (Как с этим дела в javascript, не в курсе)


                                  (как вывести, например, что x не может быть больше 1000)

                                  Говорят, для такого есть зависимые типы (но лично мне ещё не доводилось пользовать ни один язык с зависимыми типами, так что подробностей не знаю)

                                    0
                                    Полная статика приводит к тяжёлым громоздким конструкциям там, где нужна динамика, и не делает всё равно многого полезного (как вывести, например, что x не может быть больше 1000).

                                    Дайте более подробный пример, я с удовольствием выведу.

                                0
                                набор именно «типизирующих» тестов

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

                                При наличии нормальной системы типов всё это тестировать не нужно.
                                Если что-то недопустимое передать невозможно, потому что приводит к ошибке компиляции

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

                                лишь после перекура умудриться заметить то место с едва заметной опечаткой в названии ключа

                                Упавший тест показывает дифф объектов.

                                мне остаётся только посочувствовать вашему ограниченному кругозору

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

                                  Кто мешает эти проверки переложить на тайпчекер?


                                  Кроме того, если каждая функция будет все проверять в рантайме, то это будет не очень эффективно (авторам вещей вроде нового гмейла на это, конечно, плевать, но все же).


                                  Есть рантайм, в котором можно передать что угодно и ошибки компиляции не будет.

                                  Откуда это что угодно возьмётся, если весь код был протайпчекан до рантайма?

                                    0
                                    она должна проверять, что аргументы находятся в области определения

                                    А тестировать эту проверку как? Правильно, передавая параметры, не входящие в область определения! И это приводит ровно к тому списку «типизирующих» тестов, которые я описал выше.


                                    Есть рантайм, в котором можно передать что угодно

                                    Чтобы передать в рантайме «что угодно», это «что угодно» должно предварительно успешно скомпилироваться. Так что нет, «что угодно» в нормальных компилируемых языках вы не передадите. Разве что вы руками отключите все проверки (будете использовать unsafe-блоки, ассемблерные вставки и т.п.), но тут уж сами виноваты, отключать проверки вас никто не заставлял.


                                    Упавший тест показывает дифф объектов.

                                    Совсем не факт, что ключ с опечаткой будет находиться именно в тех объектах, для которых будет показан дифф. Дифф покажет следствие (неправильный объект), а не причину (опечатка в ключе параметра в options, например).


                                    Продолжаю сочувствовать вашему ограниченному кругозору. Почитайте хотя бы комментарии 0xd34df00d, он во всём этом явно опытный спец.

                                      0
                                      Есть рантайм, в котором можно передать что угодно

                                      Точки, где в рантайм передаётся «что угодно», что по любым техническим причинам не тайпчекнуто — это гораздо более узкое множество, чем весь код программы. Если эти точки вообще есть.
                                      –2
                                      А еще в TS есть strict null checking mode. Ведь какая самая популрная ошибка в мартышкином JS? Наверно такая:
                                      TypeError: Cannot read property «someProperty» of undefined.
                                      0
                                      Если функция формирует неверный объект, тест это поймает, включая опечатки, а типизация поймает только часть случаев.

                                      Раз вы так настаиваете на примерах, можете привести пример такого объекта, такой функции, опечаток и соответствующих ловящих это тестов?


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

                                      Типы — это возможность статически, без запуска программы убедиться, что программа не делает ерунды.


                                      Что именно является ерундой — вопрос выразительности системы типов. C++ гарантирует, что вы не происвоите случайно указатель на инт указателю на дабл. Rust гарантирует отсутствие рейсов. Хаскель гарантирует управление эффектами. Идрис гарантирует вообще почти всё что угодно, что выражается языком формальной логики.

                                        0
                                        Вы формируете выходной JSON, но ключ вместо version назвали versoin. Типам данных — пофиг. Ловится тестом — разобрать полученное и сравнить (при первом запуске — глазами).
                                        Да, это интерфейс. Но в применениях JS такой интерфейс чуть менее, чем всегда.
                                        Вы открываете файл, но вместо userdir при формировании пути выдернули systemdir. То же самое.
                                        Вы вызвали функцию построения графика, но поменяли местами x и y.
                                        В следующий раз вы сделали передачу в такую функцию массива объектов типа Point, но в части из них неправильный порядок параметров в конструкторе.
                                        Наконец, вы сделали разные типы для x и y (сюда нужна кликбейт-картинка «Люди ахнули, узнав...») и путаетесь в конверсиях в формуле x1*y2-x2*y1.
                                        И снова — без тестов не получить обещание корректности даже для самого себя.
                                          0

                                          Прекрасные примеры!


                                          Вы формируете выходной JSON, но ключ вместо version назвали versoin. Типам данных — пофиг. Ловится тестом — разобрать полученное и сравнить (при первом запуске — глазами).

                                          Я его что, руками формирую, JSON этот?


                                          Скорее я возьму какой-нибудь Aeson, который мне по типу данных сгенерирует JSON сам. И тогда если я опечатаюсь в имени поля в типе данных, то никакие тесты мне это не поймают.


                                          Кстати, если у меня есть какое-то подобие схемы, то писать тесты на соответствие этой схеме — ну так себе. Кто гарантирует, что в сериализаторе нет какого-нибудь if, благодаря которому для одних данных всё хорошо, а для других — нет?


                                          Вы открываете файл, но вместо userdir при формировании пути выдернули systemdir. То же самое.

                                          В языке с выразительной системой типов я описываю необходимые мне операции с файловыми путями, наворачиваю сверху operational monad и в ровно одном месте убеждаюсь, что представление Systemdir отображается в правильную команду, а проверка построения правильного представления тоже аналогично предыдущему выполняется на уровне типов.


                                          Вы вызвали функцию построения графика, но поменяли местами x и y.
                                          В следующий раз вы сделали передачу в такую функцию массива объектов типа Point, но в части из них неправильный порядок параметров в конструкторе.

                                          Ну это вообще канонический пример. x и y просто делаются разных типов, и всё, да, как вы дальше пишете.


                                          Наконец, вы сделали разные типы для x и y (сюда нужна кликбейт-картинка «Люди ахнули, узнав...») и путаетесь в конверсиях в формуле x1y2-x2y1.

                                          А зачем мне там путаться в конверсиях? Умножение компоненты одного вектора на ту же компоненту другого вектора имеет отличный смысл от умножения в этой операции, поэтому это даже хорошо, что компилятор не даст мне делать лишние конверсии.


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

                                            0
                                            > Скорее я возьму какой-нибудь Aeson, который мне по типу данных сгенерирует JSON сам. И тогда если я опечатаюсь в имени поля в типе данных, то никакие тесты мне это не поймают.

                                            А должны ловить. Именно поэтому или этот Aeson (или что там вместо него будет) должен использоваться в основном коде, а не в тестах — или таки да, вручную писать.

                                            >
                                            Кстати, если у меня есть какое-то подобие схемы, то писать тесты на соответствие этой схеме — ну так себе. Кто гарантирует, что в сериализаторе нет какого-нибудь if, благодаря которому для одних данных всё хорошо, а для других — нет?

                                            Это — только визуальной верификацией (AKA вычиткой) кода.

                                            Если вычитки нет, то начнёт появляться код, который удовлетворяет только избранные тесты прямым сравнением аргументов с образцами, и ничего не делает больше.

                                            > В языке с выразительной системой типов я описываю необходимые мне операции с файловыми путями, наворачиваю сверху operational monad и в ровно одном месте убеждаюсь, что представление Systemdir отображается в правильную команду,

                                            И всё равно вам надо проверить, что ту же монаду вы написали правильно.
                                            А раз это монада — это что-то сложное… на месте внешней приёмки я бы вам не поверил несмотря на все монады. Тест должен проверить ровно то, что файл возник где положено. Он может также проверить аргументы open(), но даже это уже не так важно.

                                            > Ну это вообще канонический пример. x и y просто делаются разных типов, и всё, да, как вы дальше пишете.

                                            Вот именно, что раздельные типы для x и y — это классический, кондовый антипаттерн.

                                            Даже какое-нибудь PointBuilder.setX(x1).setY(y1).build() по сравнению с этим будет лучше.

                                            > Умножение компоненты одного вектора на ту же компоненту другого вектора имеет отличный смысл от умножения в этой операции, поэтому это даже хорошо, что компилятор не даст мне делать лишние конверсии.

                                            Я не смог распарсить, кто от чего отличен.

                                            > Ну и в типах я могу выразить, что для моих точек выполняются законы линейной алгебры, например. Ну там, дистрибутивность, ассоциативность, вот эта вся ерунда. Как вы это тестами сделаете?

                                            В тестах я могу сделать главное: проверить, что в вашей реализации на типах не будет заметных принципиальных ошибок.
                                            Только тогда появится смысл смотреть внутрь (и уже по коду определять, какие там ещё могут быть ошибки и как формулировать тесты для их ловли).
                                              0
                                              А должны ловить. Именно поэтому или этот Aeson (или что там вместо него будет) должен использоваться в основном коде, а не в тестах — или таки да, вручную писать.

                                              Так что в итоге будет проверять тест, если Aeson с дженериками используется в основном коде для сериализации и десериализации?


                                              Это — только визуальной верификацией (AKA вычиткой) кода.

                                              Нет, не только. При достаточно мощной системе типов вам никто не мешает написать тест функцию с типом вроде


                                              alwaysHasVersion : (obj : MyType) -> (HasField "version" (toJson obj))

                                              которую даже запускать не надо, достаточно, что её тело написано и тайпчекается.


                                              И, кстати, пристальный взгляд заметит здесь квантор всеобщности по термам типа MyType.


                                              И всё равно вам надо проверить, что ту же монаду вы написали правильно.

                                              Ну вот это и делается либо той же визуальной вычиткой, либо формулированием и доказыванием (в типах, как с alwaysHasVersion выше) каких-либо специфичных для корректной реализации свойств (которые уже сложно обсуждать без отрыва от контекста).


                                              А раз это монада — это что-то сложное… на месте внешней приёмки я бы вам не поверил несмотря на все монады.

                                              Яжпрограммист, а не психолог. Социальные проблемы мне не столь интересны.


                                              Вот именно, что раздельные типы для x и y — это классический, кондовый антипаттерн.

                                              В каком языке и почему?


                                              Я не смог распарсить, кто от чего отличен.

                                              Это ж кусок векторного произведения был? Если да, то тогда забейте — координаты в нём всё равно соответствуют объектам в соответствующем поле, поверх которого построено векторное пространство, поэтому это неважно.


                                              Но если таки да, то я просто беру и проверяю (в типах, ага), что моё векторное произведение — действительно векторное произведение. Что оно удовлетворяет всем аксиомам векторного произведения, и что для него выполняется всякая там антикоммутативность, дистрибутивность слева-справа, ну и дальше зависит от вашей лени.


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

                                              Это, ИМХО, неправильный взгляд на тесты. Тесты в данном случае тестируют не корректность реализации спецификации, а корректность самой спецификации применительно к вашей задаче.


                                              Если у меня нет задачи, а есть только спека (например, я у мамы математик и играюсь с представлением целых чисел поверх натуральных через группу Гротендика), то у меня не будет никаких тестов. Будут только сформулированные в типах теоремы.


                                              Если у меня нет спеки, а есть только задача, то в типах у меня будет моё понимание спеки, а в тестах — ну, зависит. Например, у меня был проект, когда я реверсил некоторую систему, для которой у меня была только пользовательская документация с примерами использования. И тесты у меня были, да: они прогоняли эти примеры. Но у меня именно что были только эти тесты, детали реализации я не тестировал (зачем, у меня типы есть).

                                    0

                                    Функция слияния двух сортированных списков как кусок merge sort'а устроит?


                                    Или, ну, например, вы хотите реализовать деление (бредовый пример, возможно, но, с другой стороны, на самом деле не хуже обсуждений страничек с чекбоксами). Вы всерьёз будете тестами убеждаться, что оно


                                    1. Всегда завершается, и
                                    2. Всегда выдаёт корректный результат?
                                      0
                                      Функция слияния двух сортированных списков как кусок merge sort'а устроит?
                                      Интересный пример. Системой типов можно гарантировать корректность кода слияния?

                                      реализовать деление
                                      Всегда завершается, и
                                      Всегда выдаёт корректный результат?
                                      Ок, допустим, есть BigInt, но нет BigFloat. Делаем деление произвольной точности. Но завершение и корректность нельзя гарантировать во всех случаях, эквивалентно проблеме остановки.
                                        +1
                                        Интересный пример. Системой типов можно гарантировать корректность кода слияния?

                                        Достаточно мощной — да. Но не в C++ и не в TS.


                                        Ок, допустим, есть BigInt, но нет BigFloat. Делаем деление произвольной точности. Но завершение и корректность нельзя гарантировать во всех случаях, эквивалентно проблеме остановки.

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


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


                                        А что до деления, так там вообще всё просто для прямого алгоритма — на каждом шаге мы рассматриваем строго меньшее делимое, а отношение «меньше» на множестве натуральных чисел фундировано, то есть, алгоритм гарантированно завершается. Собственно, доказательство тотальности часто ограничивается нахождением изоморфизма в какое-то фундированное множество.

                                  0
                                  Можете привести наиболее показательный, с вашей точки зрения, конкретный пример?

                                  int multiply(int a, int b) {
                                    return a * b;
                                  }
                                  При передаче строки в качестве одного из аргументов Java выдаст ошибку компиляции — нет необходимости проверять такие данные.

                                  function multiply(a, b) {
                                    return a * b; 
                                  }
                                  В той же ситуации JavaScript вернёт NaN. Нужно либо обрабатывать эту ситуацию внутри функции multiply, либо в функции, используещей multiply, и писать юнит-тесты на этот случай.
                                    0
                                    Ошибка думать, что типизация ловит такие ошибки в JS.
                                    Если вы определите
                                    function multiply(a: number, b: number) {
                                      return a * b; 
                                    }
                                    
                                    и в функцию будет передано не число (значение не приводящееся к числу), то всё равно будет NaN. Это всё равно что заявить: «будут только числа, мамой клянусь!» Типизация никак не гарантирует, что вы получите извне те данные, которые описали.
                                      –1
                                      Зачем притягивать слона за уши?

                                      Если данные действительно получены извне (по сети из другой системы, через ipc канал от другого чужого процесса и тд), то валидация таких сырых данных все равно будет проводится в рантайме при парсинге кастомным образом. Будь то TS или например Java которая с рантаймом.

                                      TS не существует в рантайме, думаю это понятно? Но он отвечает за проверку типов в «лоальном» коде в девелопмент тайм и также за взвимодействие с библиотечным кодом который описан декларациями.
                                        0
                                        Это всё равно что заявить: «будут только числа, мамой клянусь!»
                                        И тут подходит компилятор и вкрадчиво так «а если найду?».

                                        Типизация никак не гарантирует, что вы получите извне те данные, которые описали.
                                        Вот типизация-то как раз гарантирует (насколько достоверно — это уже зависит от реализации), в отличие от тестов.
                                        Тест не даёт упасть функции с неправильными параметрами.
                                        Типизация не даёт написать код с неправильными параметрами.

                                        PS: конечно если под «извне» вы имеете в виду «извне функции», а не «извне программы», валидация входных данных — это отдельный вопрос, никак не пересекающийся с типизацией.
                                          0
                                          Вот типизация-то как раз гарантирует (насколько достоверно — это уже зависит от реализации), в отличие от тестов.
                                          Статическая типизация не умеет запускать код и поэтому как раз не может гарантировать. Она может сказать что в простейших случаях типы соответствуют друг другу в узком мирке типизации. Проблемы начинаются как только код становится сложнее, структуры разнообразнее, появляются any, и всё едет по кривой дорожке.

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

                                          А вот если написать тесты, которые проверяют, что поведение соответствует ожидаемому, то это с лихвой перекроет все кейсы типизации. Более того, типизация по своей сути похожа на тупые тесты, те которые проверяют детали реализации, а не ожидаемое поведение.
                                            +1
                                            Статическая типизация не умеет запускать код и поэтому как раз не может гарантировать.

                                            Эхехе, это смотря какая именно система типов.


                                            Буквально недавно сталкивался со случаем, когда типизация не предотвратила банального сложения строки с числом, где подразумевалось сложение чисел.

                                            Это в каком языке?

                                  +1
                                  Если код хорошо покрыт тестами, абсолютно все равно, какая там типизация.

                                  На самом деле нет: тестами вы не проверите что-то с квантором всеобщности, тестами сложно покрываются вещи вроде «такой-то инвариант выполняется в течение всей времени жизни программы», тестами трудно проверить «у меня тут нет рейскондишнов», тестами трудно гарантировать детерминированность параллелизованного алгоритма, тестами трудно гарантировать корректность локфри-алгоритма, тестами сложно покрываются вещи вроде «подключённая библиотека никогда не начнёт майнить биткоины или качать руткиты».


                                  Но даже если бы это было так, зачем писать тесты руками, когда можно сформулировать искомую предметную область в минимально необходимом виде (в виде типов) и поручить тайпчекеру все проверки?

                                  0
                                  Никакой язык программирования и никакой компилятор не сможет защитить от логических ошибок.

                                  На самом деле есть такие, которые смогут.

                                    0

                                    Ну например: при изменении объекта с поставленной в форме галочкой «малое изменение» нужно проставить отметку «малого» в логе изменений, а дату изменения у изменённого объекта не обновлять. Но разработчик забыл об этом и по привычке обновил эту дату изменения (с логом при этом всё сделано правильно). Если есть языки, которые смогут отловить такую вещь при компиляции, я незамедлительно побегу их учить и образовываться

                                      0

                                      Я чё-т думаю, что для GUI это оверкилл, но всё же, для какого-то представления GUI и связи с соответствующей предметной областью:


                                      smallChangeReflectedInField : (gui : Gui) ->
                                          (obj : Object) ->
                                          (GuiRepresentsObj gui obj) ->
                                          (prf : checkboxState (smallChangeCheckbox gui) = Checked) ->
                                          smallChange obj = True

                                      для первого условия и


                                      smallChangeDoesntChangeDate : (guiBefore, guiAfter : Gui) ->
                                          (objBefore, objAfter : Object) ->
                                          (GuiRepresentsObj guiBefore objBefore) ->
                                          (GuiRepresentsObj guiAfter objAfter) ->
                                          (prf : TheOnlyDifferenceIsInCheckbox guiBefore guiAfter) ->
                                          date objBefore = date objAfter

                                      Пишете реализации этих термов, и компилятор убеждается, что эти утверждения верны.

                                  0
                                  График в статье: одна огромная ошибка выжившего.
                                  C++, Java и Python — самые популярные ЯП, на них пишут очень много людей, которые, мягко говоря, не очень хорошо умеют программировать.
                                  С++ комментировать не буду. Самый сложный ЯП из всех существующих, с самым большим грузом legacy. Неудивительно. Java немного исправляет ситуацию (сборка мусора). Python ещё немного лучше с точки зрения дизайна.
                                  Вас не смущает, что лучше всех себя показывает интерпретируемый язык с динамической типизацией (Clojure)? Возможно, это из-за его иммутабельности. А возможно это потому, что это не слишком популярный язык, до которого нужно дорасти. Он не для студентов, которых кое-как «научили Яве». Он для тех, кто ищет идеала и занимается самообразованием. Он для старых, уставших программистов (шутка Рича Хики).
                                    0
                                    C++, Java и Python — самые популярные ЯП, на них пишут очень много людей, которые, мягко говоря, не очень хорошо умеют программировать.

                                    Это шутка такая? Ничего, что JS самый популярный язык?
                                    githut.info
                                    github.blog/2018-11-15-state-of-the-octoverse-top-programming-languages
                                    И как раз JS упрекают в том, что на нем пытаются писать все кому не лень из-за очень низкого порога вхождения?

                                    С++ комментировать не буду. Самый сложный ЯП из всех существующих

                                    Это с чего вы такое взяли?
                                      +1
                                      Тут идёт оценка по количеству репозиториев и коммитов, а количество строк кода, похоже, не оценивается.
                                        +1
                                        Это с чего вы такое взяли?

                                        Потому что его невозможно изучить целиком.


                                        Какой неэзотерический язык сложнее, в конце концов?

                                          +1

                                          Следующая редакция C++

                                      +1
                                      Проскроллил статью, увидел большое жирное «Type correctness does not guarantee program correctness», закрыл статью.

                                      Если брать типы как в C++ или Java (или да, как в Rust) — конечно, не гарантирует (тесты, кстати, тоже не гарантируют). На другой стороне спектра всякие агды и идрисы, они именно что гарантируют корректность (с точностью до корректности самой спецификации, но это вопрос другого совсем уровня), но на них писать долго, и выучить их, наверное, чуть сложнее, чем JS. Всё, что посередине — вопрос баланса.
                                    –4
                                    Если руки растут с нужного места, то и на Javascript вы сделаете хороший продукт
                                    Это правда, но из этого всё равно не следует, что Javascript — хороший язык.
                                      –1
                                      Хорошо, я исправлюсь. Если руки растут из нужного места, то можно и в Блокноте сделать хороший продукт. Из этого определённо следует, что Блокнот — хорошая IDE.
                                    +25

                                    Автор похож на очередного хейтера javascript, которому бесполезно что-то доказывать.

                                      +1

                                      Вообще непонятна его позиция — то ли это реклама к курсам, на которых он наконец-то научит нас, неразумных, Как Правильно, то ли это просто его личная боль — и ничего больше.

                                        0
                                        Вполне возможно, ведь аргументы звучат одни и те же, но при этом они понятны.
                                        Я, к примеру, C# программист, делаю игры на Unity, у меня есть небольшой любительский опыт js (ну, для разнообразия + в браузере, mefist0fel.github.io).
                                        И, ну это боль. Я действительно не понимаю, как мне жить с объектами-словарями. Я регулярно ошибаюсь с сигнатурами функций (мне не могут подсказать, с каким объектом она работает), ловлю NaN и пустые ссылки. Я делаю это один и мне не удобно. А если это делает несколько человек? Я не могу защитить объект, что-бы его нельзя было использовать неправильно, не могу изолировать одну часть от другой, мало инструментов, много вариантов хаков, много «гибкости».
                                        На предыдущем проекте мы писали сервер на python, и в целом было неплохо, но с ним были похожие проблемы и совершенно дурацкие ошибки в рантайме.
                                        И Я просто не понимаю — все вокруг знают серебряную пулю?
                                        Да, в небольшом скрипте все кратко и понятно, но в большом проекте, с разными объектами и библиотеками типизация — важнейшая информация. Невозможность ее задать и проверить — источник ошибок, неопределенное поведение при преобразованиях — источник ошибок.
                                        Я просто не понимаю, о какой лаконичности идет речь, если ради экономии каких то вещей мы теряем важную информацию о структуре и логике программы, мы же не на скорость набираем код.

                                        Вот и получается:
                                        — Здравствуйте, меня зовут Кирилл, и Я — хейтер js.
                                        — Здравствуй, Кирилл!
                                        — Я не посоветую его друзьям, рекомендую опасаться этого языка.
                                        * Хилые аплодисменты

                                        Конечно, небольшие парсеры для файлов действительно удобно писать на пайтоне. Но с ростом проекта разница между простотой/компактностью написания и удобством стремительно уходят не в пользу питона.
                                        Единственный серьезный ответ, который Я на это слышал — это повсеместное использование тестов. Но Я не понимаю, как они помогут (ну, в смысле так то тесты и в других языках полезны, кто спорит)
                                          0
                                          И, ну это боль. Я действительно не понимаю, как мне жить с объектами-словарями. Я регулярно ошибаюсь с сигнатурами функций (мне не могут подсказать, с каким объектом она работает), ловлю NaN и пустые ссылки.

                                          Вопрос запоминания фич языка. Вы б видели, какие фейспалмы я делаю каждый раз, когда сталкиваюсь с 1-based index в таблицах Lua. Это не (особо) мешает мне на нём писать.

                                          Я делаю это один и мне не удобно. А если это делает несколько человек?

                                          Если вы командой, не особо знающей js — пишете на js, то на мой взгляд вы что-то делаете неправильно.

                                          Я регулярно ошибаюсь с сигнатурами функций (мне не могут подсказать, с каким объектом она работает), ловлю NaN и пустые ссылки.

                                          Вам не хватает статических типов. Пишите код методом TDD или же берите Typescript.

                                          Я не могу защитить объект, что-бы его нельзя было использовать неправильно

                                          Можете (ESNext, Typescript). Ну, в рамках адекватного использования, разумеется.

                                          не могу изолировать одну часть от другой

                                          Можете.

                                          мало инструментов

                                          На этом месте я начал смеяться, потому что инструментов на самом деле уже сильно больше, чем надо. А не «мало».

                                          много вариантов хаков, много «гибкости»

                                          И этим всем можно не пользоваться. Ну, как обычно и в общем-то на любом языке: можно стрелять себе в ногу, а можно и не стрелять.
                                            0
                                            Ну так о том и речь.
                                            TDD — отлично, прекрасная практика, но она не решает всех проблем отсутствия типизации.
                                            Typescript — вообще другой язык, придуманный специально потому, что кому-то, как и мне, не нравились подобные аспекты js.
                                            Я согласен — js — хороший инструмент, чтобы сделать из него другой язык с другим поведением средствами самого js. В этом смысле инструментов достаточно, только выбирай.
                                            Понятно, что даже был бы он идеальным, нашлись бы хейтеры, а так как он супер распространен — хейтеров супер много.

                                            Мне не хватает статических типов — это моя слабость? Программистам js норм, или они плачут и колятся?
                                              0
                                              Typescript — вообще другой язык

                                              Ну нет. Это очень сильное заявление.
                                              Я бы TS назвал «синтаксическим сахаром про статическую типизацию». Он не превращает JS в другой язык, это всё тот же JS — с добавками. Это даже не как C и C++, разница куда более скромна.

                                              Мне не хватает статических типов — это моя слабость? Программистам js норм, или они плачут и колятся?

                                              Они либо пишут что-то не сложнее хеллоуворлдов, либо у них TDD, либо типы через какой-нибудь TS или (не к ночи будь помянут) Flow. Либо они быстро пишут код и очень-очень долго дебажат, такое тоже бывает.
                                            0

                                            По своему опыту могу сказать, что очень помогает vscode + jsdoc + определения типов. vscode умеет в подсказках выводить структуру объекта, его типы. Проверки входных данных можно делать по-разному: для больших json объектов можно использовать валидаторы типа ajv, для небольших можно дефолтные данные напихать. Внутри команды можно (и нужно) договориться о едином стиле, настроить строгие линтеры. Ну и, конечно, немного решает опыт, знание нюансов, лучших практик.

                                              0
                                              Ну вот Я не понимаю, если эти проблемы решаются в других языках типизированными схемами, определение типов явное и без волшебства с рефакторингом, многие вещи уже договорены.
                                              А опыт, знание нюансов, лучшие практики и договоренности о едином стиле можно потратить на другие аспекты разработки.
                                              В чем тогда плюс JS?
                                              Он реально хорош, или люди не осознают его ограничений + низкий порог входа + универсальность и стандарт во frontend разработке?
                                          +1
                                          JavaScript в его текущем состоянии прекрасен! Недавно перелез с C# (более 5 лет опыта) на JavaScript/Node.JS — получил огромное удовольствие от программирования на нём: гораздо легче, быстрее, приятнее на нём писать, аналогичный проект получился гораздо проще и раза в 3 меньше, чем на C# без строгой типизации и прочей ерунды, по ощущениям работает быстрее и т.п.

                                          Возможно для больших монолитных проектов C# и будет лучше, но для маленьких и средних JavaScript/Node.JS очень удобен.
                                            +2

                                            Для "маленьких и средних" есть много чего удобного :). Причем без зоопарка npm

                                              +1
                                              раза в 3 меньше, чем на C# без строгой типизации и прочей ерунды

                                              А потом эти «3 раза» догоняются в тестах на проверках, что оно валидно работает с необходимыми типами данных. Так себе размен.
                                                0
                                                А я перешел на JavaScript с ruby… И… Ну так себе, не очень впечатлен. Была бы возможность нормально ruby использовать в web, react / react native — его бы использовал.
                                                +2
                                                по ощущениям работает быстрее

                                                Сервер на localhost быстрее отвечает?
                                                Писали что-то сложнее Hello world?
                                                Писали статический сайт?
                                                Писали бенчмарк на сайт?
                                                Проводили нагрузочное тестирование?
                                                  +4
                                                  Чат-бота писал сложного, на JavaScript работает гораздо быстрее. Бэкэнд на JavaScript/Node.JS работает быстрее. Был у меня какой-то тест на моей конкретной задаче — раза в 2-3 быстрее выходило. V8 — в общем ;)
                                                    0
                                                    А бот на C# у вас тоже асинхронную модель использовал? И на какой платформе он работал? Windows, Linux, Mono/.Net Core?

                                                    Спрашиваю не холивара ради, а интереса для :)
                                                      0
                                                      Да с async, Linux, .Net Core
                                                  0
                                                  без строгой типизации и прочей ерунды

                                                  Ерунды? Серьезно??
                                                    +2
                                                    Вполне. Часто в контекст чата нужно было передавать параметры. В C# нужно было описывать большие безполезные и строго типизированные структуры для этого, на это тратились целые файлы исходников. На JavaScript-e это всё было гораздо проще. Можно примеры посмотреть MS Bot Framework.
                                                  +4

                                                  У JS есть очевидное преимущество: движок V8, делающий этот язык одним из самых быстрых (если не самым быстрым) интерпретируемых языков в мире. Также этот язык довольно быстро прогрессирует, и в 6й версии уже сильно не похож на то, каким мы все его знаем по году этак 2009-му.

                                                    +1
                                                    Причём прогресс осуществляется во многом вопреки фанатам языка, которым о какой фиче ни скажи, так всё «нинужно, ты просто ниасилил». Помните форумные споры года этак 2008-го, когда js-филы с пеной у рта доказывали, что вот это безобразие:
                                                    function extend(Child, Parent) {
                                                    	var F = function() { }
                                                    	F.prototype = Parent.prototype
                                                    	Child.prototype = new F()
                                                    	Child.prototype.constructor = Child
                                                    	Child.superclass = Parent.prototype
                                                    }
                                                    это якобы хорошо и замечательно. Заметьте: в языке на тот момент даже нет нормального способа сделать цепочку прототипов, но фаны готовы пинать любого, кто скажет, что такая объектная система просто убога.
                                                    Потом точно так же вопили, что не нужны классы. И люто ненавидели промисы, потому что «нефиг тащить ваш Haskell в нормальный язык»…
                                                      +5
                                                      Вам смешно, а у меня в кровавом энтерпрайзе многокилобайтный код, который с 2004 по 2014 спокойно на этой «убогой» системе работал и не жужжал.
                                                      Сейчас, конечно, его таки отправили на вечный покой — пора б уже. Но кому форумные споры про убогие системы, а кто софт 10 лет продаёт.
                                                        0
                                                        И люто ненавидели промисы, потому что «нефиг тащить ваш Haskell в нормальный язык»…

                                                        Дану, насчет классов я согласен, но у промисов особо хейтеров вроде не было, как и у async/await.
                                                        На JS не настолько распространен подход использования классов как в других языках, в которых их поддержка была изначально. Но вот проблема callback hell'a там была изначально, поэтому все в основном радовались промисам и async/await.
                                                      +6
                                                      Знатный наброс. Автор где-то взял некие утверждения, но даже не разобрался в их сути и контексте. Типичная демагогия из серии: «сам придумал — сам опроверг». Причём даже с опровержениями туговато из-за непонимания предмета и ничем не обоснованных категорических суждений вроде «Прототипы, конечно же, не годятся для разработки программного обеспечения». Автор не осилил прототипы что-ли?
                                                        0
                                                        Когда-то давно испытывал восторг и негодование каждый раз при знакомстве с другими языками после JS, каждый раз меня будоражил вопрос: а что так можно было?!!! JS казался днищем. Прошли года, теперь я люблю JS и стараюсь его всячески защищать. И он отвечает взаимностью.
                                                          +11

                                                          JavaScript — простое понятие объекта, нормальные замыкания. Плюс прототипы, объясняющие, откуда у объектов/массивов берутся их дефолтные функции. И связка «функция в поле объекта», протаскивающая this.


                                                          На этом основа JavaScript заканчивается и всё остальное — сахар и объекты среды. И в этом его сила — он очень близок к Lisp по минималистичности и возможностям делать что угодно как угодно. Он не навязывает какую-либо «единственно верную» структуру и позволяет реализовывать абстракции, которые в других языках получили бы сопротивление от самого языка.

                                                            0

                                                            А ассемблер еще более гибкий и ненавязчивый. Хотите — вот вам goto на кусок памяти с данными. Хотите — перемножим первые несколько байт двух строк как числа. Только вот на ассемблере довольно мало пишут ))


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

                                                            +6
                                                            Он даже не имеет правильного целочисленного типа или правильного типа массива. Что это за язык!?

                                                            Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array


                                                            Чем же это неправильные целочисленные типы и массивы ?

                                                              0

                                                              Я думаю, что тут скорее речь о том, что int и float был объединен в один тип number.

                                                                0

                                                                Который double
                                                                52 бита мантиссы более чем достаточно для целочисленной арифметики, а для 32х битных целых чисел есть стандартный набор битовых операций, даже два варианта сдвига вправо.

                                                                  0
                                                                  Да, но в итоге для 32х битных целых используется 64 бита. Я не утверждаю, что это большая проблема для скриптового языка, но тем не менее формально автор прав. Полноценного int32 нету.
                                                                    +2
                                                                    > Да, но в итоге для 32х битных целых используется 64 бита.

                                                                    Основной причиной использования более 32 бит является необходимость хранить тип. Если хочется обрабатывать много целых и экономить память, комментатор выше уже упомянул Int32Array.
                                                                    Под само целочисленное значение, если оно достаточно маленькое, в движках используется 32 бита или меньше.
                                                              +3
                                                              Не нарадуюсь что в свое время выбрал именно JavaScript для интерфейса к своим С++ программам. Посматриваю на новые моды и нет желания на них переходить. Все хорошо.
                                                                0
                                                                1) Прототипное наследование с появлением классов — неактуально.

                                                                2) Хороший пример как асинхронная модель победила многопоточную — это победа nginx над apache, поэтому асинхронщина вечна, впрочем, как и многопоточность.
                                                                  0
                                                                  JFYI: в js нет классов чувак — это те же прототипы) developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
                                                                    0
                                                                    Я давно и успешно пишу на классах, ожидаю в этом году нового стандарта — приватные члены и методы, и мне неважно как они реализованы. Мой код похож на Java, и я в восторге от JS.
                                                                  +2
                                                                  Средства разработки (платформа, язык, сопутствующие инструменты) которые создаются для решения задач конечных пользователей и предполагают низкий порог вхождения всегда подвергаются подобной критике. Delphi, PHP, JS — всегда слышал примерно одно и то-же.
                                                                    0
                                                                    Я конечно уже сильно придираюсь, но просто это предложение отображает всю бредовость статьи…
                                                                    Большинство разработчиков, однако, презирают этот язык и, если бы у них действительно был бы лучший выбор, они бы его сделали

                                                                    Или тут некий конфликт утверждений, или у меня проблемы с логикой. Утверждается, что лучших вариантов, чем этот язык, нет (пусть даже только в некоторой области программирования), и тут же автор заявляет что JS — чуть ли не вселенское зло… Открою секрет дедукции — если нет ничего лучше исследуемого объекта, то, вероятней всего (сарказм! это определенно точно) этот объект и является лучшим из имеющихся для выполнения конкретных задач.
                                                                      +1

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

                                                                      –3
                                                                      Вывод правильный. Слабая типизация делает JS слабым. Хорошо что существует TS.
                                                                        –3
                                                                        У код манки так бомбит что полезли последнюю карму сливать.
                                                                        0
                                                                        Замечательно то, что эта статься сама есть пример трех «ложь про JavaScript» :)
                                                                        JavaScript – это самый неправильно понимаемый язык программирования в мире.
                                                                        первый раз такое слышу.
                                                                        Но очень похоже на пережёвываемую во всех аспектах тему неочевидностей поведения, особенно в части приведения типов. Да, тут тоже мануал надыбать можно, но такие мануалы более похожи на карту разложенных граблей… А если докопаться до официальных доков, то. блин, ну нельзя постоянно думать о каждой тонкости! Из-это этого чтения исходников напоминает распутывание клубка ниток, с которым поиграли три пьяных кошки!

                                                                        Асинхронное программирование — ключевая сила JavaScript
                                                                        аналогично, ни разу такого не слышал, а вот стонов про то, что в JavaScript не хватает нормальной многопоточности — хоть отбавляй.

                                                                        JavaScript является самым популярным языком программирования в мире.
                                                                        полнее и точнее утверждение будет в виде «JavaScript является самым часто встречающимся языком программирования в мире веб-разработки», ибо тут оно на каждом углу :)
                                                                          +2
                                                                          Я уверенно предсказываю, что Go вытеснит Node в будущем, как только он нарастит свою экосистему фреймворков и пакетов. Его траектория неоспорима.


                                                                          гомерический хохот
                                                                            +2
                                                                            У автора бомбануло… Тут по-моему причина — какая-то личная проблема. Жена там к яваскрипт-разработчику ушла, или еще чего. Так желочью исходить по-поводу просто технолгии — странно
                                                                              –3
                                                                              Судя по комментариям бомбит больше у самих яваскриптеров, бегут доказывать что кто-то в интернете не прав.
                                                                              +1

                                                                              Если го захватит мир я буду подавлен. Язык из которого ради безопасности и скорости разработки вырезали все что можно было.

                                                                                –1
                                                                                Dunaevlad
                                                                                JavaScript был разработан быть легким, свежим скриптовым языком для веб-браузера. Как таковой, он был сделан, чтобы быть гибким и чрезвычайно прощающим, со слабой типизацией. Он даже не имеет правильного целочисленного типа или правильного типа массива. Что это за язык!?


                                                                                PL/1 был разработан как идеальный язык почти для всего. И где он?

                                                                                Cobol был разработан как идеальный язык экономических и финансовых расчётов — и где его теперь найти?

                                                                                SQL был разработан и отобран на конкурсе как самый простой и понятный язык для бухгалтеров, кладовщиков, библиотекарей, экономистов, кадровиков и статистиков — и кто же на нём программирует сейчас?

                                                                                Java был разработан как язык для встраиваемых систем, пульта управления телевизором, но взлетел как язык для «оживляжа» интерфейса веб-страницы в броузере (java-апплет), но найдёте вы его там, где вовсе и не ожидали увидеть его авторы этого языка в далёком 1995 году — в «кровавом энтерпрайзе» (на сервере).

                                                                                Языки развиваются как мемы. (Вспоминая Докинза).

                                                                                P.S. "JavaScript был разработан быть легким, свежим скриптовым языком для веб-браузера." Но он вдруг стал завоёвывать весь мир!
                                                                                  0
                                                                                  Согласен! И вот таким людям ставят карму в минус — ну не бред?! :)

                                                                                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                                                Самое читаемое