Как стать автором
Обновить

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

НЛО прилетело и опубликовало эту надпись здесь
> Какие проблемы будет легче решить используя statefull?

Все, в которых есть понятие «состояния».

Яркие примеры: авторизация и сессии.
сессия — это всё-таки средство, а не проблема :)
Более удобный для императивно- и функционально- ориентированных разработчиков, для которых привычнее описывать логику работы приложения путём декомпозиции на отдельные функциональные точки и программированием каждой точки в отдельном блоке (функции, модуле, объекте), а не развермишеливая её по REST-ориентированным запросам.
Разумеется, для веб разработчика, уже набившего руку на запрос-ответах, это непривычно. Поэтому и стоит тэг «новый взгляд».

Приемущества:
более последовательное описание логики,
отсутствие необходмости заботиться о сохранении состояния,
отсутствие проблемы кнопки «back» и «clone» (иллюстрировано картинками в «Inverting back the inversion»).

Если эти приемущества не очевидны, то можно сказать так:
Это не поможет решить какие-то принципиально новые проблемы.
Это поможет избежать большинства проблем и задач, возникающих при разработке веб-приложений.
Уважаемый qmax. Хочется заметить, что для «эмуляции»- достаточно лишь идентификатора сессии.

Остальное — дело техники. OOP в PHP давно позволяет делать __sleep/__wakeup. Для нормального «восстановления» объекта достаточно написать базовый класс и указать обработчик сериализованного объекта.

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

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

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

в качестве продолжения :) этого коммента я написал в апдейте поста иллюстрацию на scheme, использующую нативное использование продолжения в форме call/cc.
уровень условности реализации, думаю, ясен.

попробуйте переписать аналогичное на PHP с сериализацией объекта.
ну просто для сравнения.
По вашим словам, так за «иллюстрацию на scheme, использующую нативное использование продолжения в форме call/cc.»
будущее? =))))

Вот интересный вопрос: «наиболее естественно поддерживает». Вот лично вам не все-равно?
Для примера: file_get_contents пыховый или нативно-сишный fopen/fread. Нет file_get_contents — напишем для него враппер.

Вопрос не в том, чтобы «переписать аналогичное». Уверен, что переписать можно что угодно на чем угодно. Просто зачем набиваться на холливары — не совсем ясно =)
Вопрос не в холиварах, а в том, чтобы сравнить разные подходы.
У меня получилось в одну строчку. И я считаю это нагляднее и проще.
Что получится на php?
> По сути, «сессия» придумана, чтобы хранить состояние выполнения веб-приложения.
> А использование её тупо как набора данных — исключительно из-за отсутсвия в языке полнофункциональных продолжений.

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

Сериализация в PHP может быть использована для этой так называемой «континуации»?
в принципе, если инкапсулировать всё приложение вообще в какой-нибудь обект, то его сериализация вполне сойдёт за континуацию.

вот тут предлагается какаято библиотека для эмуляции продолжений в пхп.

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

Более удобный для императивно- и функционально- ориентированных разработчиков, для которых привычнее описывать логику работы приложения путём декомпозиции на отдельные функциональные точки и программированием каждой точки в отдельном блоке (функции, модуле, объекте), а не развермишеливая её по REST-ориентированным запросам.
Разумеется, для веб разработчика, уже набившего руку на запрос-ответах, это непривычно. Поэтому и стоит тэг «новый взгляд».

Приемущества:
более последовательное описание логики,
отсутствие необходмости заботиться о сохранении состояния,
отсутствие проблемы кнопки «back» и «clone» (иллюстрировано картинками в «Inverting back the inversion»).

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

Как относительно новый и интересный подход к разработке WEB приложений — однозначно must для ознакомления.
RESTfull => RESTful
statefull => stateful
упс!
ain't a native speaker :)
намного лучше рулить состояниями в определенных workflow фреймворках, типа OsWorkflow

продолжения — они несколько для других целей предназначены, и запоминания состояния приложения (Memento) — побочный эффект

IMHO
да нет. продолжения какраз для того и придуманы, чтобы сохранять состояние.
это основная их функция.
а то, что на них можно делать итераторы, сопрограммы, и прочее — следствие.
Спасибо за затронутый вопрос. Буквально намедне пришла в голову мысль: «Почему эту особенность сессии даже толком нигде не описывают?» Единственное. описание в статье несколько сумбурное — затрагивается несколько вопросов, а сводится все к одному.
Что касается поддержки языков точек восстановления, это, конечно, удобное подспорье в решении задачи, но не основополагающее. Например, в распределенной бизнес-транзакции одной поддержки языком явно недостаточно.
статья сумбурна, потомучто толком сам ещё не разобрался. это в общемто — просто изложение идеи.

