Обновить

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

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

В мире существует множество шейперов данных по схемам, для этого не обязательно пытаться пересадить всех на свой протокол. Многие (наверное, большинство) систем разрабатываются не с единого плана, а по частям, разными людьми, в разное время, на разные деньги и с разными целями и ограничениями. Ваш монолит просто «не взлетит» в таких условиях без участия Главного Архитектора (вероятно, вас). Вместо описания стека попробуйте описать процесс создания и долгосрочного развития на нём приложения командой хотя бы из трёх человек, показав, какие процессы в их взаимодействии с вашим протоколом стали «дешевле» (во всех смыслах) относительно общепринятых подходов.

Evolution > revolution.

Ох уж эти теоретики. Все это уже было — и "прозрачные для приложения сетевые вызовы", и "автогенерация сетевого API по коду приложения", и "передача кода по сети". Красивые идеи, промышленные реализации — все они провалились.


Такого рода система требует упор на инкапсуляцию и обратную совместимость по API и данным. Говоря конкретно:


  • сетевое API должно быть контролируемым, чтобы обеспечить обратную совместимость. Предлагаемый подход вносит слишком много факторов, влияющих на API
  • то, что локальные вызовы и удаленные — это одно и то же — опасное заблуждение. Удаленные вызовы имеют свойство выполняться произвольное время, не выполняться вообще, требовать повтор запроса, при этом клиент не может знать, выполнен ли предыдущий или нет. Насколько я в курсе, пока никто не придумал унифицированную обработку ошибок, пригодную и для локальных, и для удаленных вызовов.
  • передача кода по сети значительно усложняет соблюдение обратной совместимости. Никто же не знает, что этот код, пришедший от клиента, будет вызывать?
  • Сетевые запросы имеют свойство "застревать" и доходить до получателя сильно позже того, как их отправили. Основные причины — использование очередей сообщений, хитрые механизмы передоставки, CQRS. Так что подход "сначала шлем модель, потом упакованные данные" — не универсален.
  • Сложность. HTTP как основной протокол передачи данных прижился благодаря исключительной простоте, гибкости и расширяемости — его смогли приспособить для решения очень многих задач. Описанная в статье "универсальная платформа" может и не оказаться настолько расширяемой либо может оказаться слишком сложной для понимания массами — и что тогда?
Предполагается передача кода по сети с сервера на клиент, ни это ли происходит при
<script src="script.js"></script>
Про обратную совместимость и прочее я уже пояснил, это экспериментальный стек.

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


Вообще если натянуть эту статью на архитектуру клиент-сервер, то она начинает обретать смысл. Но замахиваться на большее не стоит.

> Пора признать, что HTTP, полон проблем и костылей, он спроектированный полуграмотными в ИТ физиками CERNа, которые полезли не в свою специальность

— это конечно мощный вброс.

Если бы не эти «полуграмотные в IT физики», то возможно бы у нас вообще не было бы никакого веба. Для своего времени и своих изначальных задач HTTP более чем замечательно подходил. А то, что его стали использовать совсем по другому — это не вина «физиков CERN».
Да не их вина конечно, вот позорно, что программисты взяли эти наработки, не поправив их проблемы в самом начале, когда это было еще очень просто.
Возможно это произошло потому, что тогда это не было проблемой?
непонятно, почему вы называете людей, которые пишут под железо для установок типа Compact Muon Solenoid или Atlas «полуграмотными в ИТ».
ну и момент, когда «грамотные» программисты должны были решить, что вот теперь хватит использовать старые наработки, и пора написать своё тоже удобно выбирать, глядя из будущего. а когда у тебя символьный терминал к машине на VAX/VMS с запущенным браузером lynx со статьёй по физике частиц, в которой некоторые понятия выделены гипертекстовой ссылкой, проблемы протокола не так очевидны, даже не беря в расчёт качество соединения между узлами типа ЦЕРНа, Дубны и Протвино.
Не добавить ID запросов это откровенная лажа, инженер лучше добавит лишний ID, чем не будет иметь возможности однозначной идентификации.
НЛО прилетело и опубликовало эту надпись здесь
Во первых HTTP 1.1 — не блокирующий протокол. Ничего не мешает клиенту отправить пачкой кучу запросов через одно и то-же соединение, а потом читать ответы по мере их прихождения. Другое дело, что в большинстве случаев чтобы понять, что нужно еще от сервера — нужно сначала получить и распарсить HTML документ. (Если вас интересует, как клиент определит где заканчивается ответ на один запрос и начинается ответ на другой — «Content-Lenght: <blah-blah>»)

Так-же никто не мешает добавить ID поверх HTTP на уровне приложения, там где оно нужно.

Я не берусь утверждать что HTTP идеален, но те недостатки которые вы ему приписываете — во многом надуманные. А реальные его недостатки должны вполне неплохо исправиться тем-же HTTP 2.0.
НЛО прилетело и опубликовало эту надпись здесь
Поверх блокирующего протокола добавить ID, для различения ответов это шикарно. Посылаем запрос 1, ждем ответа 1, посылаем запрос 2, ждем ответ 2, класс просто.
HTTP 1.1 имеет блокирующие соединения, и ограниченное их число, это одна из причин разработки HTTP/2
https://http2.github.io/faq/#what-are-the-key-differences-to-http1x
«ordering and blocking» означает лишь то, что если вдруг какой-то из запросов «задумается», то последующие не будут отданны пока не «продумается» тот медленный. Вы же говорите о принципиальной невозможности послать запрос пока не прочитаешь ответ на предыщий запрос. А это совершенно не так в случае с HTTP/1.1, и такой сценарий более чем возможен, более того, используется всеми современными браузерами (иначе страницы грузились бы минутами даже на гигабитном линке), т.к. разница в производительности между «послать, прочитать, только потом послать второй, прочитать, потом только послать третий...» и «послать, послать, послать, читать, читать, читать» — просто огромная.
Главное преимущество HTTP/2.0 в этом контектсе в его демультиплексировании, по сути он создает множество «индивидуальных каналов», поверх TCP сокета, по одному на каждый запрос. И ответы соответственно могут вообще приходить разными фрагментами, например 100 байт от первого запроса, 200 байт второго, потом снова 100 байт от первого, потом 300 байт от 3-его, итп.
Через то же HTTP 1.1 соединение нельзя послать следующий запрос, пока не вычитаешь предыдущий.
Вот вы даже не знаете на что способен HTTP/1.1, но предлагаете его исправить.

А вот если бы вы например потрудились открыть RFC 2616 (т.е. основную спецификацию на протокол HTTP/1.1), то очень быстро бы нашли там такой абзац:

> — HTTP requests and responses can be pipelined on a connection.
> Pipelining allows a client to make multiple requests without
> waiting for each response, allowing a single TCP connection to
> be used much more efficiently, with much lower elapsed time.

Так что «полуграмотные физики CERN»-а сделали не такой уж плохой протокол. Просто современные программисты разучились читать документацию, и каждый лезет со своими костылями «я щас все исправлю». От этого и вышло, что веб — такое месиво из костылей
Так протокол остается блокирующим, проблема называется «head-of-line blocking», это для API совершенно не применимо, это для загрузки статики ускорит. А если через соединение отправить запрос, то до его возврата новый не отправить все равно. Pipelining позволяет отправить пачку запросов разом и так же разом ожидать на них ответ. По сути это отправка одного запроса, склеенного и получение на него одного большого ответа. Как только запрос или пачка отправлены, то соединение заблокировано до получения последнего из них. Смысл API в том, чтобы посылать запросы тогда, когда это нужно, в произвольное время.

Я тут один в мультиплексировании запросов HTTP/2 вижу костыль?


