Блог разработчиков

Catalyst – Perl веб-фреймворк в лучших традициях MVC

Дмитрий Жарий
Опубликовано 1.10.2008 в Инструменты, Разработка, Статьи

Catalyst Perl web frameworkКогда я подыскивал себе MVC веб-фреймворк для небольшого внутрикорпоративного проекта, у меня абсолютно не было опыта работы с паттерном MVC. Я знал лишь то, что данные, их представление и логику работы обязательно нужно разделять. Страшный опыт смешивания этих ингредиентов с получением серо-буро-малинового зелья из перлового кода, HTML и SQL у меня был. Тогда я хотел быстренько найти что-то похожее на Rails, потому что читал про него, но чтобы было на Perl или PHP и чтобы было все просто и красиво. Тогда я собственно и не знал чего толком я хочу, именно поэтому я остановил свой выбор на CakePHP: просто, красиво, была русскоязычная документация и на Руби на Рельсах похоже. Поначалу все было очень хорошо: быстро понял, что к чему, быстро разобрался, куда там код писать… но, потом хлебнул бочку дёгтя из ложки меда.

Я не хочу сейчас писать о том, куда же все-таки девается оперативная память при запросе к БД, почему реализация ActiveRecord в CakePHP настолько неуклюжа, по сравнению с Ruby-аналогом, почему мне легче написать тег элемента формы в ручную, чем использовать HtmlHelper и многое другое.
Простота != гибкость.

Должен признать, что при всех своих недостатках, CakePHP дал мне понять очень важную вещь, а именно – что же я хочу получить от MVC веб-фреймворка. Я не хочу сказать, что CakePHP – это плохой и абсолютно непригодный для работы фреймворк. Нет. Он очень прост и понятен – и это его огромный плюс, но вместе с этим его возможности ограничены. Простые вещи делаются на CakePHP очень просто, но сложные вещи требуют затратить немалые усилия и по-прежнему остаются очень сложными.
Простота != гибкость.

Простота CakePHP заключается в том, что все, что вам нужно, находится в одном фреймворке. Библиотечный код для упрощения работы с БД, роутеры для работы с URL, средства для обработки веб-форм и помощники для генерации HTML-элементов стандартны для фреймворка. С другой стороны, вы не можете заменить какой либо элемент фреймворка на тот, что более удобен вам, либо использовать элемент отдельно от фреймворка (модели, например). Все уже сделано за вас. Хотите писать на CakePHP – живите по нашим правилам.

Я глубоко уверен в том, что в фреймворке не должно быть навязанного библиотечного кода, который невозможно, либо очень сложно заменить. Сам MVC фреймворк должен быть клеем между Моделями, Контроллерами и Представлениями. Фреймворк должен предоставлять свободу прикручивать и использовать те компоненты системы, которые наилучшим образом подходят для конкретного проекта. И если фреймворк не будет навязывать свой библиотечный код, то эта задача вполне выполнима.

Catalyst – это элегантный веб-фреймворк

Я не знаю, почему Catalyst называют элегантным веб-фреймворком, но, очень большая доля правды в этом есть. Я бы банально назвал его гибким, мощным и удобным фреймворком. Но, фреймворков с такими эпитетами очень много, а вот элегантный пока только Catalyst. ;) В чем же его элегантность гибкость и удобство? Ну, во-первых Catalyst делает только то, что должен делать веб-фреймворк – быть клеем между какими-то Моделями, какими-то Контроллерами и какими-то Представлениями.

Какие-то Модели

Модели служат для отделения логики работы с базой данных от прочего кода в веб приложении. Стоп… Кто сказал, что Модель должна работать только с БД?! Нет… модель служит для того, чтобы предоставлять данные из какого угодно источника. Именно так, вроде бы сказано в определении роли Модели в MVC. Источником данных для Модели может быть все что угодно, начиная плоскими файлами и xml-документами и заканчивая базой данных, веб-сервисами и IM-протоколами.

Модели в Catalyst не содержат огромных кусков библиотечного кода – они предназначены для адаптации существующих Perl-модулей для работы с Catalyst. Коме того, модели могут использоваться отдельно от фреймворка, это очень важный момент, если, к примеру, вы пишите отдельный от фреймворка модуль для импорта/экспорта информации, и хотите чтобы он использовал все те полезные функции, предоставляемые Моделью.

Особого внимания заслуживает вопрос работы с базой данных. Конечно же, вы всегда можете использовать чистый SQL для получения данных из БД. Но, на самом деле намного удобнее использовать ORM’ы – специальные модули, которые помогут вам упростить работу с БД путем замены ваших запросов на чистом SQL на работу с классами, которые возьмут на себя всю черную работу по формированию SQL-запросов и избавят вас от необходимости смотреть на листочек с дизайном вашей БД, каждый раз, когда вы создаете новый запрос, использующий больше чем одну таблицу. Использование ORM сделает ваш код для взаимодействия с БД чище и понятней как вам, так и вашим коллегам. Кроме того, ORM’ы делают ваш код переносимым между разными СУБД, и побочным эффектом использования этой технологии будет избавление от опасности SQL-инъекций. Уж поверьте, качественные ORM’ы следят за правильным формированием генерируемых ими SQL-запросов. Самым популярным ORM для Perl и Catalyst является DBIx::Class. Для него есть хороший мануал и многие другие модули поддерживают DBIx::Class (DBIC), работая с ним, как с родным. Кроме того, в официальных мануалах к Catalyst и других источниках информации вы найдете много примеров с использованием именно DBIC. Но, ваш выбор не ограничивается одним лишь DBIC. На CPAN можно найти еще парочку качественных ORM’ов. Лично я сейчас использую Rose::DB::Object из-за его гибкости и легкости в настройке. Так что, как работать с источником данных можно выбрать, и выбор этот зависит только от вас. Прикрутить Модель к Catalyst можно какую угодно. Вот почему этот блок текста я назвал «Какие-то Модели».

Контроллеры

Вы, наверное, не поверите, но контроллеры также можно прикручивать и откручивать. Сейчас можно упомянуть о том, что Catalyst – это полностью объектно-ориентированный веб-фреймворк. Все базовые классы Моделей, Контроллеров и Представлений наследуется от базового класса Компонент. Это дает вам возможность из Контроллера запросить Модель и настроить Представление. Ваши же Контроллеры наследуются от класса Catalyst::Controller, который реализует несколько базовых функций. Хотите больше? Поменяйте базовый класс! Вот, например, Catalyst::Controller::CRUD реализует код для основных функций чтения/записи в БД. А вот, к примеру, Catalyst::Controller::View делегирует запрос пользователя непосредственно в Представление. Таким образом, всю бизнес-логику можно реализовать в Представлении. Но, это уже, немного, извращение. Хотя, вполне реальное :)

Представления

Я думаю, что уже даже не стоит говорить о том, что представление будет таким, какое вы захотите прикрутить. Чаще всего, функциональность представлений реализуют шаблонизаторы. Их много. Выбирайте на любой вкус и цвет. Самый популярный, мощный и гибкий – это, конечно же, старый добрый Template-Toolkit. К слову, если вы Python-разработчик, то вам будет интересен проект Template-Python, я писал как-то об этой разработке в своем блоге.

Плагины

Есть вещи, которые сложно отнести непосредственно только к Модели, Контроллеру либо Представлению. Вот, скажем, разграничение прав доступа пользователей: в Контроллере вы будете проверять, не запросил ли текущий пользователь запрещенные данные, в Представлении будете решать какие элементы управления показывать пользователю, а в Модели можно вести журнал того, какой пользователь что изменял или удалял. Система разграничения прав доступа это одна сущность, к которой нужно иметь доступ из любой точки проекта. Это всего лишь пример одного плагина, но есть еще целая куча вариантов готовых для работы плагинов на CPAN, которые помогут в решении самых разнообразных задач.

Генераторы кода

Наверно самое сложное для меня – это создать новый файл и с чистого листа начать писать новый модуль. Генераторы кода решают эту проблему. Теперь, чтобы создать новый Контроллер мне достаточно воспользоваться

$ perl myapp_create.pl controller MyControllerName

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

Catalyst для Perl

Говорят, что Perl – это старый язык. Конечно же, много воды утекло после выпуска 5-й версии еще в далеком 1994 году. Да, стандартная языковая поддержка ООП не настолько развита, как скажем в Python или Ruby, но у языка Perl есть одна очень интересная особенность. На самом языке можно расширять сам язык. Так что сейчас в Перле могут быть доступны самые удобные вещи из ООП, которые есть в других языках.

Скажем, к примеру, в Perl нет поддержки свойств (property) и их наследования – нет проблем: эту поддержку можно реализовать запросто, использовав модули Class::Accessor::Fast или Class::Data::Inheritable. Не понравилось, как работает алгоритм множественного наследования? – Реализуем свой в Class::C3.
Все эти вещи, и многое другое, активно используются в Catalyst, что позволяет вести комфортную разработку приложений, не отказывая себе в новомодных новшествах в мире ООП.

Полезные ссылки

В этой заметке я не приводил примеров кода, и еще много чего осталось за кадром. Моя цель – обратить внимание сообщества на то, что Perl не пасет задних в области веб программирования, и если вы хотите разработать что-то свое, что-то такое чего еще нет в достаточной мере в популярных CMS’ках – то обратите внимание на Catalyst. Это фреймворк, который избавит вас от необходимости искать «что-то лучшее» или «что-то более гибкое». Catalyst и есть то самое гибкое и… элегантное. ;)

catalyst bookВ изучении веб-фреймворка вам поможет официальное вики, официальное руководство.

И замечательная книга Джонатана Роквея “Catalyst”. Конечно, эта книга не бесплатна, но, для человека, умеющего пользоваться Гуглом – это не проблема :)

Теги: , , , , ,

1 звезда2 звезды3 звезды4 звезды5 звезд (25 голосов, средний: 4.52 из 5)
Загрузка ... Загрузка ...
Распределение голосов

Понравилась статья? Подпишись на обновления по RSS/E-mail

Подписаться, не оставляя комментарий

Все комментарии (15) к “Catalyst – Perl веб-фреймворк в лучших традициях MVC” RSS

  1. Всеволод Соловьёв говорит:

    И в новый контроллер будет помещен стандартный шаблонный код, который позволит сразу же проверить новый контроллер на работоспособность.

    По файлу на контроллер? Шаблонный код? Фу-фу, я слышу запах Джавы.

  2. Сергей Щетинин говорит:

    Спасибо за статью. Есть несколько вопросов.

    А вот, к примеру, Catalyst::Controller::View делегирует запрос пользователя непосредственно в Представление. Таким образом, всю бизнес-логику можно реализовать в Представлении. Но, это уже, немного, извращение.

    Зачем делегировать запрос в V? Также было упомянуто что работой с БД занимается C. Зачем тогда вообще модель в такой системе? Если это считается извращением, то что оно вообще делает в библиотеке?

    Мне понятно желание схлопнуть разные компоненты, но непонятно зачем тогда изначально брать MVC? Есть ли у вас пример когда одна и та же модель использовалась с разными V и C?

    Еще интересна история фреймворка: кому, когда и по какой причине захотелось для веб-разработки на Перле использовать MVC? Кроме веба он способен на что-то еще?

    ORM лежит слоем ниже модели или используется как mixin? Упомянута работа с БД из контроллера. Как в таком случае читает данные модель? Или они читаются только при инициализации?

    Заранее спасибо за ответы.

  3. Максим Вуец говорит:

    Зачем делегировать запрос в V?

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

    Также было упомянуто что работой с БД занимается C. Зачем тогда вообще модель в такой системе? Если это считается извращением, то что оно вообще делает в библиотеке?

    Нет, с БД (или другим источником информации) работает M.
    C лишь принимает запрос, что и из какой M взять и какому V это скормить.
    Результат работы V отправляется клиенту. Вроде так.

    Еще интересна история фреймворка: кому, когда и по какой причине захотелось для веб-разработки на Перле использовать MVC? Кроме веба он способен на что-то еще?

    IIRC, MFC тоже сделан по этой моделе. Еще Java Swing.
    GUI framework-и часто по такой моделе делаются.
    В принципе, MVC — это pattern, по-этому можно использовать где угодно.

    ORM лежит слоем ниже модели или используется как mixin?

    ORM — тоже pattern. Почитайте о этом всем на WP. Моделью может быть
    модуль с двумя функциями: прочитать число из файла, инкрементировать его,
    записать обратно и вернуть контроллеру; а вторая тоже самое,
    только декрементировать. И это будет модель, да. А ORM — это
    один из методов абстракции поверх БД (а может и данных вообще).

  4. Сергей Щетинин говорит:

    Максим, я надеялся что по вопросам ясно что я знаю что такое MVC, а вопросы относятся к реализации и рекомендуемых подходах в Catalyst.
    Спасибо за ответы, но зря трудились.

    Насчет:

    Нет, с БД (или другим источником информации) работает M.

    Так должно бы быть, но автор написал:

    Вот, например, Catalyst::Controller::CRUD реализует код для основных функций чтения/записи в БД.

  5. Максим Вуец говорит:

    Сергей, видать вопросы были слишком базовые.
    Ничего страшного — кому-то другому пригодятся, типа FAQ (;
    Да и писал я спросонья (=

    Тогда…

    Кроме веба он способен на что-то еще?

    Ну, можно писать GUI с wxWidgets.

  6. Сергей Щетинин говорит:

    Может и базовые, подожду ответы.

  7. Сергей Волошин говорит:

    Сайты на Catalyst:
    http://catalystsites.org/,
    http://dev.catalyst.perl.org/wiki/SitesRunningCatalyst

  8. Dmitry Zhariy говорит:

    Нет, нет. Возможно, я где-то неоднозначно выразился, но я абсолютно не имел ввиду что Контроллер работает непосредственно с БД. Нет. Для работы с источниками данных контроллер использует Модель.

    Ответы на вопросы я дам после блока исходников.
    Вот пример одного Действия Контроллера, которое выполняет валидацию данных и сохраняет их посредствам Модели в БД.

    
    # Отрывок из Контроллера BoostedTest::C::Testplan
    sub create : Local {
        # Для работы с формами используется Rose::HTML::Form.
        # Для работы с БД используется ORM Rose::DB::Object.
        # ==================================================
    
        my ( $self, $c ) = @_;
    
        # $c - это переменная контекста запроса. Содержит данные о текущем
        # запросе пользователя. $c - это переменная, через которую
        # запрашиваются другие элементы фреймворка (Модели, Представления,
        # другие Контроллеры, Плагины, Объекты Request и Response)
    
        my $form = BoostedTest::Form::Testplans::Edit->new();
        $form->context_init($c);
    
    	# Это специфика Rose::DB::Object. Для работы с одной записью,
        # используется Rose::DB::Object а для группы --
        # Rose::DB::Object::Manager. Я считаю это разделение удобным,
        # но вот, скажем, в популярном DBIx::Class такого разделения нет 
    
        my $testplan = $c->model('Testplan')->create();
        my $iterator = $c->model('Testplan')->manager->get_testplans_iterator;
        if ( $form->was_submitted and $form->validate ) {
    
        	# Rose::DB::Object и Rose::HTML::Form интегрированы между собой,
            # для удобства их совместного использования. Так что из метода
            # объекта формы можно инициализировать  объект ORM и дальше работать
            # с ним.
    
            $testplan = $form->testplan_from_form($testplan);
        	$testplan->save;
        	$c->stash->{message} = "Added!";
        }
        # $c->stash->{testplans}
        # Stash - это посредник для передачи переменных в шаблон.
        # В любой шаблон. В данном случае используется Template toolkit
    
        $c->stash->{testplans} = $iterator;
        $c->stash->{form} = $form;
        $c->stash->{template} = 'testplans/create.html';
    }
    

    Модель выглядит так:

    
    package BoostedTest::M::Testplan;
    
    use strict;
    use warnings;
    
    use base qw[ Catalyst::Model::RDBO ];
    
    __PACKAGE__->config(
                         name      => 'BoostedTest::RDBO::Testplan',
                         manager   => 'BoostedTest::RDBO::Testplan::Manager',
                         # load_with => ['foo', 'bar', 'wtf']
                       );
    1; # Magic end of model ;)
    

    Класс BoostedTest::RDBO::Testplan содержит сгенерированную автоматически структуру таблицы, с информацией о типах полях и связях между таблицами. Пользовательские методы для работы с БД (получение 3-х последних записей и т.д. ) можно дописывать в Модель.

    Теперь конкретно по вопросам:

    Зачем делегировать запрос в V? Также было упомянуто что работой с БД занимается C.
    Зачем тогда вообще модель в такой системе? Если это считается извращением, то что
    оно вообще делает в библиотеке?

    И

    Так должно бы быть, но автор написал:
    Вот, например, Catalyst::Controller::CRUD реализует код для основных функций
    чтения/записи в БД.

    Catalyst::Controller::CRUD и Catalyst::Controller::View это не часть основной библиотеки Catalyst. Все ваши Контроллеры, по умолчанию, наследуются от Catalyst::Controller. А те два модуля, представленные выше – это всего лишь доработка и изменение поведения Catalyst::Controller, от которого они наследуются. Для Catalyst есть две основных библиотеки Catalyst-Runtime и Catalyst-Devel. Для работы (продакшн) приложения на Каталисте требуется обязательно только Catalyst-Runtime. Все же остальные модули являются надстройками и в некоторых конкретных ситуациях способны упростить жизнь разработчику, но они необязательны.
    В Perl принято называть модули по принципу «что делает модуль». Модули с общим префиксом могут не быть частями одной большой библиотеки, и зачастую так и происходит.
    Вот пример:
    Есть модули CGI, CGI::Tiny, CGI::Simple. На самом деле это разные модули, написанные разными людьми, но чтобы было понятно, что они служат для работы с CGI – у этих модулей один и тот же префикс.

    Вот пример по поводу Catalyst::Controller::View.
    Предположим у вас есть приложение, которое не взаимодействует с пользователей через формы. Просто отображает информацию. Что-то там мониторит выводит информацию и рисует графики. Дело в том, что приложения на Catalyst переносимы между различными серверными конфигурациями. Будь то mod_perl, cgi, FastCGI – не важно, ваше приложение не требует переписывания для переноса на другую конфигурацию. При использовании чистого Perl’a, без фреймворков – проблемы переносимости могли бы быть, с Каталистом их не будет.

    ORM лежит слоем ниже модели или используется как mixin? Упомянута работа с БД
    из контроллера. Как в таком случае читает данные модель? Или они читаются только
    при инициализации?

    Из Контроллера запрашивается модель ( как показано в примере выше ) и далее работа ведется по средствам ORM’а. В примере, в шаблон был передан итератор. Вот пример его использования в шаблоне:

    [% WHILE ( testplan = testplans.next ) %]
    [% testplan.name %] [% testplan.created %]
    [% END %]
    

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

    Еще интересна история фреймворка: кому, когда и по какой причине захотелось для
    веб-разработки на Перле использовать MVC? Кроме веба он способен на что-то еще?
    

    Я думаю, что Perl ничем не уступает ни Python, ни PHP, ни Ruby. Просто Перл немного сложнее в изучении. В Catalyst, к примеру, очень много чего похожего из Rails (это все таки Опен Сорс, и хорошие идеи необходимо реализовывать). Так если на Rail можно создавать красивые веб-сайты, то почему бы не делать этого на Catalyst?
    Кроме того, у Perl намного больше различных модулей для работы с источниками данных, парсинга текста и много-много другого. И… Perl просто работает быстрее Ruby.
    Вот, могу посоветовать почитать следующею очень интересную заметку:
    Catalyst: Perl’s answer to Ruby on Rails and AJAX

    P.S: советую посмотреть еще один сайт, разработанный на Catalyst:
    http://godcore.org.ua/

  9. Сергей Щетинин говорит:

    Понял, спасибо.

  10. Dmitry Zhariy говорит:

    2 Всеволод Соловьёв

    И в новый контроллер будет помещен стандартный шаблонный код, который позволит сразу же проверить новый контроллер на работоспособность.

    По файлу на контроллер? Шаблонный код? Фу-фу, я слышу запах Джавы.

    А я считаю такой подход очень удобным. По крайней мере такой подход сейчас очень популярен. Но, если очень и очень хочется – то можно держать и много контроллеров в одном файле. Есть там такой корневой контроллер Root.pm, который создается для каждого проекта Catalyst, действия которого вызываются прежде действий других контроллеров. Это нужно, например, для собственной обработки HTTP-ошибок, как то 404-я или 500-я, но, можно и перехватывать вызовы других контроллеров и обрабатывать их по-своему. С другой стороны, можно кастумезировать обработчик запросов Catalyst::Dispatcher, и создать свой, локальный… но это уже немного усложнит код проекта ;)

  11. PavelR говорит:

    Подскажите экзампл, с которого можно начать написание веб-проекта, например по типу форума?

  12. Dmitry Zhariy говорит:

    Не поленитесь вытянуть исходники Catalyst из svn-репозитория:

    $ svn co http://dev.catalyst.perl.org/repos/Catalyst/trunk

    там есть очень полезные примеры простых приложений, включая небольшой форум.
    Есть проект форума. Foorum называется. Живое демо можно посмотреть тут.
    Могу посоветовать еще движок блога на Catalyst. Там есть хорошие примеры использования Rose::DB::Object.

    ====
    И, пользуясь случаем, вот еще один пример проекта на Catalyst:
    Сервис по поиску соседей по квартире http://delim.com.ua/
    Изображение Какталистовой молекулы в (http://delim.com.ua/favicon.ico) выдает то, какую технологию применили создатели сайта. Вспомнил о проекте, потому что когда-то читал заметку на Хабре.

  13. Dmitry Zhariy говорит:

    Доклад (видео) Романа Беликина по теме: MVC + Catalyst можно посмотреть на YAPC::TV – http://yapc.tv/2008/fe/roman-catalyst

  14. Krin говорит:

    Может кто подскажет - есть ли русская документция к этому чудному фреймворку? Или к примеру исходники какого нибудь приложения с русскими коментариями.

  15. Дмитрий Жарий говорит:

    С русскоязычной докой увы… не сложилось :(
    Можете поискать книгу, которая была рекомендована в заметке, с ее помощью можно научится работать с Каталистом без особых знаний английского: очень интересно, просто и понятно написана.

Оставить комментарий

Указать свой сайт могут только зарегистрированные пользователи. Регистрация или вход.

Архив

Комментарии

Последние комментарии