Previous Entry Add to Memories Tell a Friend Next Entry
#rocket web-science
Side Effects
[info]mr_aleph
Собрались как-то три компиляторщика ([info]esil0x, [info]kashnikov и ваш покорный слуга [info]mr_aleph) и под коньячок решили обсудить довольно странную (для компиляторщиков) проблему: красивый способ реализации веб-интерфейсов. Обсуждали достаточно долго и результативно (дело почти дошло до размахивания стульями и битья посуды о головы оппонентов). Обсуждавшаяся же задача мне показалась достаточно интересной и я решил поделится ей =)

Началось всё с простых примеров. Предположим есть контрол IncLink: это обычная ссылка, текстом которой является число и при нажатии на эту ссылку число увеличивается. При этом состояние страницы immutable (т.е. если открыть эту ссылку в новой вкладке, а потом обновить текущую, то в текущей останется N, а в новой уже будет N+1).

Усложняем: две такие ссылки на странице, каждая работает независимо.

Усложняем ещё больше: вводим составные контроллы. Заводим контрол XIncLink, который ведёт себя почти как IncLink, за исключением того что если текст ссылки делится на 5, он "выбрасывает" некоторое событие, на которое можно подписываться. Теперь "собираем" два контрола с участием XIncLink и скажем простого советского CountingLabel: K1, который каждые пыть кликов по XIncLink увеличивает число в CountingLabel на единицу, и K2, который каждые пять кликов уменьшает число в CountingLabel на единицу. Требования к неизменяемости состояния страницы сохраняется.

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

Я ночью сделал кое какие наброски на Lua, но пока оппоненты (да и я сам) не очень довольны результатом, поскольку всё сделано через протяжку глобального состояния через рендеринг всех контролов, а хочется чтобы каждый контрол видел только локальное состояние. С++-адепт [info]esil0x предложил решение (скажу сразу, оно мне не очень нравится), в котором перед рендерингом всем контролам выставляется состояние (в некоторое поле state), потом делается рендеринг, а потом состояние счищается. [info]kashnikov решил выступить в нашем споре вооружившись Haskell'ом, но пока не предъявил никакого рабочего варианта =).

Any ideas, languages, frameworks are welcome!

// распространение ссылок на эту запись приветствуется

(Leave a comment)
JavaScript + Prototype вам в помощь. Каждые пять кликов запускается ивент, который ловит соответствующий соunting label. Задача вполне решается в рамках Prototype-расширения DOM-модели.


а immutable-свойство страницы ты как предлагаешь гарантировать, hijaxом? =)

понятно что гибридная модель js+serverside должна сильно облегчить жизнь. но интересно, как всё таки задизайнить server side в отрыве от JS...

Edited at 2009-03-14 11:44 am (UTC)


Похоже на то что я говорил. Сейчас турбинаду расчехлим. :-)


Правильный ответ: "Вы такого не должны хотеть". А менеджер проекта даст кодерам по шее и заставит писать код вручную на ПХП, вместо фреймворков :)
Это почти не шутка, я от осмысления и изготовления похожих вещей(правда не для веба) сознательно отказываюсь, потому что иначе возникает тупик на стадии "а зачем мы это все делали". Клиентам нужна работающая система, что у нее внутри - мегафреймворк или 100 раз copy-paste один и тот же код - им фиолетово. Обобщение задач до фреймворка или встроенного DSL _до_ реализации функционала задачи приводит к тому, что мы к дедлайну имеем "универсальный решатель любых задач", но который еще нужно программировать под конкретную задачу, причем программировать сложнее, чем если бы мы это написали на обычном языке.
Обратная ситуация - когда проект прошел пару итераций, уже работает и по опыту эксплуатации и разработки видно, что можно обобщить - получается гораздо лучше - тогда можно и DSL делать, и общий код в фреймворки выносить. Если есть другие похожие проекты - вообще отлично, можно повторно код использовать.


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

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


Да вот только побыстрому что-то никто особо не хочет :-) Вспомни, что кое-кто сказал про Java :-D


По поводу фреймворков:

Как говорит Роберт Гласс (Факты и заблуждения профессионального программирования), повторно используемые компоненты, которые обладают достаточным уровнем общности для разных задач примерно в 3 раза дороже, чем узкоспециализированное решение конкретной задачи, аналогичное по функциональности.


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

Есть плохие framework, с недостатками, которые описали вы, а есть нормальные сделанные.

Примеры хороших, проверенных временем и множеством проектов.

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

Еще примеры хороших frmaework: spring, hibernate, onPHP, zend framework, django.

===============================================

По-поводу с++ для веб приложений. Ну извините, это бывает действительно нужно крайне редко. Причин две:

1. Очень высокие наргрузки.
2. Очень много серверов(здесь скажем скоратив кол-во серверов с 100 до 10 можно получить много профита как в стоимости, так и в сложности поддержки).
3. Специфичное самописное нечто(реализация своего стораджа, например).

1 и 2 причины объективные. 3, очень часто совершенно не имеет под собой никаких оснований, кроме непреодолимой тяги к велосипеду. Хотя есть и иные примеры.

Мудрые люди обычно пишут отдельные сервера или модули(к nginx, например) на чем-то мегабыстром типа с/с++ и снимают таким образом 80% нагрузки, а остальное на скриптовых языках, где программирование много проще и дешевле.

Одельно идет java, если она используется, ничего более и не надо, скорее всего.


Ч0рт, не сразу въехал в постановку задачи, так что мой предыдущий пост следует считать только защитой подхода использоваия FW вообще. Остальное можно пропустить :-)


Соглашусь с коллегой, который утверждает, что "вы этого не должны хотеть". И вот мои аргументы.

Дело в том, что построение классического web-интерфейса (без AJAX, без тонны JavaScript) в разы дешевле, чем разработка классического оконного интерфейса a la MFC/Swing/WinForms... У таких интерфейсов есть как сильные, так и слабые стороны.

Сильные состоят в том, что легко делать навигацию, шаблоны страниц, тогда как в классическом подходе -- это очень дорого.

Слабые состоят в том, что presentation-layer фактически не имеет состояния. И тут начинают сливать всякие попытки сделать tiling и заставить куски страницы жить собственной жизнью, причём жизнью немного пересекающейся с жизнью других tile'ов. Чтобы "исправить" этот недостаток одни люди запинывают кучи JavaScript, другие придумывают Flex и.т.д.

В результате стоимость разработки такого интерфейса начинает временами значительно превосходить стоимость классических интерфейсов. Например, все в курсе, как крут GMail. Но если сравнить стоимость разработки интерфейса GMail и стоимость разработки UI любого почтовика, то я уверен на 100%, что GMail на порядок дороже.

К чему это приводит? Это приводит к необходимому следствию, что AJAX и JavaScript, Flex и тому подобная хрень должна использоваться минимально и только там, где это даёт реальный выйгрыш. А мест, где такой выйгрыш достигается -- ну не так уж и много.

Теперь по твоему примеру. Зачем высасывать из пальца какие-то фишки, которые легко сделать в обычном интерфейсе, но сложно сделать на web? Их просто неразумно портировать на web. И самое главное, какое value появится от того, что ты сможешь это реализовать?


Кстати, формы обрабатывать на web тоже намного труднее из-за того, что состояние не сохраняется.


В исходной постановке задачи как раз говорилось про то, что хочется иметь plain-HTML интерфейс, без JavaScript/AJAX.

А пример далеко не высосан из пальца. Банальный пример: таблица, позволяющая производить сортировку по разным колонкам. Сделать такую таблицу "влоб" не составляет труда. А если известно, что таких таблиц будет много, и они будут расположены в разных местах разных страниц? Как менять сортировку в таблице при том, что эта таблица расположена на странице, которая вообще говоря живёт своей жизнью, т. е. у её элементов есть какие-то другие состояния? Получается, что каждый раз приходится переписывать один и тот же код несколько раз.


Типичная проблема портирования классического представления на web.

Думаю, что самым элегантным является нетехническое решение проблемы (далее следуют варианты), но есть и технические:

1) Изучить ситуации, когда пользователям требуется менять сортировку. И по максимуму выдавать уже отсортированное в правильном порядке. Либо автоматически представить результаты какого-то анализа, который проводится человеком, который химичит там что-то с сортировками
2) Предложить ему что-нибудь наподобие Flash-компонента (а можно даже апплет забубуенить :). И у них будет состояние, как положено, т.к. эти бинарники -- не что иное, как классический интерфейс внутри web.
3) Предложить пользователю отчёт в формате Excel/OpenOffice Calc :)
4) Если таблицы маленькие и полностью влазят в экран -- можно сделать сортировку на стороне браузера (гимор, но работать будет).


Есть еще такой нюанс что у "любого почтовика" (TM) нет таких проблем со спамерами как у гугла. А разработка сортира типа "очко" из досок - на десятки порядков дешевле чем разработка санузла для МКС. Но особенности среды накладывают требования на конструкцию.


>Есть еще такой нюанс что у "любого почтовика" (TM) нет таких проблем со спамерами как у гугла.

Закусывать надо © При чём тут спам? Это как-то связано с UI? Если вы ходите на GMail по IMAP4, то у вас уже резко появляется много спама? Или что вы хотели сказать?

Борьба со спамом -- это исключительно внутренняя серверная функциональность, которая может быть как хороша, так и плоха в разных почтовых службах. Под почтовиком я подразумевал конечно же Outlook, Thunderbird, ... Ну если вы понимаете под этим словом такие сервисы как НГС, то ради бога, но НГС -- это на несколько порядков более простой в реализации интерфейс, чем у GMail. Работа со спамом для пользователя ничем не лучше и не хуже. Просто у GMail хороший фильтр :)


Для того, чтобы не зависеть о состояния был придуман REST. Но в целом да, некоторые вещи невозможно реализовать как client-server, без специального толстого клиентского слоя.


я долгим путём пришёл к схеме:

browser(JS) -----http(urt-text)---> server(nginx ---fcgi---> c-program)
browser(JS) <----http(JS-text)----- server(nginx <--fcgi---- c-program)

и Боже сохрани от фрэймворков, "движков", "ЦМСок"

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

P.S.
на днях страдал, отчего же до сих пор не сделали нормальный язык описания ГУёв, фрэймворк - это недоязык, Турбовижын придумали, а следущий шаг не сделали! В итоге у нас я зыки описания языков есть, а языка описания морд - нету. Генераторы парсеров есть, а генераторов такой рутинной рутины как морда - нету. И это при том, что морда это тот же парсер, тока он парсит язык нажатий мышкой. А что если попытаться засунуть описание морды в привычный БНФ?


Write in C? Ага-ага.


Языков описания "гуёв" дофига. HTML, XUL,.... А вот языков описания хотелок, компилируемых в готовый код действительно нет. И не жаль :)


Хм я не уверен что правильно оценил всю сложность задачи...

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

То вся задача делится на две части :

Быстрое хранилище экземпляров контролов, которые выживают во время сессии. Хранилище на какихнить lockfree коллекциях.

И сосбственно cgi параметры перехода конечного автомата состояний для конкретного контрола, или группы вида например - href=?trasfer=control_id:instance_id:event_id.
Через POST/GET передаем только переходы но не текущие состояния других контролов.

Состояние храним или в сессионном хранилище на сервере, или в куках.

При переходе обрабатываем эвенты сначала. Потом рендерим текущие состояния контролов. Все.


Чего-то я в постановку задачи не въезжаю совершенно.


С какого места непонятно? =)


Сильно в постановку задачи не вчитвался. После первого прочтения ничего не понял, а на второе меня на хватило. Но больно мне твои примеры напомнили вот это:
http://www.seaside.st/about/examples?_s=PkkfaqmiEEA8bsT-&_k=7C6ti6Z1&_n&13
(а может и нет, не помню, где-то я уде вилео counter'ы.. может это был какой-то фраймворк на haskell или o'caml? я помню там точно были continuation'ы и closure'ы)

Еще вот сюда посмотри:
http://wiki.liftweb.net/index.php?title=Main_Page#Advanced_Framework


ага, ага, мы когда с утра проспались сразу побежали SeaSide смотреть...


(Leave a comment)