Ведь если добавить в протокол ID, то необходимости в мультиплексировании нет, зато появляются интересные возможности использования протокола, да ещё и разные, в зависимости от того, кто генерирует ID — клиент или сервер. Так ещё если и делать ID, то этож можно сделать ID функцией например, от времени и/или от uid инициатора соединения...


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

Как из анекдота «чем такого лечить, проще нового сделать». Добавить не очень сложно, но они очень долго не будет поддерживаться всеми, а значит, на нее нельзя будет рассчитывать. Да и ID это только одна проблема, нужно еще объединять мелкие пакеты в один и бить большие пакеты на части, потому, что один большой ответ может забить собой соединение на долго, не пропуская маленькие ответы. Еще нужно возможность отменять долгие запросы, да вообще слишком много чего нужно.
Сравните диаграммы
Вы сами то поняли, что на этих картинках?

Впрочем я не буду вдаваться в объяснения в чем вы не правы. Чем больше заблуждений у вас в голове, и чем большему количеству студентов вы из внушите, тем больше будет моя ЗП.
а где здесь диаграмма про JSTP?
У Вас определенно большие проблемы в образовании.
Аргумент, че…
Исходя из Вашей статьи очевидно, что Вы не знаете и не понимаете принципы HTTP.

Императивные инструкции в протоколе, жестко завязанные на реализацию какого либо языка ??
Почерк архитектора! че…
Очень умно:
{
...
  age: () => {
    let difference = new Date() - birth.date;
    while(true){new String("jstp is sh*t")};
    return Math.floor(difference / 31536000000);
  },
...
new vm.Script(code, { timeout: <number> });
Вы серьезно??

ДА Вы еще и JS не знаете!!!!111
в данном случае timeout Вам не поможет — зависнет функция в основном потоке, а не в
vm.Script


Я был не прав, у Вас не большие проблемы в образовании, а очень большие.
Попробуйте
Не, Вы серьёзно???????????

/tmp $ cat jstp.js 
"use strict"

const vm = require('vm');

var jstp = {}
jstp.parse = (s) => {
  let sandbox = vm.createContext({});
  let js = vm.createScript('(' + s + ')');
  let exported = js.runInNewContext(sandbox);
  for (let key in exported) {
    sandbox[key] = exported[key];
  }
  return exported;
};


let code = "{ a: 1, age: () => { for(var i=0; i<9999999; i++){new String('jstp is sh*t')}; return a; }}"

console.time("parse")
var o = jstp.parse(code)
console.timeEnd("parse")

console.dir(o)

console.time("call age()")
o.age()
console.timeEnd("call age()")


node jstp.js
parse: 1ms
{ a: 1, age: [Function] }
call age(): 2703ms


Картинка из Вашего профиля как бы намекает

image
Где?
new vm.Script(code, { timeout: <number> });
ВОТ:

"use strict"

const vm = require('vm');

var jstp = {}
jstp.parse = (s) => {
  let sandbox = vm.createContext({});
  let js = new vm.Script('(' + s + ')', { timeout: 1000} );
  let exported = js.runInNewContext(sandbox);
  for (let key in exported) {
    sandbox[key] = exported[key];
  }
  return exported;
};


let code = "{ a: 1, age: () => { for(var i=0; i<9999999; i++){new String('jstp is sh*t')}; return a; }}"

console.time("parse")
var o = jstp.parse(code)
console.timeEnd("parse")

console.dir(o)

console.time("call age()")
o.age()
console.timeEnd("call age()")

/tmp $ node jstp.js 
parse: 2ms
{ a: 1, age: [Function] }
call age(): 2782ms



Если Вы до сих пор не уловили в чем прикол — у Вас ни малейшего понимания JS
Я бы Вам не доверил проектировать и HelloWorld.
Это таймаут на парсинг, а теперь на исполнение скрипта
let exported = js.runInNewContext(sandbox, { timeout: 1000 });

Доки читайте.
Так че, заработало?
...
  let exported = js.runInNewContext(sandbox, { timeout: 1000});
...

parse: 1ms
{ a: 1, age: [Function] }
call age(): 2753ms

Таймаут должен быть в runInNewContext, и в JSTP он по умолчанию равен тридцати миллисекундам.

Тсс… пусть сам делает лабу, а не паленую сдает, я его уже почти обучил.

Это в случае, если будет что-то вроде (() => { while (true) /* do nothing */ ; })(). А функции с вычислимыми полями, которые вызываются позже, теоретически можно передавать, но на практике это нигде не используется сейчас, а когда будет, то естественно, что всё это будет происходить не таким кустарным способом.

Запустил код slayerhabr под node v4.2.6, указал timeout как и положено — в runInNewContext. Имею результат


parse: 2ms
{ a: 1, age: [Function] }
call age(): 2615ms

Никакого отвала по timeout'у не наблюдаю. Складывается впечатление, что timeout отрабатывает как минимум не всегда.

Так потому что age() вызывается уже после runInNewContext, смотрите мой комментарий выше.

Т.е., получается, что выставленный timeout никакого отношения к измеренному выводу времени работы age() не имеет? В одном случае


let js = new vm.Script('(' + s + ')', {timeout: 1000});

timeout выставляется на компиляцию кода, а в другом


let exported = js.runInNewContext(sandbox, { timeout: 1000});

на выполнение кода (т.е. на создание объекта и его метода age()).


Выполнение же метода age происходит здесь


console.time("call age()")
o.age()
console.timeEnd("call age()")

и никакими timeout'ами не ограничено.


В таком случае, непонятно, что имел в виду коллега slayerhabr, демонстрируя свой пример :(

flancer
Все очень просто — таймауты по сути ограничивают парсинг JS. выполнение JS кода они не ограничвают, т.к. функции выполняется он уже в основном контексте.

Все потому, что применение императивного кода в протоколе, как это предлагает «архитектор» — чушь и бред. Протокол по определению — декларативное понятие.
Вызывайте функцию age() через runInNewContext и будут ограничивать.
Таймауты нужно ставить на: парсинг, исполнение кода и вызовый функций, которые из этого кода экспортируются, но все это скрыто от разработчика, делается рантаймом.
НЛО прилетело и опубликовало эту надпись здесь
и в JSTP он по умолчанию равен тридцати миллисекундам.

полагаю, раз есть "по умолчанию", значит есть и явный способ задать timeout.

Считать пи на ноде, серьезно?
НЛО прилетело и опубликовало эту надпись здесь

Почему нет? В отдельном процессе норм.

Так в отдельном процессе на другом языке и по JSTP с ноды высылать запрос или адон на Си сделать, но в js не самая лучшая математика для алгоритмов.
смотря как считать ))

Считать π в геттере — довольно странное решение, имхо. Да и написано уже выше, что вычислимые поля пока нигде в JSTP не используются, а когда/если это понадобится, это уже отдельный вопрос. Просто теоретически такая возможность заложена и когда будет должным образом реализована, API для всего этого дела останется таким же, как и сейчас. Это ж эксперименты и угар, а не продакшн-реди код, чего вы хотели ¯_(ツ)_/¯

НЛО прилетело и опубликовало эту надпись здесь
1. Намертво привязать всё к этому несуразному языку — это и есть основная идея, хех. NechaiDO в последнем комментарии отлично это описал копипастом одного известного твита.

2. Это не сизифов труд, а кодинг в своё удовольствие. Кто-то собирает марки, а кто-то пилит ради лулзов свои технологии. Если время и деньги на это есть, то кто может это запретить? В конце-концов, «ради лулзов» — это лучшая мотивация, которая существует в этом мире.

3. AST лучше, спору нет, но посколько JavaScript не гомоиконичен, как Lisp или какой-то Rebol, то это противоречит пункту 1. Вообще, идея передавать функции в объекте мне очень не нравится, но если же разделять данные и метаданные, и сначала передавать один раз схему данных, а затем слать лишь чистые значения без имён полей, то тогда это можно по-человечески реализовать. Методы будут передаваться лишь один раз при передаче, фактически, уже класса, и можно позволить себе такую затратную операцию, как парсинг при помощи Esprima, анализ и валидацию AST на предмет разрешённых операций. Остаётся открытым вопрос о времени исполнения, так как г-н Алан Тьюринг в своё время математически обосновал, почему одна программа в общем случае не может узнать, завершится ли другая программа и если да, то за какое время, не выполняя её, но и эта проблема решаема, если разрешено будет лишь ограниченное подмножество операций над полями и всё. Даже не факт, что циклы нужны, а если и да, то можно банально ограничить количество разрешённых итераций.
НЛО прилетело и опубликовало эту надпись здесь

Собственно да, замыкания там не нужны. Как по мне, JSTP должен использоваться только для сериализации анемичных структур данных и единственное применения для функций там — это небольшие геттеры, буквально формулы от нескольких полей, ни в коем случае не поведение. MarcusAurelius привёл хороший пример, в котором person.birth.date — это обычное поле, а person.age возвращает возраст пользователя в момент вызова. Я вижу мало применений такой технике в прикладном коде, но для пока несуществующих GlobalStorage и JSQL это будет довольно полезная вещь.

НЛО прилетело и опубликовало эту надпись здесь
в то время и gopher замечательно подходил
но теперь почему-то о нем мало кто помнит
Теперь посмотрим более сложный пример JSTP, имеющий функции и выражения:

Зачем так усложнять? Все базовые элементы системы должны быть максимально простыми и независимыми. Что мешает определить 2 класса/метода PersoneSerializer и PersoneUnserializer для вычислимых полей?
Вычисляемых полей это не добавит и на каждый класс по два таких метода?
НЛО прилетело и опубликовало эту надпись здесь
Скобочки в Date это опечатка, спасибо, поправил. Пример концептуального кода по этому вопросу тут: https://github.com/metarhia/JSQL/blob/master/Examples/filterArray.js
НЛО прилетело и опубликовало эту надпись здесь
Потому, что это JavaScript, для отличения скалярных типов от объектов, встроенные типы данных пишутся с маленькой, а встроенные типы объектов в большой.

Второй вопрос: последовательность итерации ключей. Вы невнимательно читали статью, если вообще читали. Хром тут ни при чем, это не для браузеров все. Приложения на базе JSTP не будут работать в браузерах гипертекста, они запускаются в своем рантайме, который имеет встроенный парсер, работающий с порядком ключей так, как нужно нашему стеку. А пока все движки реализуют позиционное итерирование.
НЛО прилетело и опубликовало эту надпись здесь
Представьте, что мы откажемся от HTTP, HTML, CSS, DOM, URL....
Конечно своя среда запуска.
Для справедливости нужно сказать, что JavaScriptCore для iOS не поддерживает позиционного итерирования для числовых ключей.
> Мы имеем ситуацию, когда ни кто не использует REST, да ладно, мало кто понимает, что это, но все говорят, что у них REST API. URLы идентифицируют объекты или методы? PUT, PATCH и DELETE используются? Последовательность вызовов API не важна? У кого через REST работают платежи, корзина, чат, напоминания? В основном у всех AJAX API, которое так и нужно называть.

Вы ошибаетесь. Много у кого вполне себе Stateless REST API, и ресурсы и методы используются вполне верно. Конечно «чистый» REST API это маловероятный вариант в реальном проекте, но все не так плохо, как вы описали точно. И уж тем более не понятен ваш термин «Ajax API», причем тут вообще AJAX? Вы в курсе, что это вообще чисто браузерная технология? Да и сам термин во многом устарел. Если бы вы назвали JSON API или HTTP API, я бы еще понял.
Ну а в целом очевидно у вас «javascript головного мозга». Сам много пишу на js, но только сейчас понял какое это все таки зло и насколько это заразно. Удачи вам с лечением!

Прочитав заголовок — заинтересовался. Дочитав до JSTP подумал, что видимо пишет какой-то архитектор. Посмотрев на регалии автора — убедился в своей правоте.