а конкретного опыта написания таких приложений пока нет.
конкретно в питоне генераторы реализуются ЧЕРЕЗ продолжения. и поэтому их можно заюзать в этом качестве.

в оргинале статьи был ещё более явный пример на scheme.
но я побоялся ломать мозг ещё и этим :)
смотря в каком ) в Stateless — да, а в стандартном питоне нет продолжений, и генераторы там созданы на обычных сях, без каких бы то ни было абстракций )
да и генераторы могут быть сделаны не только на продолжениях но и, например, на потоках (подробнее тут www.python.org/dev/peps/pep-0255/)
а продолжение — гораздо более мощная конструкция

почему это не продолжения, например, как сейчас вспомню свою мысль, например можно вернуть продолжение из нескольких вложенных вызовов функций, а с генераторами так не выйдет.
Ну и пару ссылок, где еще это обсуждается (отличие генераторов от продолжений)
www.hutteman.com/weblog/2005/04/26-224.html
zope.stackless.com/spc-sheets-seoul.ppt
оговорился, в Stackless
ну да, естественно, продложения более мощные конструкции.
однако yield всёже обладает некоторыми подходящими свойствами.
хотя я слабо представляю как можно их сделать на «обычных сях».
и интересно посмотреть как оно будет реализовано на PyPy.

да и пост в общем-то не про питон :)
да как на обычных сях, очень просто, посмотрите, например файлик genobject.h из стандартного дистрибутива питона
подходящими для построения на его основе веб-фреймворка (по принципу продолжений) вроде не обладает, т.е. когда захочется сделать компонентную модель (по типу Seaside), что-то мне подсказывает, что не получится
кстати сказать, именно эта твоя статья меня и побудила написать заметку :)
я там даже коммент оставил.
Поясните дураку. При применении данной технологии приложение становится подобием конечного\бесконечного автомата? Таким образом мы выводим проблемы возможности\невозможности какого-либо действия из данной точки на принципиально новый уровень? Я прав?
континуации, в принципе, позволяют реализовать конечный автомат в пределах одной функции. но это одно из применений. (в другой терминологии — «сопрограмма с самой собой»).

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

в частности, эти подходы никак не пересекаются если подумать о недетерминированных автоматах с нечётким состоянием, котрые на континуациях ну никак не вписываются.
А мне моя идея понравилась :) Что если рассматривать веб приложение как последовательность состояний? Тогда можно будет чётко указать возможные действия пользователя. Повысится секьюрность и простота разработки логики. Напишу-ка плагин для рельсов :)
ну в принципе не плохая идея :)

но как её применить в этих случаях:
1. юзер нажимает кнопку «back» несколько раз и перепостит форму, которая уже была засубмичена
2. а потом нажимает кнопку вперёд, пропуская одну из форм.
3. юзер делает несколько копий первой формы, и продвигается паралельно по нескольким путям.

в случае с континуациями, восстанавливающимися по параметрам запроса, (спрятанным в форму):
1. приложение возвращается в предыдущее состояние
2. приложение возвращается в следующее состояние, как оно зафиксирвоано в форме
3. приложение двигается параллельными путями, как если бы это были разные юзеры

в случае с континуациями, восстанавливающимися из сессии (всегда последнее для любого запроса):
1. приложение посылает пользователя нафик
2. приложение посылает пользователя нафик
3. приложение посылает пользователя нафик
:))
Посылать — жестоко. По поводу кнопок — изменить состояние приложения. Запрос же идёт в любом случае. По поводу параллельности выполнения одним пользователем — надо подумать плотнее. Могут быть проблемы. Простейший выход — своя сессия для каждой из нитей.
Отличная идея. Удачи вам.
Когда я занимался разработкой системного ПО на C++, я использовал фрэймворк который реализовывал подход автоматного программирования. Это было прикольно.
Спасибо. Попробую реализовать, когда буду принадлежать себе.
Талию где делать будем с кнопкой Back как поступим?
см. суб коммент выше,
и в статье «Inverting back the inversion of control» — с картинками.
какраз про кнопку back. и возможные извращения с ней.
Вопрос наверное глупый, но меня он волнует:

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

P.S. Статья немного сумбурная, но я получил информацию для размышления.
Сервер может быть не только апач. Например, это может быть сервер приложений (написанный на python, java или smalltalk) который как и апач никогда не завершается и только и занят тем что обрабатывать запросы пользователей. Этот самый сервер приложений может при желании проксироваться через апач. Именно так обычно работают J2EE-сервера, всякие Django и т.д. =)
На PHP (CGI, mod_*) свет клином не сошелся )
как-то так
Еще видимо как-то через fastCGI может быть реализованно.
да вот так, по большому счёту, если смотреть с позиции «сессия как состояние» — тут вообще ничо сложного нет — сериализовать вообще весь контекст приложения, и дело с концом.

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

вродебы единственный язык, котрый поддерживает продлжения полностью — это scheme.
но пример на scheme в статье ломал бы мозг два раза а не один :)

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

а цель статьи и была дать информацию к размышлению :)
вы хотите сказать, что папа-CLisp не поддерживает?
папа-lisp не поддерживал.
а common-lisp это брат scheme.
причом младший.

см. генеалогию

HTTP в-принципе stateless.

Будущее за новым протоколом, а не языком.

А так это всё извраты, т.е. хаки, хоть и красивые.
протокол — да.
но это вовсе не значит, что и приложение должно быть stateless.

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

хотя нет. таки мешает. я не могу ответить одним комментом на несколько сразу и приходится использовать ссылки типа «см. коммент выше» :)
НЛО прилетело и опубликовало эту надпись здесь
если протокол http заменится каким-либо stateful аналогом, то он вполне сможет обеспечить обратную совместимость.

хотя как-то слабо представляется WWW на отличных от REST-подобных принципов.
Континуации звучит как-то не по-русски. Чем вам не угодили продления?

Кстати, идея использования продлений родилась в Smalltalk фреймворке Seaside.
Сейчас она реализована в разных диалектах Лиспа: в PLT Scheme Web Server и Common Lisp фреймворках UnCommon Web и Weblocks.

По поводу REST и состояний: далеко не вск согласны, что RESTful = stateless (см. blog.dhananjaynene.com/2008/11/rest-fomenting-unrest-is-restfulness-a-semantics-game-why-does-rest-require-statelessness/)
настаиваю на продлении: продолжение звучит слишком неопределенно, как верно подмечено ниже. :)
статью из Википедии в данном случае можно считать лишь мнением ее автора, поскольку термин новый и консенсуса, как его называть, нет.
см., например: lingvo.yandex.ru/en/?text=continuation&from=os
ну в интернете используют в основном вариант «продолжения», сравните:
1 vs 2
потому что люди берут первый перевод, не задумываясь :)
тогда уж «возобновление»

а концепт сам по себе не очень определённый — это и действие, и результат действия, и результат как незадействованный результат действия :)
возобновление — это по-английски будет restart, а это уже чуток другая концепция из Common Lisp (функция-реакция на исключительную ситуацию).

«это и действие, и результат действия..» — как раз то, что написано в Лингво про продление
",,, и результат как незадействованный результат действия" — что вы имели в виду? В принципе, результат есть у любого действия, и его не обязательно задействовать
да. тут есть тонкость, которая затронутав комменте выше.
stateless — это протокол.
в принципе, выражение в статье «RESTful (statles)» не совсем предполагает синонимичность.

если не путаю, по принципам REST состояние приложения абстрагируется как «ресурс» (идентифицируемый URI, потомучто там всё ресурс.
в этом свете, «продолжения» — какраз и есть такой ресурс.

статью сейчас покурю. спасибо.

P.S.
слово «континуации» я скалькировал для придания ему большего оттенка терминологичности.
слово «продолжение» в контексте, не предполагающем понимания этого понятия, будет выглядеть немного неопределённо.
а Seaside смотреть пока не решаюсь, потомучто совершенно не видел SmallTalkа как такового.
Smalltalk — это более consistent Руби ;)
Посмотрите Common Lisp ;))
common lisp я смотрел в подаче Хювённен Сеппяннен.
но не шибко досконально.

и мне он показался несколько «грубым» :)
по сравнению со scheme.

сейчас я занимаюсь изучениам scheme, и наверно пока не буду отвлекаться на альтернативы. а может, наоборот, будет полезно…
это очень плохая подача, гораздо лучше — Practical Common Lisp (есть перевод на русский, если это имеет значение) или On Lisp.
ну, а в целом, как по мне, разобравшись с CL вы будете хорошо понимать Scheme, а вот наоборот не верно, поскольку тема макросов не будет раскрыта
вроде бы в scheme макросы продвинутее чем в лиспе?
Я бы сказал наоброт. Но это, конечно, вопрос философский (по которому, в основном, и разделяются пользователя CL и Scheme. Точнее, те, кто использует CL утверждают, что макросы — это одна из ключевых причин выбора именно его, а Schemer'ы придают им намного меньшее значение).

попробуйте и то, и то, и сами сможете сказать
Не в Seaside родилась идея. Впервые я увидел continuations в Cocoon
Огромное спасибо! в закладки и разбираться в контексте…
В контексте HTTP протокола вообще не вижу никакого позитива в такой реализации. Какую проблему Вам решить не удается изза stateless? Помоему все проблемы уже давно решены и довольно успешно, все к ним привыкли и они имхо совсем не dirty tricks
лёхкое противоречие в вашем комменте.

если «все проблемы уже решены» — это значит они есть.
неважно, насколько успешными решениями они закрыты.
и то, что все привыкли — никак не признак отсутствия проблем как таковых.

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

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

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

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

Соответственно простая форма ввода будет выглядеть на языке поддерживающем континуации примерно так:

do{
print_form();
data=read_form();
}while (check_data(data));
print_success();

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

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

А… так вы об этом.
Я почемуто подумал об уязвимости через переполнение буферов.

А так тут ровно теже приколы что и с храненем сессий, разница лишь в масштабах.

Furthermore, garbage collection can not be used to free this memory, because there are roots outside the system: users’ browsers, bookmarks, brains, and notebooks.

Поэтому всякие менеджеры континуаций с таймаутами и прочим.

И ещё есть подозрение, что размер будет зависить от структуры кода, а не только от количества параметров.
конечно, это не подозрение, надо храниить стек и все переменные на стеке, соответственно информацию о всех откртых ресурсах. А это ОЧЕНЬ накладно. Пример:

$data = sql.exec(«SELECT * from table»); //здесь селект миллиона строк
switch( get_user_action()){

case page_out: print_page($data);

}

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

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

P.S.
а на языках запредельно высокого уровня, транслятор вполне сможет вывести, что вообще весь этот кусок кода — сплошное наебалово, и выполнять его не нужно :))
нет, вы не совсем правы:
проблема в том, что при выходе из программы с последующей континуацией, транслятор не знает какие данные потребуются после континуации. В приведенном примере транслятор не знает будет ли дальше использоваться результат sql запроса или нет.
очевидно даже не глядя в код, что после возврата потребуются следующие или предыдущие 5 строчек.
такое обращение с данными вписывается в интерфейс итератора и реализуется курсором бд.
а почему вы не можете представить что-то другое на месте этих sql данных?

$data=read_from_file($f,100000); //read 100k from file
do_some_work_with_data($data);
ask_user()
do_some_work_with_data($data);

вот к примеру, разрыв в точке ask_user(), 100килобайт на ура
в целом — не вижу ничего плохого в том, что технология делает неэффективным написание говнокода.
то есть вы предлагаете использовать континуации без плюшек которые они предлагают? :) зачем тогда нужны континуации? :)
континуации нужны для сохранения состояния приложения.

а для хранения данных придуманы бызы данных и всякие кэши.
разве состояние приложения это не есть:
1) состояние стека
2) состояние перменных
3) открытые ресурсы и их состояние (на каком байте открыт файловый дескриптор, и тп)
ну вот как показывает опыт эрланга —
переманных и стэка вообще может не быть.
может не быть, но при этом и состояния как такового нет :)

подумайте как вы можете отделить одного пользователя от другого (одно состояние от другого) если у вас они не отличаются :)
Спасибо за инфу! Всегда считал что общепринятый подход писать полезный код в «контроллерах» запросов это извращение!

Есть правда одна проблема — в динамических языках далеко не все объекты поддаются сериализации… В python-е приходится писать обработчики set_state/ get_state для pickle. Но как быть с 3rd party классами? Недавно использовал mechanize и нужно было сохранить состояние, а pickle его не берет. Пришлось выкручиваться руками, а как бы было красиво, если просто сохранять состояние…
эта проблема связана со путаницей между состоянием приложения и состоянием объектов.
если состояние приложения полностью реализуется ограниченным (в пространстве имён) набором переменных — то сессия целиком и полностью решает все возможные проблемы.

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

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

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

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

Я про то, что технологию должен поддерживать инструментарий, чтобы можно было работать на высоком абстрактном уровне.
Ну я своим комментарием, хотел сказать, что инструменты уже есть.
а сайты на лиспе где видали?
за 5 минут в гугле нашел пару десятков.
ищущий да обрящет…
Стоило взять пример из Seaside для более наглядной демонстрации.
go
| user |
user := self call: AuthRegisterComponent new.
user username ~= ''
ifTrue: [ self inform: ('Good Job ', user username) ]
ifFalse: [ self inform: 'You did not register' ]

Пока выполнятся эти строки, произойдет 4 HTTP запроса.
А еще посмотрите на это в действии DabbleDB
в действии смотреть не особо интересно.
интересней, что у него унутре.
но за ссылку спасибо.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации