Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Динамическая Опердень на Haskell                 Как за три шага превратить острый гемморой в хронический
Приближение I
Приближение IКлиент (Браузер)                Сервер приложений                СУБД   JavaScript                   HTTP/JSO...
Приближение I●   Результат: FAIL●   Разработчики не довели проект...    ●   Даже до середины●   Основные причины --- орган...
Приближение I●   QooxDoo    ●   Сложный дизайн    ●   Oчень verbose    ●   Очень много писать руками на JS    ●   Практиче...
Приближение I●   Mochiweb/Erlang    ●   Динамическая типизация        –   ОБЯЗАТЕЛЬНО требуются юнит-тесты             ●  ...
Приближение I●   Mochiweb/Erlang    ●   Автоматический маппинг HTTP на SQL (CRUD)        –   Оказался слишком сложен      ...
Приближение I●   FAIL    ●   Недостаточная организация        –   Недостаток времени на организацию    ●   Недостаток опыт...
Приближение II
Приближение II●   Другой разработчик●   Erlang/MochiWeb●   ExtJS вместо QooxDoo    ●   Чуть больше декларативности    ●   ...
Приближение II●   FAIL    ●   Основные причины        –   Недостаточная организация        –   Недостаток квалификации    ...
Приближение III      Если хочешь, что бы что-то было сделано хорошо --- сделай это сам
Приближение IIIКлиент (Браузер)            Сервер приложений           СУБД      ?            HTTP/?                      ...
Лирическое отступление: Дизайн         “Центр масс” системы         Клиент            Сервер   СУБД          Вариант I   К...
Лирическое отступление: Дизайн    Клиент        Сервер   СУБД   Вариант I●    Pros                               ●     Con...
Лирическое отступление: Дизайн    Клиент           Сервер    СУБД              Вариант II●    Pros                        ...
Лирическое отступление: ДизайнКлиент       Сервер                        СУБД         Вариант III    ●    Pros            ...
Приближение III        ?          Сервер приложений●   OCaml/Ocsigen/Eliom                 ●   Haskell/Happstack    ●   Ни...
Приближение III        ?             Сервер приложений●   OCaml/Ocsigen/Eliom                             ●   Haskell/Happ...
Приближение III        ?              Сервер приложений●   OCaml/Ocsigen/Eliom                              ●   Haskell/Ha...
Приближение III                   … And the winner is: Haskell/HappstackКлиент (Браузер)               Сервер приложений  ...
Приближение III                     ●   QooxDooКлиент (Браузер)                     ●   ExtJs                     ●   Оста...
Приближение IIIКлиент (Браузер)              Сервер приложений           СУБД                                 Haskell / JS...
Приближение III  Опердень: CRUD    UPDATE    генерируется   CREATE                   генерируется  READ             Businn...
Приближение III                       Сервер:Клиент: JS/OL          Happstack App                XHR    Widget            ...
Приближение III                                     Happstack App                                     (generic CRUD + BL) ...
Приближение III                                            Полная картина       Клиент                                    ...
Приближение III●   WIN    ●   Разработка завершена    ●   Деплоймент произведен●   Некоторые свойства    ●   Достаточно ун...
Приближение III●   Некоторые метрики    ●   Приблизительно сорок экранов/форм    ●   Свыше пятидесяти таблиц    ●   Порядк...
Приближение IIIА причем тут вообще Haskell?    Какая от него польза?
Haskell●   Сильная типизация    ●   Как правило, если скомпилировалось, то работает    ●   Легко и безопасно вносить измен...
Haskell●   Компилируется в нативный код    ●   Легко разворачивать на Production        –   Как правило, не требуется ниче...
Haskell●   Много готовых к использованию библиотек    ●   Больше, чем в OСaml или Erlang    ●   Например        –   Happst...
Приближение III●   Haskell    ●   Много готовых к использованию библиотек           ●   hslogger                 – Логгиро...
Haskell●   Много готовых к использованию библиотек    ●   Регулярные выражения        –   Различные бэкенды             ● ...
Haskell●   Много готовых к использованию библиотек    ●   STM (Software Transactional Memory)        –   Атомарный конкуре...
Haskell●   Много готовых к использованию библиотек    ●   MySQL    ●   PostgreSQL    ●   SQLite    ●   ODBC    ●   Riak   ...
Haskell●   Инфраструктура разработки    ●   Cabal        –   Централизованная установка пакетов (как CPAN и подобные)     ...
Haskell●   Инфраструктура разработки    ●   Hlint         –   Научит вас, как надо писать на Haskell         –   Находит д...
Haskell●   Инфраструктура разработки    ●   QuickCheck        –   Автоматическая генерация тестов    ●   Средства автомати...
Приближение III   Заключение
Haskell●   Удобный инструмент                                        ●   Академический язык для маргиналов    ●   Большое ...
Конец
Haskell●   Напишем маленький HTTP сервер    ●   Пусть слушает на порту 10000    ●   И отвечает HELLO WORLD         import ...
Haskell●   Добавим счетчик запросов      import Happstack.Server      import Control.Concurrent.STM      import Control.Co...
Haskell●   Демонизируем      import Happstack.Server      import   Control.Concurrent.STM      import   Control.Concurrent...
Haskell●   Добавим обработку сигналов    ●   Обнулим счетчик запросов по SIGUSR1    ●   Напишем что-нибудь в системный лог...
Haskell●   Проверяем        $ sudo hello start        $ tail /var/log/daemon.log        Apr 28 12:39:53 slim hello: starti...
Haskell●   Запишем что-нибудь в БД     ●   И постараемся остаться в рамках одного кадра презентации     ●   Допустим, у на...
Haskell●   Проверим    $sudo hello restart    $ curl http://localhost:10000    HELLO WORLD: 0$ curl http://localhost:10000...
Вот теперь всё. Спасибо за внимание
Operden1
Upcoming SlideShare
Loading in …5
×

Operden1

10,262 views

Published on

  • 46 слайд, добавим счётчик запросов: чтение и запись не синхронизированы, так и задумано?
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Operden1

  1. 1. Динамическая Опердень на Haskell Как за три шага превратить острый гемморой в хронический
  2. 2. Приближение I
  3. 3. Приближение IКлиент (Браузер) Сервер приложений СУБД JavaScript HTTP/JSON Erlang/MochiWeb SQL QooxDoo PostgreSQL Совершенно типичная, рядовая, унылая опердень
  4. 4. Приближение I● Результат: FAIL● Разработчики не довели проект... ● Даже до середины● Основные причины --- организационные ● И тем не менее
  5. 5. Приближение I● QooxDoo ● Сложный дизайн ● Oчень verbose ● Очень много писать руками на JS ● Практическое отсутствие декларативности ● Ручной маппинг данных ● Странные ограничения в виджетах ● Относительно слабая документация ● Довольно симпатично выглядит, впрочем
  6. 6. Приближение I● Mochiweb/Erlang ● Динамическая типизация – ОБЯЗАТЕЛЬНО требуются юнит-тесты ● Которые никто не пишет ● Полуживые средства Database Connectivity – Требовалась ручная доработка ● Генерация и парсинг JSON – Очень мало и полуживое – Потребовалась ручная доработка
  7. 7. Приближение I● Mochiweb/Erlang ● Автоматический маппинг HTTP на SQL (CRUD) – Оказался слишком сложен ● Достаточно бедный язык ● Динамическая типизация – При этом почти отсутствует метапрограммирование ● Недостаток опыта у разрабатывающих
  8. 8. Приближение I● FAIL ● Недостаточная организация – Недостаток времени на организацию ● Недостаток опыта – Овердизайн ● Инструменты увеличивают количество работы – А должны уменьшать
  9. 9. Приближение II
  10. 10. Приближение II● Другой разработчик● Erlang/MochiWeb● ExtJS вместо QooxDoo ● Чуть больше декларативности ● Шаг в сторону --- расстрел ● Мистические глюки
  11. 11. Приближение II● FAIL ● Основные причины – Недостаточная организация – Недостаток квалификации – Недостаток опыта
  12. 12. Приближение III Если хочешь, что бы что-то было сделано хорошо --- сделай это сам
  13. 13. Приближение IIIКлиент (Браузер) Сервер приложений СУБД ? HTTP/? ? SQL PostgreSQL
  14. 14. Лирическое отступление: Дизайн “Центр масс” системы Клиент Сервер СУБД Вариант I Клиент Сервер СУБД Вариант IIКлиент Сервер СУБД Вариант III
  15. 15. Лирическое отступление: Дизайн Клиент Сервер СУБД Вариант I● Pros ● Cons ● Быстро ● Трэш прототипировать ● Угар – Иногда ● Содомия
  16. 16. Лирическое отступление: Дизайн Клиент Сервер СУБД Вариант II● Pros ● Cons ● Миграция между СУБД ● Быстро, толькo если держать всю – Как секс у тинейжеров: чаще говорят, БД в памяти приложения чем делают – Страдает D в ACID ● Использование ORM ● Типичные языки для – Хорошо, если не знаете SQL манипуляции данными менее ● Возможность строгого удобны, чем SQL + расширения типизирования модели ● Все равно отчеты придется Если вы используете типизацию – делать на SQL
  17. 17. Лирическое отступление: ДизайнКлиент Сервер СУБД Вариант III ● Pros ● Cons ● Просто ● Дорогая смена СУБД ● Быстрая разработка – Но см. предыдущий ● “Горячие” апгрейды слайд – Кроме изменения схемы ● Отвратительная ● Поддерживать может типизация в БД любой DBA – Придется с этим жить – И даже немного дорабатывать
  18. 18. Приближение III ? Сервер приложений● OCaml/Ocsigen/Eliom ● Haskell/Happstack ● Низкий порог ● Выше качество вхождения сервера – Верно для OCaml (но ● API проще не для Ocsigen/Eliom) ● Отличные ● Слабые библиотеки библиотеки DB DB Connectivity Connectivity (HDBC) – Пришлось – Все работает дорабатывать
  19. 19. Приближение III ? Сервер приложений● OCaml/Ocsigen/Eliom ● Haskell/Happstack ● Легкие процессы (Lwt) ● Легкие процессы (ForkIO) – Ручной запуск блокирующих – Прозрачный запуск блокирующих вызовов в native threads вызовов (GHC 6) в native threads ● Например, SQL запросов ● Не будут блокировать сервер ● Либо блокировка всего сервера ● Без усилий с вашей стороны ● Признанные ошибки Ocsigen для – epoll/kqueue IO backend в GHC 7.x этого случая ● Не блокируют – Реализация на основе монад ● Как в Erlang ● Время удивляться ● C10K / C100K (?) ● Какие еще монады в Окамле?! – Естественно вписываются в язык ● End of easy-to-learn Ocaml ● Действительно просто – И это вы еще типов в Eliom не видели
  20. 20. Приближение III ? Сервер приложений● OCaml/Ocsigen/Eliom ● Haskell/Happstack ● Инфраструктура ● Инфраструктура – Стандартная библиотека бедна – Стандартная библиотека и неудобна (Prelude как минимум) хороша ● Почти всегда требуются дополнительные библиотеки (ExtLib – Немало сторонних библиотек --- как Boost в C++) ● См. apt-cache search haskell – Относительно мало сторонних ● См. cabal list библиотек – Системы сборки / пакетирования – Системы сборки / пакетирования ● Cabal ● Ocamlfind ● Cabal-dev ● Ocamlbuild ● Capri ● И другие – Последние две решают ● Package hell присутствует проблему package hell ● В целом, удобнее
  21. 21. Приближение III … And the winner is: Haskell/HappstackКлиент (Браузер) Сервер приложений СУБД ? HTTP/? Haskell / Happstack SQL PostgreSQL
  22. 22. Приближение III ● QooxDooКлиент (Браузер) ● ExtJs ● Остальные подобного уровня Такие же или много хуже ? ● OpenLazslo ● HTML5 (Canvas) / Flash ● Не DOM ● В основном декларативное ● Layout Engine ● Декларативный биндинг данных в XML на контролы при помощи Xpath – PostgreSQL умеет отдавать данные в XML
  23. 23. Приближение IIIКлиент (Браузер) Сервер приложений СУБД Haskell / JS/OpenLaszlo HTTP/XML SQL Happstack PostgreSQL
  24. 24. Приближение III Опердень: CRUD UPDATE генерируется CREATE генерируется READ Businness Logic генерируется (хранимые процедуры) DELETE (SOFT)
  25. 25. Приближение III Сервер:Клиент: JS/OL Happstack App XHR Widget XML XHR SQL Widget PostgreSQL XML Widget XHR XML
  26. 26. Приближение III Happstack App (generic CRUD + BL) HTTP GET/POST SQL /list/entity?col1=... SELECT XMLELEMENT(..)/query/entity?col=CND(CND2(..))&.. SELECT .. FROM .. WHERE CONDITIONS /create/entity?col1=... INSERT INTO … /update/entity?key1=...&col1=... UPDATE … WHERE … /delete/entity?key1=... DELETE FROM … WHERE ... /fn/function?$0=x1...$n=xn SELECT function(x1, … , xn)
  27. 27. Приближение III Полная картина Клиент Happstack/App HTTP HTTP (XHR) Node 1 SQL JS/OL NGINX PostgreSQL XML XML Happstack/App XML mod_proxy Node N ●Данные Раздача статики ●Generic CRUD● ●Вызов бизнес-логики ●View●Балансирование нагрузки ●Хранимые процедуры ●Отчеты (XML → Latex → PDF)●Failover ●Триггеры ●Аутентификация / Авторизация●HTTPS ●Правила ●RBAC ●Констрейнты
  28. 28. Приближение III● WIN ● Разработка завершена ● Деплоймент произведен● Некоторые свойства ● Достаточно универсальный сервер на Happstack – Отсутствует специфичный для приложения код – Можно использовать в другом подобном проекте ● Возможно, даже без перекомпиляции – Можно дорабатывать, не трогая часть на Haskell вообще (только PG и JS) ● Аутентификация / Авторизация / RBAC – Сессии пользователей (кэширование привилегий) – Двухуровневый механизм пермиссий (permissions и metapermissions) – Проверка пермиссий server-side и client-side – Сокрытие элементов UI, к которым нет доступа ● Generic CRUD ● Трансляция HTTP запросов в SQL по определенным правилам – В том числе и для хранимых процедур ● Генерация отчетов: XML → Latex → PDF
  29. 29. Приближение III● Некоторые метрики ● Приблизительно сорок экранов/форм ● Свыше пятидесяти таблиц ● Порядка семидесяти VIEW ● Около сорока хранимых процедур ● 116 различных веб-методов (CRUD + BL + Отчеты + Auth ) – Судя по количеству пермиссий
  30. 30. Приближение IIIА причем тут вообще Haskell? Какая от него польза?
  31. 31. Haskell● Сильная типизация ● Как правило, если скомпилировалось, то работает ● Легко и безопасно вносить изменения – Не собирается, пока некорректно (как правило)● Компилируется в нативный код ● Работает точно быстрее Erlang, Python, Ruby, Javascript, Lua ... – Это не так важно, но довольно приятно
  32. 32. Haskell● Компилируется в нативный код ● Легко разворачивать на Production – Как правило, не требуется ничего дополнительно устанавливать
  33. 33. Haskell● Много готовых к использованию библиотек ● Больше, чем в OСaml или Erlang ● Например – Happstack.Server ● Организация HTTP сервера ● Роутинг и обработка HTTP запросов – HDBC ● Доступ к БД ● Существует множество альтернатив, включая решения с сильной типизацией, генерацией схем из ADT, генерацией запросов, большим выбором бэкенда для хранения данных (аналогов ORM), etc, etc – hdaemonize ● Стандартный демон, понимающий daemon start|stop|restart в несколько строчек кода
  34. 34. Приближение III● Haskell ● Много готовых к использованию библиотек ● hslogger – Логгирование с обширными настройками ● ConfigFile – Чтение конфигов ● Parsec – Разбор DSL для не-KV HTTP-запросов: col1 = OR(EQ(“BAR”), LIKE(“%FOO%”)) col2 = AND(GREATER(1), LESS(10)) ● В неcколько строчек кода
  35. 35. Haskell● Много готовых к использованию библиотек ● Регулярные выражения – Различные бэкенды ● POSIX, TDFA, PCRE ... – Наличие произвольных операторов в языке делает их практически встроенными в язык, как в Perl: ● someString =~ “FOO (BAR)” :: Bool ● someString =~ “FOO (BAR) ALICE (BOB)” :: [[String]] – Работают с UTF8 ● someString =~ “Превед (медвед)” :: [[String]]
  36. 36. Haskell● Много готовых к использованию библиотек ● STM (Software Transactional Memory) – Атомарный конкурентный доступ к данным в памяти – Для хранения сессионных данных ● Сеreal – Сериализация структур данных – Для сохранения служебной информации в БД – Один из десятков вариантов
  37. 37. Haskell● Много готовых к использованию библиотек ● MySQL ● PostgreSQL ● SQLite ● ODBC ● Riak ● Redis ● MongoDB ● Memcached ● MACID ● ...
  38. 38. Haskell● Инфраструктура разработки ● Cabal – Централизованная установка пакетов (как CPAN и подобные) – Сборка проекта – Трекинг зависимостей – Запуск тестов – Сборка дистрибутивов ● Cabal-dev – Тот же cabal, но без боли ● Позволяет устанавливать пакеты в локальную песочницу для проекта ● Не трогает остальную систему ● Ликвидирует Package Hell в среде разработки – А в Production его и так нет
  39. 39. Haskell● Инфраструктура разработки ● Hlint – Научит вас, как надо писать на Haskell – Находит дублирующий код и предлагает варианты исправления – Способен заменить не слишком въедливое Code Review ● Каким оно чаще всего и бывает (нехватка времени, лень, усталость, замыленность, нежелание брать ответственность за чужой код на себя) ● В Haskell практически отсутствует тип ошибок, которые может найти Code Review и не может найти компилятор – Использование неинициализированных данных, etc
  40. 40. Haskell● Инфраструктура разработки ● QuickCheck – Автоматическая генерация тестов ● Средства автоматического документирования – Haddock ● Просто запустите cabal haddock
  41. 41. Приближение III Заключение
  42. 42. Haskell● Удобный инструмент ● Академический язык для маргиналов ● Большое количество библиотек ● Не поддерживается в вашем IDE ● Удобный FFI – Простите, не поддерживается в чем? ● Хорошая инфраструктура разработки ● Ленивость ● Выразительный язык – Так было надо – Пишем меньше – Иногда, наоборот, полезна – Получаем больше – Когда она создаст реальные проблемы, я ● Сильная статическая типизация обязательно расскажу (пока просто нет такого опыта) – Безжалостно массово правим код, не боясь что-то сломать и не заметить ● Монады ● Конкурентность – А что “монады” ? – epoll/kqueue IO – А вы уверены, что точно знаете, что такое – STM “объект” и “класс” например? ● Поддержка SMP ● Но продолжаете ими пользоваться ● Либо ваше имя, вероятно, Luca Cardelli – Считай факториал в два раза быстрее на двух ядрах вместо одного, просто добавив вызов ● Сложная система типов функции par Зато многое позволяет – ● Поддержка UTF-8 ● Ограниченный вывод типов ● Метапрограммирование Местами заставляет расставлять аннотации – ● Хороший REPL ● И это правильно
  43. 43. Конец
  44. 44. Haskell● Напишем маленький HTTP сервер ● Пусть слушает на порту 10000 ● И отвечает HELLO WORLD import Happstack.Server main = do simpleHTTP nullConf { port = 10000 } $ ok "HELLO WORLD"
  45. 45. Haskell● Добавим счетчик запросов import Happstack.Server import Control.Concurrent.STM import Control.Concurrent.STM.TVar import Control.Monad.Reader main = do counter <- newTVarIO 0 simpleHTTP nullConf { port = 10000 } $ do cnt <- readCounter counter writeCounter counter (cnt+1) ok $ "HELLO WORLD: " ++ show cnt where readCounter c = liftIO . atomically $ readTVar c writeCounter c v = liftIO . atomically $ writeTVar c v
  46. 46. Haskell● Демонизируем import Happstack.Server import Control.Concurrent.STM import Control.Concurrent.STM.TVar import Control.Monad.Reader import System.Posix.Daemonize main = do counter <- newTVarIO 0 let ourHttpDaemon () = do simpleHTTP nullConf { port = 10000 } $ do cnt <- readCounter counter writeCounter counter (cnt+1) ok $ "HELLO WORLD: " ++ show cnt serviced simpleDaemon { program = ourHttpDaemon } where readCounter c = liftIO . atomically $ readTVar c writeCounter c v = liftIO . atomically $ writeTVar c v
  47. 47. Haskell● Добавим обработку сигналов ● Обнулим счетчик запросов по SIGUSR1 ● Напишем что-нибудь в системный лог import Happstack.Server import Control.Concurrent.STM import Control.Concurrent.STM.TVar import Control.Monad.Reader import System.Posix.Daemonize import System.Posix.Signals import System.Posix.Syslog main = do counter <- newTVarIO 0 let ourHttpDaemon () = do simpleHTTP nullConf { port = 10000 } $ do cnt <- readCounter counter writeCounter counter (cnt+1) ok $ "HELLO WORLD: " ++ show cnt let onUSR1 = writeCounter counter 0 >> syslog Notice "Counter is set to 0" :: IO () installHandler sigUSR1 (Catch onUSR1) (Just fullSignalSet) serviced simpleDaemon { program = ourHttpDaemon } where readCounter c = liftIO . atomically $ readTVar c writeCounter c v = liftIO . atomically $ writeTVar c v
  48. 48. Haskell● Проверяем $ sudo hello start $ tail /var/log/daemon.log Apr 28 12:39:53 slim hello: starting $ ls /var/run/hello.pid /var/run/hello.pid $ curl http://localhost:10000 HELLO WORLD: 0$ curl http://localhost:10000 HELLO WORLD: 1$ curl http://localhost:10000 HELLO WORLD: 2$ curl http://localhost:10000 HELLO WORLD: 3$ curl http://localhost:10000 HELLO WORLD: 4$ curl http://localhost:10000 HELLO WORLD: 5$ curl http://localhost:10000 HELLO WORLD: 6$ curl http://localhost:10000 $ sudo kill -s USR1 `cat /var/run/hello.pid` $ tail /var/log/daemon.log Apr 28 12:44:11 slim hello: Counter is set to 0 $ curl http://localhost:10000 HELLO WORLD: 0
  49. 49. Haskell● Запишем что-нибудь в БД ● И постараемся остаться в рамках одного кадра презентации ● Допустим, у нас есть база test и таблица counter (int, timestamp) import Happstack.Server import Control.Concurrent.STM import Control.Concurrent.STM.TVar import Control.Monad.Reader import System.Posix.Daemonize import System.Posix.Signals import System.Posix.Syslog import Database.HDBC import Database.HDBC.PostgreSQL main = do counter <- newTVarIO 0 let ourHttpDaemon () = do simpleHTTP nullConf { port = 10000 } $ do cnt <- readCounter counter writeCounter counter (cnt+1) liftIO $ doInsert cnt ok $ "HELLO WORLD: " ++ show cnt let onUSR1 = writeCounter counter 0 >> syslog Notice "Counter is set to 0" :: IO () installHandler sigUSR1 (Catch onUSR1) (Just fullSignalSet) serviced simpleDaemon { program = ourHttpDaemon } where readCounter c = liftIO . atomically $ readTVar c writeCounter c v = liftIO . atomically $ writeTVar c v insert c conn = quickQuery conn "INSERT INTO counter VALUES(?)" [toSql (c::Int)] doInsert cnt = withPostgreSQL "dbname=test user=dmz" (c -> withTransaction c (insert cnt))
  50. 50. Haskell● Проверим $sudo hello restart $ curl http://localhost:10000 HELLO WORLD: 0$ curl http://localhost:10000 HELLO WORLD: 1$ curl http://localhost:10000 HELLO WORLD: 2$ curl http://localhost:10000 HELLO WORLD: 3$ $ cat | psql test select * from counter; k | ts ---+---------------------------- 0 | 2011-04-28 14:15:58.294183 1 | 2011-04-28 14:15:59.252331 2 | 2011-04-28 14:15:59.843991 3 | 2011-04-28 14:16:00.323366 (4 rows)
  51. 51. Вот теперь всё. Спасибо за внимание

×