Д т упрлс чтл?
Сразу изменить и протокол, и формат передачи, и серверную часть, и базу данных, и клиент-браузер.

Затея интересная, но трудоёмкая.

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

Вообще смотрю на этот широкий замах с умилением. Что-то подобное, причём весьма подобное, я и сам ощущал да испытывал, задумывая гипертекстовый Фидонет. Совершенно так же смотришь на технологии многодесятилетней давности и желаешь всё в них переменить: и разметку фидотекста (устроить гипертекст), и редактор-просмотрщик (поставить фидобраузер), и формат баз фидопочты (обеспечить поддержку хотя бы SQL-подобных запросов, если не Mongo-подобных map+reduce), и эхопроцессор (чтобы он работал с этой новой базой), и фрекопроцессор (чтобы можно было запрашивать не только файлы, но и сообщения фидопочты), и мейлер (чтобы вместо прежних двоичных пакетов в жёстком формате обмениваться каким-нибудь JSON), и так далее. В итоге оказалось, что и одного только фидобраузера хватит надолго повозёхаться.

(Правда, я не располагал отделом R&D размером в десяток человек. Располагая таким отделом, много чего можно достигнуть. Желаю удачи, разумеется.)
Спасибо за поддержку, надеюсь, что редукция до одного синтаксиса много что упростит. А JavaScript уже реализован на всех платформах. Мы и язык запросов делаем вот такого толка, см. концептуальный код. Это существенно проще, чем мы делали в конце девяностых на Дэлфи, шлюз между FIDO hydra протоколом и USP over TCP. Тмыл, голдед, UUE, это все было пропитано правильным духом общения людей, но таким же нагромождением стандартов, как и ветхий веб сейчас. Сейчас я год выбирал из более чем 300 студентов политехнического ВУЗа, читал лекции, делал семинары, сидел с ними с 10 утра до 10 вечера, и теперь они сами пишут код именно так, как это делал бы я, теперь они очень эффективны, потому, что одинаково мыслят, тратя минимум времени, чтобы договориться между собой. Мы все сделаем, тов. Mithgol the Webmaster!
НЛО прилетело и опубликовало эту надпись здесь
У нас: несколько сишников, несколько питонистов, несколько свифтовцев, несколько джавистов, несколько обджективсишников, по одному го и хаскелевцев.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Это просто «юношеский максимализм» ┐( ̄ー ̄)┌
Вообще пользуюсь какой-нибудь технологией часто задумаюсь о своём «велосипеде» (◡ ‿ ◡ ).
был же в то время UUCP, зачем вообще придумали FIDO
Вновь подтверждён Закон Этвуда: «Всё, что может быть написано на JavaScript, будет написано на JavaScript».
Кстати, так нечаянно случилось, что именно сегодня, 23 августа, 25 лет назал, другой Тим запустил ветхий веб, о чем нам рассказывает Wired, а 6 лет назад тот же Wired похоронил веб
НЛО прилетело и опубликовало эту надпись здесь
Впервые новый протокол не вводит ни одного нового синтаксиса или нового формата данных, а использует уже стандартизированный EcmaScript.
НЛО прилетело и опубликовало эту надпись здесь
Зачастую кол-во знаний, ресурсов и времени очень сильно влияет на «взял и переписал» и «создал свой».
НЛО прилетело и опубликовало эту надпись здесь
> Потому, что в HTTP нет нумерации запросов, просто обычной, примитивной, самой простой нумерации нет и открытое соединение ожидает.

А Вы точно архитектор? Преподаватель?
НЛО прилетело и опубликовало эту надпись здесь
Не понимаю, почему этого еще нет:
«Один пацан писал все на JavaScript, и клиент, и сервер, говорил что нравится, удобно, читабельно. Потом его в дурку забрали, конечно.»
Я с огромным удовольствием прочитал статью и посмотрел видео. Спасибо, Тимур.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации