Пользователь
0,0
рейтинг
5 июля 2014 в 06:58

Разработка → TJ Holowaychuk: Прощай Node.js перевод

Примечание от переводчика:

Я решил перевести эту статью в основном из-за личности автора. TJ вложил очень много усилий в развитие Node.js и его инфраструктуры, он автор таких проектов как express, jade, mocha, stylus, автор 550 репозиториев на npm. Существуют также теория, что под этим именем скрывается группа людей.

Как бы то ни было, JavaScript и Go сообщества в ближайшие время ожидают изменения.

Покидая страну Node.js


Я сражался с Node.js достаточно долго, что бы перестать получать от этого удовольствие, это мое официальное прощание! И, что еще важнее, я ищу людей, которые смогут поддерживать мои проекты!

Node отлично справляется с некоторыми вещами, но, к сожалению, это не самый подходящий инструмент для того, что мне сейчас интересно. Я все еще планирую использовать его для сайтов, но если вы хотели бы заняться поддержкой одного из моих проектов, дайте мне знать. Просто оставьте комментарий с вашим именем на Github, ссылкой на npm и названием проекта. Как обычно я прошу не делать больших изменений в существующих API: создать новый проект будет проще.

Я также продолжу поддерживать Koa.


Святой Грааль


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

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

Я не говорю, что Go — «Святой Грааль», он не идеален, но для меня, среди существующих сейчас языков, Go — отличный выбор. Со временем, когда языки следующего поколения, такие как Rust и Julia найдут свое применение и повзрослеют, я уверен, что количество отличных решений увеличится.

Лично меня Go больше всего впечатлил скоростью развития языка. Весьма впечатляет увидеть, как разработчики стремятся к 2.0 и, как я слышал, не боятся поломать обратную совместимость, что отлично.

ПОПРАВКА: Я видимо неправильно прочитал рассылку, никаких критических изменений ближайшее время не планируется.

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

Почему Go?


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

Еще раз, я не утверждаю, что Go — самый лучший язык в мире, и вам обязательно нужно начать его использовать, но он весьма зрел и надежен для своего возраста (ему примерно столько же, сколько и Node.js), рефакторинг с типами прост и приятен, инструменты, которые Go предоставляет для профилирования и отладки работают отлично, а в сообществе есть устоявшиеся представления о документации, форматировании, измерении скорости и дизайне API

В момент первого знакомства с Go, стандартная библиотека показалась мне просто ужасной, в основном из-за того, что я привык к ультра-модульности в Node, и видел, как гниет стандартная библиотека в Ruby. Когда я начал больше работать с языком, я понял, что большая часть stdlib Go играет важную роль в разработке программного обеспечение: компрессия, JSON, буферизированный ввод/вывод, операции над строками и прочее. Большая часть этих API хорошо продуманы и мощны. Можно писать целые программы, в основном используя лишь стандартную библиотеку.

Сторонние библиотеки Go


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

Не существует единого репозитория для библиотек Go, поэтому часто можно встретить 5 или 6 разных пакетов с одним и тем же именем, что может иногда вызвать путаницу, но у этого есть и полезная сторона: нужно внимательно проверять каждый, чтобы выбрать самое лучшее решение. В Node есть общепринятые модули, вроде “redis”, “mongodb-native”, или “zeromq”, так что можно предположить, что это лучший вариант и остановить поиски.

Go или Node?


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

Обработка ошибок, на мой взгляд, реализована в Go гораздо лучше. Node позволяет нам принять решения для каждой отдельной взятой ошибки, но есть несколько вещей, где у Node все плохо:
  • У вас могут быть дублированные callback'и
  • Вызов callback'а может потеряться по дороге
  • У вас могут быть ошибки вообще из других потоков
  • В обработчик emitter могут прийти несколько событий типа «error»
  • Если не поймать ошибку, то все полетит к чертям
  • Часто непонятно, как именно обрабатываются ошибки
  • Обработчики ошибок слишком многословны
  • Callback'и — отстой

В Go если мой код выполнен, он выполнен, нельзя еще раз выполнить оператор. В Node это не так. Вам может показаться, что код закончил выполнение, ровно до того момента, пока библиотека случайно не запустит callback несколько раз, или неправильно очистит обработчики, что вызовет повторое исполнение кода. С этим непросто разобраться, особенно когда код уже в продакшене, да и зачем? Другие языки не заставят вас так страдать

Node в будущем


Я еще надеюсь, что у Node все будет в порядке, множество людей вложили в него свой труд и у него есть потенциал. Я считаю, что Joyent и команда должны сфокусироваться на удобстве использования: производительность ничего не значит, если ваше приложение сложно отлаживать, рефакторить и разрабатывать.

Наличие ошибок вроде “Error: getaddrinfo EADDRINFO”, по прошествии 4-5 лет, показывает расстановку приоритетов. Понятно, что можно пропустить такие мелочи, если вы концентрируете свои усилия на разработке ядра системы, но пользователи раз за разом напоминают про это а результатов все еще не видно. Мы обычно получаем ответы от людей из «элиты», заявляющих, и сейчас все идеально, но, на самом деле, все обстоит иначе.

Потоки (Streams) сломаны, работать с callback'ами неудобно, сообщения об ошибках расплывчаты и непонятны, инструменты не вызывают восторга, соглашения сообщества вроде есть, но им еще далеко до того, что есть в Go. Учитывая все вышеперечисленное, существует набор задач, для которых я продолжу использовать Node: сайты, может какой-нибудь прототип или API. Если Node сможет починить свои основные проблемы, тогда у него есть неплохие шансы оставаться полезным, однако аргумент, о предпочтении производительности удобству использования, работает не очень хорошо, учитывая, что существуют решения, которые быстрее и удобней.

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

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

Примечание от переводчика:

Совсем незадолго до появления переведенной статьи, была опубликована заметка от Will Yager с противоположным мнением: Почему Go плохой (eng.), было бы здорово, если бы кто-то знакомый с Go, взялся бы за перевод, чтобы дополнить картину.
UPD: А вот и перевод
Перевод: TJ Holowaychuk
Kirill Cherkashin @z6Dabrata
карма
89,5
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (70)

  • НЛО прилетело и опубликовало эту надпись здесь
    • +15
      Знаете, многие программисты боятся/избегают таких вещей как асинхронное программирование или многопоточное программирование. Это чисто психологическое явление, но это факт (на слайдах недавнего выступления Роба Пайка была фраза «Threads scare people.»).

      Лично меня асинхронное программирование не пугает — я пишу асинхронный код уже более 10-ти лет (в основном на Perl, но это не важно), делал свой event loop (не от хорошей жизни, просто в 2004-ом не было готовых библиотек для perl на epoll), написал кучку модулей (для асинхронного I/O, асинхронной работы с MySQL, etc.) на CPAN, недавно статью про альтернативу Promises/Deferred.

      При этом многопоточное программирование в традиционном (не CSP) стиле меня тоже пугает и я его вполне успешно избегал всю жизнь.

      Так вот, я могу ответственно заявить, что писать многопоточный код в стиле CSP (например на Go или Limbo) действительно на порядок проще, чем асинхронный! И callback-и действительно полный отстой по сравнению с CSP. Так что ничего удивительного в решении TJ Holowaychuk нет.
      • НЛО прилетело и опубликовало эту надпись здесь
        • +1
          Дело не в том, хороши коллбэки в ноде или нет. Я согласен, что в ноде подход к обработке ошибок сделан неплохо, да и стандарт для Promises появился во многом благодаря активному использованию коллбэков в ноде. Но суть в том, что как бы ни были хороши коллбэки в ноде, писать обычный синхронный код без коллбэков намного проще.

          Проблема была в том, что такой код раньше был (по сравнению с асинхронным) либо очень медленным, либо очень сложным (на традиционных нитях). Но стиль CSP это изменил, и теперь можно писать (например, на Go) синхронный, и при этом очень быстрый и простой код.
          • НЛО прилетело и опубликовало эту надпись здесь
            • +3
              На всякий случай если кто не в курсе — в EcmaScript 7 планируют добавить async-await — наглядно, удобно и асинхронно. Вариант с генераторами и yield в принципе аналогичен.
        • +1
          Коллбэки не composable. точка.
      • +2
        А где сейчас используется Go?
      • 0
        Чтобы писать без колбэков вовсе не обязательно отказываться от ноды :-)
  • –25
    Бег Головайчука в ноде на одну проблему станет меньше. Позор предателям! Слава джаваскрипту!
    • +2
      Бендер, ты же должен был говорить «Смерть человекам!». Что с тобой стало? Опять ты с tessel баловался.
      • –3
        Без Головайчука, я имел в виду без, но бег тоже в тему, я больше скажу, не без, а побег.
      • +38
        Фразы «Слава джаваскрипту!» и «Смерть человекам!» не так сильно отличаются по сути.
    • +38
      Колбекам слава!
  • 0
    Это видимо тренд, то основной разработчик скала говорит что скала гавно, то разработчик nodejs. А люди в тоже время продолжают использовать эти технологии и вполне себе довольны.
    • +19
      «Люди довольны» — с одной стороны не сильно аргумент, т.к. до сих пор живут люди, довольные Delphi и Borland C Builder :)

      Все языки/платформы/фреймворки — это инструменты, имеющие свою область применения, а не самоцель. There's no silver bullet. А разработчики все же люди, у них изменяются решаемые задачи, изменяются самые технологии, и в какой-то момент они упираются в те самые рамки области применения для своего инструмента, и многие — кто с огорчением, кто с радостью — берут в руки другой инструмент. Это нормально, так работает прогресс :)
      • 0
        А чем плох BCB?
    • +2
      > основной разработчик скала говорит что скала гавно
      Можно ссылку?
    • +3
      Людям интересны разные этапы. Одним — творить всё новое, менять старое, и менять даже своё вчерашнее, потому что он ушел уже дальше. Когда язык становится популярным и используемым, то он само собой начинает костенеть, возникают традиции, правила. В такие моменты создатели и чувствуют желание уйти, и ищут для этого причины.Сам язык тут не при чем.
    • 0
      1) Ну как основной. Коммитил больше всех на гитхаб в течение одного года, но это не значит, что был лидером, самым ценным и т.п. Он был одним из единичных «внешних» разрабов скалы.
      2) Основные его претензии были не столько к языку, а к коллекциям. Грозился сделать свое. Проблемы реальные, но критичность их натянутая.

      Пока от него было много крику, про зачатки новых коллекций не слышал еще.
      • +1
        Не год, а пять лет.
        Не к коллекциям, а к компилятору, который настолько излишне усложнен, что нужно быть Эйнштейном от программирования, чтобы что-то там править. Хотя у него и были претензии к коллекциям, а именно что мутабельные и иммутабельные классы наследуются от одних родителей, все же основной посыл состоял в том, что все написано в угоду временной производительности и совместимости, нежели понятности и изменяемости, а виноват во всем компилятор.
  • 0
    Мне кажется, Node.JS в конечном счете зайдет в тупик, потому что это единственная платформа, которая поддерживает Javascript на сервере. Я бы с удовольствием посмотрел бы на реализации Node.JS от Mozilla с их движками или даже от Microsoft (при условии, если они будут Open Source'ить их).
    Не так давно я читал статью Domenic Tarr о том, чего можно достичь с Open Source. Да, человек идеалист, хочет мира во всем мире и текст наивен, однако в статье есть замечательные слова:
    Fortunately, it’s possible for these monkeys to work in teams. In fact, it’s really quite simple, because they actually work better if they are just let to themselves and given only the most gentle direction. If you try and dictate what they do they’ll only resent you. All that is needed is the right sort of guide to encourage them to communicate in the most effective way, and make it more rewarding for them to work together than to work on their own.
    This is essentially what git, github and npm accomplish.
    Я считаю, что благодаря TJ, Node.js, npm это действительно стало так. Эти вещи взорвали Open Source и подстегнули его развитие, на мой взгляд не меньше, чем Линус. И это самая замечательная вещь, которая получилась у Node.JS. Объединять людей со всего земного шара для того, чтобы делать крутые штуки.
    • +2
      > Node.JS в конечном счете зайдет в тупик, потому что это единственная платформа, которая поддерживает Javascript на сервере
      не понимаю, а разве для php, java, .net и прочих не так?
      • +2
        А чем .Net не улучшенная версия Java EE, SE? Спорить конечно о том, что лучше не буду, но прицел разработчиков был явно такой.
    • +3
      ASP.NET Owin «Helios» как раз неплохое развитие идеи Node.JS, только с преимуществами типизированного языка.
      Если не смотреть на монстроузный комбайн под названием ASP.NET Identity 2 — то очень лаконичный и простой в изучении фреймворк получился.
    • +1
      Есть 2 TJ — Tj Holowaychuk автор статьи и TJ Fontaine Node project lead. Вы про которого?
      • 0
        Второй пока что ничего грандиозного не сделал, имхо.
    • 0
      так не единственная же — как минимум есть vet.x
  • +3
    edit: ответ нв комментарий выше:
    Есть же Rhino от Mozilla,
    есть ему на смену Nashorn от Oracle, работает в JVM
    • +6
      Rhino это движок Javascript, Как и Rhino, Nashorn, Spider Money. А Node.js это платформа, которая построена поверх движка. И на данный момент это единственная распространенная платформа.
      • +3
        Monkey. Прошу прощения.
      • 0
        JavaScript — один из нативных языков разработки под Windows 8, например.
        • +8
          не нативных, прошу заметить.
          • 0
            Мде? А в чем разница относительно нативных?
        • +1
          JScript?
          • +1
            WinJS!
      • +3
        На основе nashorn oracle делает project avalon, как совместимую с node.js платформу. Поживем увидим.
  • +1
    Кстати говоря, статья с критикой Go, упомянутая в конце перевода, очень интересная.
    • +1
      Да, только вот сравнивают Go не с Node, а с Rust… и, кстати, плюс один — статья и правда интереснейшая…
    • +14
      Статья неплохая, но общее впечатление от неё «ну почему же Go не Haskell?!». В недавнем выступлении Роб Пайк по сути объяснил «почему Go не Haskell» — они осознанно создавали не экспериментальный язык, а максимально обычный и привычный для программистов C++ и Python язык, старались отобрать в язык лучшие концепции из широко известных и популярных языков а не экспериментировать с новыми концепциями. Всё это для того, чтобы добавить к получившемуся простому и привычному языку всего одну концепцию: параллелизм на CSP.

      Дело в том, что они раньше уже выпускали действительно революционные и экспериментальные вещи (Plan9, Inferno, Limbo) но они «не взлетели». Так что Go — это попытка двигаться в том же (Plan9/Inferno) направлении, но на этот раз ма-а-аленькими шажками, приучая людей к хорошему постепенно.

      Конкретнее по пунктам той статьи:
      • я где-то недавно читал, что Generic-и в Go могут добавить, просто пока не определились как это лучше сделать;
      • перегрузка операторов — нет, спасибо, видя + я хочу знать что это сложение без беготни по исходникам всех операндов этой операции чтобы выяснить, что на самом деле будет происходить при выполнении этой операции;
      • по поводу отсутствия в Go продвинутой системы типов Haskell уже сказал выше;
      • что касается Immutability, то это дело хорошее, но при использовании CSP проблема «bug caused by mutating a data structure in one place while using it in another» решается иначе: структура данных принадлежит одной конкретной нити/горутине, и все остальные нити работают с этими данными через каналы — таким образом весь код, который using и который mutating эти данные находится in one place;
      • Pattern Matching тоже штука хорошая, но аргументация та же, что и для продвинутых типов Haskell;
      • Embedded Programming — Go для этого не подходит, его разрабатывали для других задач, ничего плохого в том, что у языка есть своя область применения и он не годится для других областей нет (впрочем, автор этой статьи тоже так считает).
      • +5
        switch case конструкция бесит своей ограниченностью начиная с С, думаю, что Pattern Matching — должен пойти в народ легко, жаль, что не сделали
      • +1
        * Насчет перегрузки операторов — что изменится, если я напишу (Python)
        def add(self, other):
            return self.val * other.val
        
        o1.add(o2)
        

        вместо
        def __add__(self, other):
            return self.val * other.val
        
        o1 + o2
        

        Оба варианта выглядят как сложение, хотя внутри умножение.

        * Насчёт системы типов — всё-таки приятнее, когда типизация продуманная и РАБОТАЕТ, а не добавлена «для галочки» и страдает дырявостью.

        * Pattern matching — я лично не понимаю что вообще можно иметь против него — штука то крайне удобная (что в Erlang, что в Rust). Сложным бы я его тоже не назвал.
  • +1
    Предлагаю немного другой взгляд на вопрос
    Головайчук много сделал для nodejs, это факт, express стал де-факто стандартом, все что ни делаеться так или иначе совместимо, расширяет, дополняет или копирует функционал express-а. Который в свою очередь копирует Синатру. Hо это Бог с ним, кто-то же должен был портировать хороший рестфул фреймворк на js, ой, как это express не restfull? тоесть хорошего рестфул фреймворка под js всеравно нет?! давайте хотябы споем хвалебную песню тому как написан express — он поддерживает прослойки (middleware) от connect (который написан тем же автором); он модульный, то есть состоит из кучи маленьких модулей, некоторые из которых состоят из 1 (одной) функции github.com/component/escape-html github.com/visionmedia/node-methods. Это конечно же сразу дает представление о том откуда у него 550 npm пакетов в репозитарии

    PS всем спасибо за внимание и понимание — наболело
    • +1
      Sails.js вполне себе RESTfull фрэймворк.
    • +11
      TJ Holowaychuk называет ультра-модульность (то есть ситуацию, когда есть множество мелких модулей, каждый из которых хорошо делает что-то одно) достоинством сообщества, сложившегося вокруг Node.js.

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

      Так случилось, что последний раз я увидал это на своём собственном примере: npm-пакет uue, к началу нынешнего июня созданный мною вообще-то для декодирования UUE-кодов из Фидонета (например, именно им декодируется SVG-файл во браузере гипертекстового векторного Фидонета), в том же месяце стал использоваться и пакетом mailparser (предназначенным для анализа не фидопочты, а интернетовского e-mail, в котором также ведь могут повстречаться UUE-коды) — так что в один прекрасный день я увидел, что его скачивают более трёх тысяч раз в месяц:

      [статистика] [гистограмма]

      Иными словами, сотни готовых npm-пакетов — это клёво, и это превеликая польза сообществу.
      • +8
        Благодарю за внеочередной пиар гипертекстового векторного Фидонета :)

        У модульной архитектуры определенно есть достоинства, которые никто не отрицает. тем не менее сейчас npm репозиторий забит мусором, нет не плохими пакетами, а именно мусором, кто-то, когдато сделал пакет с именем name и закомитил, навсегда забыв о нем, а другие люди поддержавшие идею вынуждены называть свои пакеты name-1 name_1 и my_name. Получаеться что не зная зарание что ищешь, там очень сложно что либо найти. Выход из этой ситуации нашел bower который прекрасно кушает ссылку на github или maven который кушает имя пакета (имя сайта в обратном порядке)

        теперь давайте отвлечемся от npm репозитория и посмотрим в package.json
        { "express": "4.4.5", "express-session": "1.6.1", "serve-static": "1.3.0", "compression": "1.0.8", "body-parser": "1.4.3", "morgan": "1.1.1", "static-favicon": "1.0.2", "cookie-parser" : "1.3.2", "errorhandler": "1.1.1" }

        это из моего текущего проекта, в нем 8 пакетов о которых я бы предпочел не думать, совсем, от слова вообще. Меня очень привлекает возможность заменить эти пакеты на другие, но других нет! нет ни вменяемого репозтитария прослоек для express, ни поиска, ни смысла их искать — проще сделать пулл реквест в существующие, так как они выпускают новые версии (патчи) раз в неделю, не реже.

        И у вас, кстати, не одна функция а uue пакете
        • +4
          > Благодарю за внеочередной пиар гипертекстового векторного Фидонета
          В этот раз без жидомасонства обошлось… и то ладно…
      • –2
        Воистину. Мне как-то понадобилась пара асинхронных функций: extend/defaults и each для объектов. Если вторая и является чисто оберткой классического each из пакета async, то extend — уже чуть посложнее. Я сделал эти модули сначала как часть библиотеки в своем проекте, а после решил выложить на npm. На пакет выходит примерно по 500 скачиваний в месяц — мелочь, а приятно.
        • +2
          скажите пожалуйста название пакета, очень хочеться посмотреть на асинхронный extend
  • +29
    Предлагаю теорию заговора: Гугл несколько лет силами своих разработчиков развивал виртуальный аккаунт TJ Holowaychuk, чтобы набрать авторитет среди разработчиков Node, а потом авторитетно заявить, что нужно валить на Go.
    • +8
      Эта теория имеет право на жизнь хотя бы из-за того, что о TJ Holowaychuk почти ничего не известно, он нигде не выступал и его никто не видел. Вот основная информация, которая о нем известна.
    • –4
      Переход на Go это дело времени, гугл другими способами этого добивается. А вот если бы ваш план существовал, TJ Holowaychuk бы сделал цикл статей про Google+
      • +10
        Зачем такой глупостью портить хитрый план?
  • +7
    Все свелось в итоге к недостаткам яваскрипта, странно, что это заняло у него так много времени.
    • +1
      Во многом, но не во всём. В инфраструктуре ноды тоже есть некоторые проблемы, в частности, он кстати упомянул некоторые невыразительные ошибки.
      Я думаю, потому и заняло много времени, что он считает существенными не столько архитектурные недостатки JS, сколько недостатки ноды.
  • –15
    Лично с node js сбежал на Meteor, хотя пока еще нет 1.0 но все равно очень приятна работать
    • +5
      Вы что-то путаете, Meteor это фреймворк для Node, который изначально поддерживал свой формат пакетов, отличающийся от npm, но сейчас работает и ним. Так что вы не смогли никуда сбежать :)
  • 0
    Марк Лехман (автор libev) утверждает, что ошибки и кривизна так или иначе заложены в самих механизмах асинхронной обработки (select, epoll, kqueue) на уровне ядер большинства современных ОС, поэтому нельзя так уж однозначно винить в кривости и убогости ту или иную надстройку над этими механизмами (будь то node.js или стандартная либа Go)…
    • 0
      libuv
      • 0
        libuv — асинхронное I/O
        libev — event loop

        Node.js использует и то и то.
  • +6
    Кто бы что не говорил о node.js — но в нем имеется одно для нас важное преимущество: один язык и один фреймворк для клиента и сервера. Скорость разработки приложения увеличилась у нас в разы, когда бизнес логика, хэлперы, сервисы и прочее используются по обе стороны.

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