Showing posts with label webdev. Show all posts
Showing posts with label webdev. Show all posts

Saturday, February 09, 2008

Yaws — веб-сервер на Erlang

В самом начале обещал рассказать про веб-приложения на эрланге. Наверное, пора сворачивать ближе к теме.

В качестве веб-сервера для Erlang-приложений лучшим вариантом является написанный на эрланге же веб-сервер Yaws. Чем он хорош — он довольно сильно заточен под высо­копро­изво­ди­тельные приложения, и динамические страницы там удобно генерировать на эрланге.

Сначала насчет производительности:

Картинка известная, подробнее узнать, как она получена можно тут.  По горизонтали это количество параллельных запросов  к серверу (очень медленных клиентов), по вертикали — сколько кб/с при этом параллельно может отдавать сервер одному быстрому клиенту. Красненькое это yaws, синенькое и зелененькое это Apache, который после нескольких тысяч тихо умирает.

Конечно, Apache сравнивать с yaws не очень честно — все-таки апач продукт сложный и намного более многофункциональный, с кучей дополнительных модулей и настроек, и, в общем-то использовать его для отдачи статических страниц не очень принято. Однако ж картинка все-таки очень показательна, возможность держать много параллельных соединений важна в любом случае, да и с динамикой дела у yaws должны быть тоже хорошо (см. например Erlang vs PHP на Computer Language Shootout).

Пару слов об установке Yaws — с линуксом проблем, конечно, нет, на винду поставить тоже можно из-под Суgwin, но чтобы избежать лишней головной боли, обратите внимание, чтобы в пути к эрлангу и директории home не было пробелов (а последняя по умолчанию в "Documents And Settings" находится). Еще пара полезных замечаний про процесс установки есть тут.

 

Настраивается yaws с помощью конфиг-файла, там все довольно тривиально — дефолтный файл можно пока особенно не менять, разве что установить root директорию (параметр docroot).

Простейшее приложение с использованием yaws:

<head><title>Hello world using Yaws</title></head>
<body>
<erl>
out(A) ->
   case queryvar(A, "name") of
      {ok, Name} ->
        {html, "<div style=\"font-size: 12pt;\"> Hello, " ++ Name ++"</div>"};

      undefined ->
        {html, "<b> Name parameter required </b>"}
    end.
</erl>
</body>

 

Сохраняем его как hello.yaws в root директории.

hello-yaws

.yaws файл, как уже видно, это просто HTML шаблон. Каждый блок между тегами <erl> и </erl> компилируется в отдельный Erlang модуль. Каждый такой блок должен содержать функцию out/1, которой в качестве параметра передается структура, содержащая параметры запроса. Есть много вариантов как можно возвращать ответ, наиболее интересны два:

использованный выше

{html, HtmlString}

Где HtmlString — просто кусок HTML в виде строки, как в примере выше.

И чуть более удобный

{ehtml, Term}

Где Term — тот же HTML в виде терма Erlang, где тэги представляются кортежами или списками кортежей. Например, вот такой терм

{p, [],
    [
        {b, [], "Hello World"},
        {a, [{href, "http://www.example.com"}], 
           "link"}
    ]
}

преобразуется сервером в HTML-строку

<p>
  <b>Hello World</b>
  <a href="http://example.com">link</a>
</p>

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

Еще Yaws, кроме того что является просто веб-сервером, предоставляет немало дополнительных инструментов, таких как автоматическая поддержка сессий, cookie, механизмов удаленного вызова процедур на основе SOAP и JSON-RPC.

Для полноценного фреймворка — аналога Ruby on Rails и прочих, API Yaws, конечно, не дотягивает (для этого есть библиотека ErlyWeb), но для небольших приложений этого должно быть вполне достаточно.


Thursday, November 08, 2007

Угадайка

Как думаете, какой язык поддерживает сразу

  • First-class функции, лямбды и замыкания;
  • параметризованные типы;
  • хвостовые вызовы;
  • array comprehensions;
  • ООП с классами и интерфейсами;
  • ООП на основе прототипов;
  • мультиметоды;
  • coroutines (оператор yield);
  • структурные и номинальные подтипы;
  • перегрузку операторов;
  • Nullable/Non nullable аттрибуты для всех типов.

Ну и по мелочи: for-each, array slicing а-ля питон, регулярные выражения, открытые пространства имен и пр.

Однако ж это все ожидается в чудесном новом Javascript ECMAScript 4!

Еще  одна из самых интересных возможностей в четвертой версии — опциональная статическая проверка типов. Это должно упростить написание сложных систем (засчет строго описанных интерфейсов), и помочь [jit] компиляторам иногда генерировать более эффективный код. Опциональные статические типы, похоже, становятся модными: в Python 3000 тоже не так давно добавили что-то похожее.

Четвертая версия пока получается довольно пестрой — появилась куча новых механизмов и языковых конструкций (см. выше), а совместимость с предыдущей версией надо, по возможности, сохранить — поэтому синтаксис местами получился довольно странный: скажем, [int] это массив целых чисел, а [int, string] — это уже кортеж из целого и строки.

Еще из забавных вещей — явная поддержка структурных типов. В частности, с помощью специального оператора like можно задать переменной структурный тип (то есть ей можно присвоить только объект, обладающий набором заданных свойств):

var foo : like {x : int, y : int};

А переменная, объявленная с ключевым словом wrap автоматически дополняет хранимый в ней объект нужными свойствами:

var bar : wrap foo { x : int, y : int} = {x : 10, y : 20}.

Может и не революционная фича, конечно, но выглядит крайне интересно.

В ECMAScript 4 обещают также обязательную оптимизацию хвостовых вызовов. В Python 3000 их точно не будет, с руби ситуация туманна —что делает ES4 лучшим выбором в качестве платформы для компиляторов с функциональных языков. В общем-то уже сейчас есть компиляторы, как минимум, OCaml, SML и Haskell, генерирующие код на ECMASCript 3.

Собственно мощь и текущей-то версии js во многом недооценена. Кстати, только я не знал, что автор один из авторов первой версии Javascript — Гай Стил мл., а в качестве основных источников вдохновения при разработке Javascript 3 авторы называют языки Scheme и Self?

Новый Javascript явно претендует на что-то большее. Если он действительно будет "принят на вооружение" — определенно можно ожидать появления изрядного количества серверных приложений и фреймворков на js. Во всяком случае, язык получился явно не слабее питона и руби — хотя, конечно, вряд ли средства интеграции с кодом на C и C++ будут тут столь же развиты, ниша у языка все-таки другая.

Ссылки:


Saturday, September 08, 2007

Seaside: веб-фреймворк на основе continuations

[Довольно длинное введение]

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

Написание сложных (и не очень) веб-приложений обычно наталкивается на кучу проблем, и основная — это то, что протокол HTTP не подразумевает никакого состояния — и поэтому это состояние приходится за собой таскать в виде cookies, скрытых полей в формах и букета параметров методов GET/POST. Плюс к этому, линейные переходы между страницами — по сути, аналог оператора goto — приводят к тому что дизайн многих веб приложений представляет из себя мешанину из процедурного и как-бы-объектно-ориентированного кода, сумбурных обращений к базе данных, разбавленных HTML разметкой.

Проблемы эти стараются решить современные фреймворки для веб-разработки, прежде всего Django, CakePHP и Ruby on Rails, в которых авторы постарались максимально отделить представление от логики, упростить работу с базой данных засчет всяких ORM подсистем и вообще структурировать приложение (в той или иной степени) заставляя его следовать классическому, но подзабытому в 90-е паттерну Model-View-Controller. В Ruby on Rails, скажем, под моделью понимаются данные, хранящиеся в БД, view — это система шаблонов, на основе которых генерируются страницы и контроллер — это собственно бизнес-логика.

Однако же проблема таскать за собой "состояние" сессии остается, хотя и для ее решения фреймворки предлагают много всяких вспомогательных средств.

[Па-пам]

Старики помнят, что термин "объектно-ориентированный" был изобретен для того чтобы назвать так язык Smalltalk. В дискуссиях о том, насколько тот или иной язык ОО обычно гуру ссылаются именно на него, как на эталон тру ОО языка.

Более того, паттерн MVC у тех же стариков ассоциируется прежде всего с GUI библиотеками Smalltalk, именно там этот паттерн родился и получил широкое применение (потом эта вся идеология перекочевала в ОС NextStep, а из нее в Mac OS(X), если кто не в курсе).

Возвращаясь к веб-разработке, многие наверное читали эссе Пола Грэма Beating the Averages, как Пол с товарищами написали на лиспе систему для создания веб-магазинов и потом продали ее за много миллионов баксов Yahoo!. Там они, кроме всего прочего, использовали continuations как механизм передачи управления между страницами. Continuation'ы хранились на сервере в словаре, а ссылки на страницах содержали как параметр id того continuation, который надо выполнить для генерации страницы.

Если сложить вместе концепцию continuations, MVC в качестве основного паттерна для архитектуры всего приложения и smalltalk в качестве языка разработки — получим Seaside, фреймворк для разработки сложных веб-приложений, не думая о большинстве вышеописанных проблем.

[Немножко подробнее про continuations в вебе]

С логикой и control flow в вебе проблем несколько — во первых, вышеупомянутое состояние сессии: таскать его между страницами через параметры POST/GET довольно неудобно да и иногда просто нереально, а наличие у юзера кнопок "назад" и "открыть в новом окне" создает проблемы, если мы храним состояние в куках или сразу сохраняем в базе данных введенные в формы данные.

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

Например, представим себе такой пример: пользователь заполняет форму, нажимает ОК, но одно поле заполнено неверно, и мы хотим показать ему страничку с предупреждением и кнопкой ОК, и вернуться обратно к той (уже частично заполненной им) форме.

В стандартном случае мы передаем скрипту, выводящему страницу с предупреждением значения заполненных полей, а он потом передает их обратно. Как-то так:

/show_form.php 
-> validate_form.php?userName=John&phone=02
-> show_warning.php?userName=John&phone=02
-> show_form.php?userName=John&phone=02

В фреймворках, основанных на continuations метод showForm() просто вызывает validateForm(), которая вызывает showWarning(), и на время, когда юзеру надо показать отрендеренную страницу все состояние сохраняется в continuation. Потом, когда юзер жмет OK — все возобновляется с того места где приложение остановилось.

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

Последнее особенно хорошо иллюстрируется примером из дистрибутива Seaside: пять компонентов (счетчиков) на одной странице, состояние обо всех некоторым образом передается между страницами, но каждый счетчик ничего не знает о других — вся логика и представление сосредоточено внутри класса, отвечающего за компонент, а не размазана по скрипту сгенерить_страницу_с_пятью_счетчиками.php. Это именно благодаря тому, что состояние сохраняется и передается автоматически между вызовами. И кнопка back в браузере отлично работает без всяких усилий со стороны разработчика.

[Seaside]

Собственно, про сам Seaside добавить можно теперь немного — используется в точности подход, описанный выше.

Немаловажный момент — Seaside принципиально не использует никакой системы шаблонов, подобно Ruby on Rails и Django — XHTML код генерится с помощью набора специальных классов, благодаря чему генерацию XHTML можно разносить по методам, применять к ним инструменты для рефакторинга Smalltalk-овского кода (а среда тут предоставляет их очень богатый набор). Конечно, дизайнерам править XHTML будет немного сложнее, но, по-хорошему, им и не надо: XHTML призван отвечать за "семантику" страницы, а для представления ее существует CSS.

Вообще среда разработки в Smalltalk (точнее Squeak, основная но не единственная реализация Smalltalk, в которой работает Seaside)  заслуживает отдельного большого поста — настолько это инопланетное создание. Чего стоит только тот факт что там нету понятия исходных файлов — есть только один большой рантайм, все классы и методы правятся "на лету", не останавливая работы приложения. Система контроля версий тоже своя, и diff работающий не на уровне текста, а на уровне классов и методов. Поначалу больше всего расстраивает то, что в Squeak нельзя воспользоваться своим любимым редактором, но мало какой редактор предоставляет столько инструментов для рефакторинга и автоматической генерации кода, как System Browser в Squeak.

Кроме всего этого, к Squeak/Seaside прилагаются очень неплохие инструменты для отладки, тестирования и настройки производительности. В отладочном режиме вообще много приятностей — когда в приложении происходит какой-то эксепшен, можно нажать кнопку Debug и начать отлаживать с этого места в Squeak. Для десктопных средств разработки в этом ничего выдающегося нету, но для веб — это большой шаг вперед.

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

Лучше, конечно один раз увидеть: скринкаст здесь — рефакторинг приложения (не веб-) в squeak, не останавливая его работы; и тут — создание блога за 15 минут в Seaside. Заметьте, как товарищ ловко фиксит там баг на лету, опять же без остановки приложения.

[Кто-то же должен за это платить?]

Естественно, все это оборачивается несколько более высокими аппаратными требованиями. Seaside изначально ставит стоимость времени программиста много выше стоимости железок. Squeak кушает изрядно памяти и процессорного времени (хотя по скорости выполнения, говорят, как минимум не медленнее питона и руби). По стабильности рантайма проблем нету, если кого-то беспокоит что это все может быть несколько "сыровато" — виртуальная машина squeak разрабатывается уже лет 10 как, причем довольно серьезными и профессиональными дядьками, начиная с того же Алана Кея.

[Ну и..]

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

[Ссылки. Много ссылок]

  • Блог "On Smalltalk" много про squeak, smalltalk и seaside
  • Блог "HREF Considered Harmful" про про seaside и внутренности squeak
  • Подробно о continuations в вебе Статья "Seaside - a Multiple Control Flow Web Application Framework" [PDF]
  • Сравнение Rails Vs Seaside (+ в комментах интересная битва между любителями Rails и автором)
  • Другое интересное сравнение Rails и Seaside от опытного программиста на java Дэвида Поллака. Судя по всему, Дэвида все-таки не устроило ни то, ни другое, поэтому сейчас он активно разрабатывает фреймворк на базе Scala, это отдельная интересная тема :)
  • Сайт Seaside
  • Сайт Squeak
  • Бесплатный хостинг для некоммерческих Seaside приложений
  • Туториалы к Seaside: вот и вот, и еще несколько в гугле можно найти. К сожалению, кое-какие из них местами устарели.