SlideShare ist ein Scribd-Unternehmen logo
1 von 123
Downloaden Sie, um offline zu lesen
Почему Mojolicious?
     Анатолий Шарифулин
      YAPC::Russia 2011
mojolicio.us
Кто знает, что такое
    Mojolicious?
Кто использует
 Mojolicious?
На кого повлиял я? :)
Коротко
Современный и
   молодой
веб-фреймворк
Веб в коробке!
Mojo::Base
Mojo::DOM, Mojo::JSON
   Mojo::UserAgent
     Mojo::IOLoop
    Mojo::Template
Mojo
 Mojolicious
Mojolicious::Lite
Test::Mojo
   ojo
     ...
385 вотчеров
 88 форков
 По данным github.com
и один Шарифулин :-)
      По моему мнению
Почему всё-таки
   Mojolicious?
Когда есть Dancer, Plack, Python и Node.js
Помогает решить
почти любую задачу
     Почему Mojolicious?
Начиная от простого
 сайта в 5 страниц
     Почему Mojolicious?
tochkak.ru
use Mojolicious::Lite;

get '/'      => 'about/what' ;
get '/who' => 'about/who' ;
get '/what' => 'about/what' ;
get '/where' => 'about/where';
get '/code' => 'about/code' ;

app->log->level('error');

app->start;
Заканчивая стартапом
c 5000+ пользователями
       Почему Mojolicious?
frodio.com
или
узкоспециализированной
  системой управления
    для кинотеатров
       Почему Mojolicious?
db.dcp24.ru
От простых скриптов
     Почему Mojolicious?
#!/usr/bin/env perl
use ojo;

g( 'http://bobina.pdj.ru/rss.xml' )
	

 ->dom
   	

 ->find( 'enclosure[url]' )
	

 ->each(sub {
	

 	

 say shift->attrs->{url}
	

 })
;
или TCP-клиента для
сотни радио-потоков
     Почему Mojolicious?
my $url = Mojo::URL->new(
	

 'http://frod.io:8000/station20'
);
$loop->connect(
	

 address       => $url->host,
	

 port           => $url->port,
	

 on_connect => sub { ... },
    on_read        => sub { ... },
);
$loop->start;
on_connect => sub {
	

 	

 my ($self, $id) = @_;
	

 	

	

 	

 my $r = Mojo::Message::Request->new;
	

 	

 $r->headers->header(
           'Icy-MetaData' => 1
        );
	

 	

 $r->url( $url );
	

 	

	

 	

 $self->write($id, $r->to_string);
},
on_read => sub {
	

 my ($self, $id, $chunk) = @_;

	

 return unless my %tag =
	

 	

 $chunk =~ /Stream(w+)='(.*?)';/g;
	

	

 say $tag{Title};
},
До софта по
   тиражированию
     фильмов для
цифровых кинотеатров
      Почему Mojolicious?
CopyDisk
Mojo::Base
  Mojo::Log
 MojoX::Run
Curses::Widgets
А также тесты для
  веб-сервисов
    Почему Mojolicious?
use Test::More tests => 252;
use Test::Mojo;

my $t = Test::Mojo->new(app => 'App'); # App.pm
my $url = '/api';
# my $url = 'http://api.dev.frodio.com';

$t->get_ok( "$url/" )
  ->status_is( 200 )
  ->json_content_is({ hello => 'Hello, Frodio!' })
;
my $data = $t->post_form_ok("$url/like",
{station_id => 2}, {'X-Frodio-Auth' => $auth})
   ->status_is(200)
   ->tx->res->json
;
{
	

 is ref    $data, 'HASH';
	

 is exists $data->{ok}, 1;
	

 is exists $data->{count}, 1;
	

 is defined $data->{sign}, 1, 'Like station';
}
$t->post_form_ok("$url/logout/",
	

 {'X-Frodio-Auth' => $auth}
)
   ->status_is(200)
;
Большинство своих
   задач я решаю,
используя Mojolicious
«Всегда хотел
научиться делать
     сайты»
etnogenez.ru
Небольшой сайт с
полноценной панелью
     управления
26 модулей (140k), 91 шаблон (408k), 16 таблиц
Структура проекта
Все пути и запуски — от корня проекта
bin/
conf/
data/
lib/
log/
script/
t/
tmpl/
tmp/
bin/check.sh
bin/logs.sh
bin/mysql
bin/mysqldump
bin/restart.sh
bin/start.sh
bin/stop.sh
bin/start.sh
(
	

 # script/etnogenez daemon --reload
	

 starman --listen :3000 script/etnogenez
) >> log/error.log &
conf/app.conf
conf/mysql.conf
conf/nginx.conf
conf/app.conf
{
	

   secret => '*****',
	

   server => {
	

   	

 www => $ENV{DEV} ? 'http://...' : 'http:/...',
	

   	

 ...
	

   },
	

   session => { ... },
	

   log       => {
	

   	

 level => $ENV{DEV} ? 'debug' : 'warn',
	

   	

 path => 'log/app.log',
	

   }, ...
}
conf/mysql.conf
{
	

   drivername => 'mysql',
	

   user           => $ENV{DEV} ? 'dev' : 'не-dev',
	

   password       => '******',
	

   datasource => {
	

   	

 database => $ENV{DEV} ? 'dev' : 'не-dev',
	

   	

 host     => 'localhost',
	

   },
};
data/
 log/
tmp/
  t/
script/
Стартовый скрипт
Пути к библиотекам, настройка переменных
               окружения
use common::sense;
use lib qw(lib /tk/lib);

BEGIN {
	

 $ENV{DEV}++ if qx(pwd) =~ /dev/;
	

 $ENV{MOJO_MODE} ||= $ENV{DEV} ? 'dev' : 'production';
	

 $ENV{MOJO_TMPDIR} = 'tmp/upload';
	

 $ENV{MOJO_MAX_MESSAGE_SIZE} = 2 * 1024 ** 3;
};
$ENV{MOJO_APP} ||= 'App';

use Mojolicious::Commands;
Mojolicious::Commands->start;
lib/
App.pm
package App;
use Mojo::Base 'Mojolicious';

has conf => sub { do 'conf/app.conf' };
has db => sub { use Util; Util->db(
	

 do 'conf/mysql.conf'
) };

sub startup { ... }
use DBI 1.58; use DBD::mysql 4.004; use DBI::Util;

return DBI->connect(DBI::Util::_parse_cfg(
	

 $conf,
	

 {
	

 	

 RootClass => 'DBI::Util',
	

 	

 mysql_enable_utf8 => 1,
	

 	

 mysql_auto_reconnect => 1,
	

 }
));
select
query
   in
 limit
values
use dw;
Lazy-обертка, связи parent/child и прочее
       Контекстно проекту и БД
sub book { my $self = shift;
	

 SLICELY { $self->dw::g::part ('book_id') } 'id' => 'part' =>
	

 ...
}

sub part { my $self = shift;
	

 SLICELY { CHV {$_->[0]} $self->dw::g::book('id') } 'book_id'
=> 'book' =>
	

 ...
}
sub _list {
	

 my $self = shift;
	

 ...	

	

 return $self->dw->book(
	

 	

 $self->db->select(
	

 	

 	

 "select * from book where hidden=0
	

 	

 	

 order by $order $limit"
	

 	

 )
	

 );
}
bin/mysql
С базой данной работаю через консоль
Настройка путей,
логов, сессий, типов
        startup
Подключение
плаггинов и хелперов
        startup
$app->helper(db => sub { shift->app->db });

sub action {
	

 my $self = shift;
	

 # my $DB = $self->app->db;

	

 $self->db->select('...');
}
$app->helper(u => sub {
	

 	

 my $self = shift;
	

 	

 my $func = shift || return;
	

 	

	

 	

 return &{"Util::$func"};
	

 });

$self->u(iso2human => '...');

%=u iso2human => '...'
# в каждом контроллере
use Util;

# в шаблоне или коде
Util::iso2human(...);

# это boilercode и некрасиво
# поэтому хелпер
Общие и
контексно проекта
     хелперы
Mojolicious::Plugin::UtilHelpers и App::Helpers
Все роутеры проекта
        startup
route, bridge, waypoint,
    name, shortcut
     Mojolicious::Guides::Routing
my $ad = $r->route('/admin')->to->name('admin');
$ad->route('/login')->post->to('admin-enter#login');
	

my $a = $ad->bridge->to('admin-enter#check');

# shortcut / /sort /add /:id /:id/edit /:id/remove /:filter
$a->crud($_ => "admin-$_") for qw(book part ...);

$a->route('/(*any)')->to('admin#not_found');
App::Helpers
Различные форматирования, работы со строками,
          повторяющиеся действия
$app->helper(format_mmss => sub {
	

   	

 my $self = shift;
	

   	

 my $int = shift || return '00:00';
	

   	

	

   	

 return sprintf "%02d:%02d",
	

   	

 	

 $int / 60, $int % 60;
	

   });
$app->helper(user_img => sub {
	

   	

 my $self = shift;
	

   	

 my $user = shift || $self->stash('USER');
	

   	

	

   	

 return $user->{avatar} || '/.../default.png';
	

   });
App::Index
        Контроллер
$r->route->to('index#main');
package App::Index;
use App::Base -controller, with =>
['App::News', 'App::Book', 'App::Audio'];

sub main { ... }
package App::Index;
use Mojo::Base 'Mojolicious::Controller';
use common::sense;

use App::News;
use App::Book;
use App::Audio;

has news => sub { App::News->new(%{ +shift }) };
has book => sub { App::Book->new(%{ +shift }) };
has audio => sub { App::Audio->new(%{ +shift }) };
package App::Index;
use Mojo::Base 'Mojolicious::Controller';
use common::sense;

use App::News;
use App::Book;
use App::Audio;

__PACKAGE__->attr(news => sub { App::News->new
(%{ +shift }) });
__PACKAGE__->attr(book => sub { App::Book->new
(%{ +shift }) });
__PACKAGE__->attr(audio => sub { App::Audio->new
(%{ +shift }) };
Mojo::Base vs. App::Base
    common::sense, -controller, with
package App::Index;
use App::Base -controller, with =>
['App::News', 'App::Book', 'App::Audio'];

sub main { ... }
my $self = shift;
my $limit = $self->conf('limit')->{index};

$self->render('index',
	

 news => $self->news->_last(limit =>
$limit->{news}),
	

 book => $self->book->_list,
	

 part => $self->audio->_last(limit =>
$limit->{part}),
);
App::Book
  Контроллер
package App::Book;
use App::Base -controller;

sub check { ... } # для bridge

sub list { ... }

sub item { ... }

sub _list { ... } # возращает данные
sub check {
	

 my $self = shift;
	

	

 return 0 unless my $book = $self->dw->book(
	

 	

 $self->db->select(
	

 	

 	

 'select * from book where name=? limit 1',
	

 	

 	

 $self->stash('book_name')
	

 	

 )
	

 )->[0];
	

	

 $self->stash(book => $book);
	

 return 1;
}
sub item {
	

 my $self = shift;
	

 my $book = $self->stash('book');
	

 ...
}

# роутеры

my $bn = $r->bridge('/book/:book_name')
->to('book#check');

$bn->route->to('book#item')->name('book');
tmpl/
index.html.ep
          Шаблон
$r->route->to('index#main');
% layout 'default', title => '...';

<div id="column1">
% for (@$news) {
	

 %== include 'news/item.inc', item => $_
%}
</div>

<span class="date">
	

 %=u iso2humanM => $_->{published}
</span>

<span class="download_count">
	

 <%= format_digital($_->{listened}) %> раз
</span>
$news
     vs.
stash 'news'
layouts/default.html.ep
layouts/default.mail.ep
  layouts/default.rss.ep
 layouts/admin.html.ep
etc/page.html.ep
etc/submenu.html.ep
admin/etc/sort.txt.ep
Ни в коем случае
сложной логики, тем
   более SQL :-)
exception.html.ep
  exception.mail.ep
exception.dev.html.ep
% layout 'default', title => 'Страница временно
недоступна', simple => 1;

<div class="error_page">Ошибка 500. Страница
временно недоступна. Попробуйте позднее.</
div>

% mail(to => conf('mail')->{devel}, template =>
'exception', format => 'mail');
stash и defaults
Справочники и работа с ними
include 'etc/vars'
Раньше был шаблон, который подключался везде
# app.conf
defaults => {
	

 book_status => [
	

 	

 [soon => 'Готовится к изданию'],
	

 	

 ...,
	

 	

 [new => 'Новинки'],
	

 ],
	

 ...
}
# App.pm
if (my $d = $conf->{defaults}) {
	

 	

 $self->defaults( $d );
	

 	

	

 	

 for (keys %$d) {
	

 	

 	

 next unless ref $d->{$_} eq 'ARRAY';
	

 	

 	

 $self->defaults($_ . '_hash' => {
	

 	

 	

 	

 map { $_->[0] => $_->[1] }
	

 	

 	

 	

 @{ $d->{$_} }
	

 	

 	

 });
	

 	

 }
}
# в шаблоне

@$book_status

# или

$book_status_hash->{new}
Работы с формами
Я не использую
никаких генераторов
       форм
Формы для
 пользователей и
модель данных —
  разные вещи
# App::Admin::Book
sub add {
	

 my $self = shift;
	

 return $self->form unless $self->validate->book;
	

 # работа с полученными данными
}

sub edit {
	

 my $self = shift;
	

 my $item = $self->stash('item'); # через bridge
	

	

 return $self->form unless $self->validate->book;
	

 ...
}
admin/book/
form.html.ep
Шаблон может быть один
В итоге получаются
  очень простые
  контроллеры и
     шаблоны
И весь проект в целом
Вспомогательные
      скрипты
Рассылка по пользователям, графики для munin,
                cron-скрипты
# script/munin/user.pl

use MojoX::Loader;
my $user = MojoX::Loader->load(
	

 controller => 'App::User'
);

say $user->_total;

# $user->db->select(...);
# $user->conf('server')->{www}
# $user->render_partial('...', stash1 => '..', stash2 => '..')
# $user->mail(to => '..', template => '..')
MojoX::Loader
https://github.com/sharifulin/mojox-loader
Mojolicious очень
удобный и простой
   инструмент
С большим количеством
  современных фитч
Хороший open source
     проект
Активное сообщество
И в принципе
адекватый автор :-)
«Удивлен насколько
легко читается код,
 даже для человека,
который Perl видит
второй раз в жизни»
Попробуйте
Mojolicious прямо
     сейчас!
Не будьте
«I am just slow to get
      things...»
       http://frd.io/gf6
use Mojolicious or die;
use Perl or die;
JFDI
Спасибо за внимание!
     Анатолий Шарифулин
      YAPC::Russia 2011
Mojolicous by @vti

Weitere ähnliche Inhalte

Was ist angesagt?

Не верь никому или разработка эффективных приложений (Как писать по настоящем...
Не верь никому или разработка эффективных приложений (Как писать по настоящем...Не верь никому или разработка эффективных приложений (Как писать по настоящем...
Не верь никому или разработка эффективных приложений (Как писать по настоящем...Moscow.pm
 
Динамический код: модифицируем таблицу символов во время выполнения. Елена Ши...
Динамический код: модифицируем таблицу символов во время выполнения. Елена Ши...Динамический код: модифицируем таблицу символов во время выполнения. Елена Ши...
Динамический код: модифицируем таблицу символов во время выполнения. Елена Ши...Moscow.pm
 
Программирование Linux
Программирование LinuxПрограммирование Linux
Программирование LinuxAnthony Shoumikhin
 
Present saint-per3-by-pavel-vlasov
Present saint-per3-by-pavel-vlasovPresent saint-per3-by-pavel-vlasov
Present saint-per3-by-pavel-vlasovPavel Vlasov
 
Js Http Request дмитрий котеров
Js Http Request   дмитрий котеровJs Http Request   дмитрий котеров
Js Http Request дмитрий котеровMedia Gorod
 
UWDC 2013, Как мы используем Yii
UWDC 2013, Как мы используем YiiUWDC 2013, Как мы используем Yii
UWDC 2013, Как мы используем YiiAlexander Makarov
 
Блоки, лямбды, замыкания
Блоки, лямбды, замыканияБлоки, лямбды, замыкания
Блоки, лямбды, замыканияDmitriy Kiriyenko
 
Командная разработка “толстых клиентов”
Командная разработка “толстых клиентов”Командная разработка “толстых клиентов”
Командная разработка “толстых клиентов”Open-IT
 
Программирование Linux
Программирование LinuxПрограммирование Linux
Программирование LinuxAnthony Shoumikhin
 
«Изоморфные js приложения с использованием catberry.js», Денис Речкунов
«Изоморфные js приложения с использованием catberry.js», Денис Речкунов«Изоморфные js приложения с использованием catberry.js», Денис Речкунов
«Изоморфные js приложения с использованием catberry.js», Денис РечкуновDevDay
 
Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием...
Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием...Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием...
Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием...Vadim Kruchkov
 
dont badmouth mojo
dont badmouth mojodont badmouth mojo
dont badmouth mojoAnton Ukolov
 
Что нового в Perl? 5.10 — 5.16
Что нового в Perl? 5.10 — 5.16Что нового в Perl? 5.10 — 5.16
Что нового в Perl? 5.10 — 5.16Anatoly Sharifulin
 
Михаил Боднарчук Современное функциональное тестирование с Codeception
Михаил Боднарчук Современное функциональное тестирование с CodeceptionМихаил Боднарчук Современное функциональное тестирование с Codeception
Михаил Боднарчук Современное функциональное тестирование с CodeceptionAlbina Tiupa
 

Was ist angesagt? (20)

Erlang tasty & useful stuff
Erlang tasty & useful stuffErlang tasty & useful stuff
Erlang tasty & useful stuff
 
Не верь никому или разработка эффективных приложений (Как писать по настоящем...
Не верь никому или разработка эффективных приложений (Как писать по настоящем...Не верь никому или разработка эффективных приложений (Как писать по настоящем...
Не верь никому или разработка эффективных приложений (Как писать по настоящем...
 
Динамический код: модифицируем таблицу символов во время выполнения. Елена Ши...
Динамический код: модифицируем таблицу символов во время выполнения. Елена Ши...Динамический код: модифицируем таблицу символов во время выполнения. Елена Ши...
Динамический код: модифицируем таблицу символов во время выполнения. Елена Ши...
 
Программирование Linux
Программирование LinuxПрограммирование Linux
Программирование Linux
 
UWDC 2013, Yii2
UWDC 2013, Yii2UWDC 2013, Yii2
UWDC 2013, Yii2
 
Decorators' recipes
Decorators' recipesDecorators' recipes
Decorators' recipes
 
Present saint-per3-by-pavel-vlasov
Present saint-per3-by-pavel-vlasovPresent saint-per3-by-pavel-vlasov
Present saint-per3-by-pavel-vlasov
 
Js Http Request дмитрий котеров
Js Http Request   дмитрий котеровJs Http Request   дмитрий котеров
Js Http Request дмитрий котеров
 
PowerShell
PowerShellPowerShell
PowerShell
 
UWDC 2013, Как мы используем Yii
UWDC 2013, Как мы используем YiiUWDC 2013, Как мы используем Yii
UWDC 2013, Как мы используем Yii
 
Блоки, лямбды, замыкания
Блоки, лямбды, замыканияБлоки, лямбды, замыкания
Блоки, лямбды, замыкания
 
Perl 5.10 и 5.12
Perl 5.10 и 5.12Perl 5.10 и 5.12
Perl 5.10 и 5.12
 
Perl – жив?!
Perl – жив?!Perl – жив?!
Perl – жив?!
 
Командная разработка “толстых клиентов”
Командная разработка “толстых клиентов”Командная разработка “толстых клиентов”
Командная разработка “толстых клиентов”
 
Программирование Linux
Программирование LinuxПрограммирование Linux
Программирование Linux
 
«Изоморфные js приложения с использованием catberry.js», Денис Речкунов
«Изоморфные js приложения с использованием catberry.js», Денис Речкунов«Изоморфные js приложения с использованием catberry.js», Денис Речкунов
«Изоморфные js приложения с использованием catberry.js», Денис Речкунов
 
Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием...
Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием...Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием...
Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием...
 
dont badmouth mojo
dont badmouth mojodont badmouth mojo
dont badmouth mojo
 
Что нового в Perl? 5.10 — 5.16
Что нового в Perl? 5.10 — 5.16Что нового в Perl? 5.10 — 5.16
Что нового в Perl? 5.10 — 5.16
 
Михаил Боднарчук Современное функциональное тестирование с Codeception
Михаил Боднарчук Современное функциональное тестирование с CodeceptionМихаил Боднарчук Современное функциональное тестирование с Codeception
Михаил Боднарчук Современное функциональное тестирование с Codeception
 

Ähnlich wie Почему Mojolicious?

Psgi app
Psgi appPsgi app
Psgi appund3f
 
Мульти-доменность в Django проекте
Мульти-доменность в Django проектеМульти-доменность в Django проекте
Мульти-доменность в Django проектеAlexey Kinyov
 
Behat в PHP с использованием Behat и Mink
Behat в PHP с использованием Behat и MinkBehat в PHP с использованием Behat и Mink
Behat в PHP с использованием Behat и Minktyomo4ka
 
Эффективное программирование на NodeJS
Эффективное программирование на NodeJSЭффективное программирование на NodeJS
Эффективное программирование на NodeJSYura Bogdanov
 
Интуит. Разработка приложений для iOS. Лекция 7. Работа с сетью
Интуит. Разработка приложений для iOS. Лекция 7. Работа с сетьюИнтуит. Разработка приложений для iOS. Лекция 7. Работа с сетью
Интуит. Разработка приложений для iOS. Лекция 7. Работа с сетьюГлеб Тарасов
 
Ubercart -nemnogo_primerov_iz_zhizni
Ubercart  -nemnogo_primerov_iz_zhizniUbercart  -nemnogo_primerov_iz_zhizni
Ubercart -nemnogo_primerov_iz_zhiznidrupalconf
 
PHP Tricks
PHP TricksPHP Tricks
PHP TricksBlackFan
 
Easy authcache 2 кеширование для pro родионов игорь
Easy authcache 2   кеширование для pro родионов игорьEasy authcache 2   кеширование для pro родионов игорь
Easy authcache 2 кеширование для pro родионов игорьdrupalconf
 
Saint Perl 2009: CGI::Ajax demo
Saint Perl 2009: CGI::Ajax demoSaint Perl 2009: CGI::Ajax demo
Saint Perl 2009: CGI::Ajax demomegakott
 
'The best practices' by KONSTANTIN KULAKSYZ at OdessaJS'2020
'The best practices' by KONSTANTIN KULAKSYZ at OdessaJS'2020'The best practices' by KONSTANTIN KULAKSYZ at OdessaJS'2020
'The best practices' by KONSTANTIN KULAKSYZ at OdessaJS'2020OdessaJS Conf
 
Symfony2. На чем можно сэкономить время при разработке?
Symfony2. На чем можно сэкономить время при разработке?Symfony2. На чем можно сэкономить время при разработке?
Symfony2. На чем можно сэкономить время при разработке?Stepan Tanasiychuk
 
Easy authcache 2 кэширование для pro. Родионов Игорь
Easy authcache 2   кэширование для pro. Родионов ИгорьEasy authcache 2   кэширование для pro. Родионов Игорь
Easy authcache 2 кэширование для pro. Родионов ИгорьPVasili
 
Микрофреймворки PHP
Микрофреймворки PHPМикрофреймворки PHP
Микрофреймворки PHPEkaterina Giganova
 
Страх и ненависть в исходном коде
Страх и ненависть в исходном кодеСтрах и ненависть в исходном коде
Страх и ненависть в исходном кодеKolya Korobochkin
 
Миша Рудрастых: Введение в HTTP API WordPress
Миша Рудрастых: Введение в HTTP API WordPressМиша Рудрастых: Введение в HTTP API WordPress
Миша Рудрастых: Введение в HTTP API WordPressRuslan Begaliev
 
Knockoutjs на примере 2ГИС-Онлайн
Knockoutjs на примере 2ГИС-ОнлайнKnockoutjs на примере 2ГИС-Онлайн
Knockoutjs на примере 2ГИС-Онлайн2ГИС Технологии
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 1)
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 1)ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 1)
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 1)ZFConf Conference
 

Ähnlich wie Почему Mojolicious? (20)

Psgi app
Psgi appPsgi app
Psgi app
 
Мульти-доменность в Django проекте
Мульти-доменность в Django проектеМульти-доменность в Django проекте
Мульти-доменность в Django проекте
 
Behat в PHP с использованием Behat и Mink
Behat в PHP с использованием Behat и MinkBehat в PHP с использованием Behat и Mink
Behat в PHP с использованием Behat и Mink
 
Эффективное программирование на NodeJS
Эффективное программирование на NodeJSЭффективное программирование на NodeJS
Эффективное программирование на NodeJS
 
Crazy owl yii1=> yii2
Crazy owl yii1=> yii2Crazy owl yii1=> yii2
Crazy owl yii1=> yii2
 
Интуит. Разработка приложений для iOS. Лекция 7. Работа с сетью
Интуит. Разработка приложений для iOS. Лекция 7. Работа с сетьюИнтуит. Разработка приложений для iOS. Лекция 7. Работа с сетью
Интуит. Разработка приложений для iOS. Лекция 7. Работа с сетью
 
Ubercart -nemnogo_primerov_iz_zhizni
Ubercart  -nemnogo_primerov_iz_zhizniUbercart  -nemnogo_primerov_iz_zhizni
Ubercart -nemnogo_primerov_iz_zhizni
 
PHP Tricks
PHP TricksPHP Tricks
PHP Tricks
 
Easy authcache 2 кеширование для pro родионов игорь
Easy authcache 2   кеширование для pro родионов игорьEasy authcache 2   кеширование для pro родионов игорь
Easy authcache 2 кеширование для pro родионов игорь
 
Saint Perl 2009: CGI::Ajax demo
Saint Perl 2009: CGI::Ajax demoSaint Perl 2009: CGI::Ajax demo
Saint Perl 2009: CGI::Ajax demo
 
'The best practices' by KONSTANTIN KULAKSYZ at OdessaJS'2020
'The best practices' by KONSTANTIN KULAKSYZ at OdessaJS'2020'The best practices' by KONSTANTIN KULAKSYZ at OdessaJS'2020
'The best practices' by KONSTANTIN KULAKSYZ at OdessaJS'2020
 
Symfony2. На чем можно сэкономить время при разработке?
Symfony2. На чем можно сэкономить время при разработке?Symfony2. На чем можно сэкономить время при разработке?
Symfony2. На чем можно сэкономить время при разработке?
 
Easy authcache 2 кэширование для pro. Родионов Игорь
Easy authcache 2   кэширование для pro. Родионов ИгорьEasy authcache 2   кэширование для pro. Родионов Игорь
Easy authcache 2 кэширование для pro. Родионов Игорь
 
Микрофреймворки PHP
Микрофреймворки PHPМикрофреймворки PHP
Микрофреймворки PHP
 
Страх и ненависть в исходном коде
Страх и ненависть в исходном кодеСтрах и ненависть в исходном коде
Страх и ненависть в исходном коде
 
Миша Рудрастых: Введение в HTTP API WordPress
Миша Рудрастых: Введение в HTTP API WordPressМиша Рудрастых: Введение в HTTP API WordPress
Миша Рудрастых: Введение в HTTP API WordPress
 
Knockoutjs на примере 2ГИС-Онлайн
Knockoutjs на примере 2ГИС-ОнлайнKnockoutjs на примере 2ГИС-Онлайн
Knockoutjs на примере 2ГИС-Онлайн
 
BDD для PHP проектов
BDD для PHP проектовBDD для PHP проектов
BDD для PHP проектов
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 1)
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 1)ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 1)
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 1)
 
Ci
CiCi
Ci
 

Mehr von Anatoly Sharifulin

Ещё один способ привлекать и удерживать пользователей в играх
Ещё один способ привлекать и удерживать пользователей в играхЕщё один способ привлекать и удерживать пользователей в играх
Ещё один способ привлекать и удерживать пользователей в играхAnatoly Sharifulin
 
ASO Аудит для приложений и игр
ASO Аудит для приложений и игрASO Аудит для приложений и игр
ASO Аудит для приложений и игрAnatoly Sharifulin
 
ASO для iOS 11 (продвижение In-App Prurchases)
ASO для iOS 11 (продвижение In-App Prurchases)ASO для iOS 11 (продвижение In-App Prurchases)
ASO для iOS 11 (продвижение In-App Prurchases)Anatoly Sharifulin
 
AppFollow митап в Москве
AppFollow митап в МосквеAppFollow митап в Москве
AppFollow митап в МосквеAnatoly Sharifulin
 
То, что русскому — ФРИИ, финну — Startup Sauna. Опыт прохождения акселерации ...
То, что русскому — ФРИИ, финну — Startup Sauna. Опыт прохождения акселерации ...То, что русскому — ФРИИ, финну — Startup Sauna. Опыт прохождения акселерации ...
То, что русскому — ФРИИ, финну — Startup Sauna. Опыт прохождения акселерации ...Anatoly Sharifulin
 
Аналитика приложений конкурентов в Google Play
Аналитика приложений конкурентов в Google PlayАналитика приложений конкурентов в Google Play
Аналитика приложений конкурентов в Google PlayAnatoly Sharifulin
 
Конкурентный анализ мобильных приложений
Конкурентный анализ мобильных приложенийКонкурентный анализ мобильных приложений
Конкурентный анализ мобильных приложенийAnatoly Sharifulin
 
Аналитика приложений конкурентов
Аналитика приложений конкурентовАналитика приложений конкурентов
Аналитика приложений конкурентовAnatoly Sharifulin
 
Аналитика магазинов приложений
Аналитика магазинов приложенийАналитика магазинов приложений
Аналитика магазинов приложенийAnatoly Sharifulin
 
Аналитика мобильных приложений
Аналитика мобильных приложенийАналитика мобильных приложений
Аналитика мобильных приложенийAnatoly Sharifulin
 
Анализ приложений конкурентов
Анализ приложений конкурентовАнализ приложений конкурентов
Анализ приложений конкурентовAnatoly Sharifulin
 
ASO оптимизация мобильных приложений: «Что такое хорошо и что такое плохо?»
ASO оптимизация мобильных приложений: «Что такое хорошо и что такое плохо?»ASO оптимизация мобильных приложений: «Что такое хорошо и что такое плохо?»
ASO оптимизация мобильных приложений: «Что такое хорошо и что такое плохо?»Anatoly Sharifulin
 
Продвижение мобильных приложений: с чего начать?
Продвижение мобильных приложений: с чего начать?Продвижение мобильных приложений: с чего начать?
Продвижение мобильных приложений: с чего начать?Anatoly Sharifulin
 
Основной продукт vs. мобильный на примере Ostrovok.ru
Основной продукт vs. мобильный на примере Ostrovok.ruОсновной продукт vs. мобильный на примере Ostrovok.ru
Основной продукт vs. мобильный на примере Ostrovok.ruAnatoly Sharifulin
 
ASO оптимизация и продвижение мобильных приложений
ASO  оптимизация и продвижение мобильных приложенийASO  оптимизация и продвижение мобильных приложений
ASO оптимизация и продвижение мобильных приложенийAnatoly Sharifulin
 

Mehr von Anatoly Sharifulin (20)

Ещё один способ привлекать и удерживать пользователей в играх
Ещё один способ привлекать и удерживать пользователей в играхЕщё один способ привлекать и удерживать пользователей в играх
Ещё один способ привлекать и удерживать пользователей в играх
 
ASO Аудит для приложений и игр
ASO Аудит для приложений и игрASO Аудит для приложений и игр
ASO Аудит для приложений и игр
 
ASO для iOS 11 (продвижение In-App Prurchases)
ASO для iOS 11 (продвижение In-App Prurchases)ASO для iOS 11 (продвижение In-App Prurchases)
ASO для iOS 11 (продвижение In-App Prurchases)
 
ASO для iOS 11
ASO для iOS 11ASO для iOS 11
ASO для iOS 11
 
AppFollow митап в Москве
AppFollow митап в МосквеAppFollow митап в Москве
AppFollow митап в Москве
 
ASO Best Practices 2016
ASO Best Practices 2016ASO Best Practices 2016
ASO Best Practices 2016
 
То, что русскому — ФРИИ, финну — Startup Sauna. Опыт прохождения акселерации ...
То, что русскому — ФРИИ, финну — Startup Sauna. Опыт прохождения акселерации ...То, что русскому — ФРИИ, финну — Startup Sauna. Опыт прохождения акселерации ...
То, что русскому — ФРИИ, финну — Startup Sauna. Опыт прохождения акселерации ...
 
Аналитика приложений конкурентов в Google Play
Аналитика приложений конкурентов в Google PlayАналитика приложений конкурентов в Google Play
Аналитика приложений конкурентов в Google Play
 
ASO FAQ
ASO FAQASO FAQ
ASO FAQ
 
ASO: Best Practices 2015
ASO: Best Practices 2015ASO: Best Practices 2015
ASO: Best Practices 2015
 
AppFollow Demo Day ФРИИ
AppFollow Demo Day ФРИИAppFollow Demo Day ФРИИ
AppFollow Demo Day ФРИИ
 
Конкурентный анализ мобильных приложений
Конкурентный анализ мобильных приложенийКонкурентный анализ мобильных приложений
Конкурентный анализ мобильных приложений
 
Аналитика приложений конкурентов
Аналитика приложений конкурентовАналитика приложений конкурентов
Аналитика приложений конкурентов
 
Аналитика магазинов приложений
Аналитика магазинов приложенийАналитика магазинов приложений
Аналитика магазинов приложений
 
Аналитика мобильных приложений
Аналитика мобильных приложенийАналитика мобильных приложений
Аналитика мобильных приложений
 
Анализ приложений конкурентов
Анализ приложений конкурентовАнализ приложений конкурентов
Анализ приложений конкурентов
 
ASO оптимизация мобильных приложений: «Что такое хорошо и что такое плохо?»
ASO оптимизация мобильных приложений: «Что такое хорошо и что такое плохо?»ASO оптимизация мобильных приложений: «Что такое хорошо и что такое плохо?»
ASO оптимизация мобильных приложений: «Что такое хорошо и что такое плохо?»
 
Продвижение мобильных приложений: с чего начать?
Продвижение мобильных приложений: с чего начать?Продвижение мобильных приложений: с чего начать?
Продвижение мобильных приложений: с чего начать?
 
Основной продукт vs. мобильный на примере Ostrovok.ru
Основной продукт vs. мобильный на примере Ostrovok.ruОсновной продукт vs. мобильный на примере Ostrovok.ru
Основной продукт vs. мобильный на примере Ostrovok.ru
 
ASO оптимизация и продвижение мобильных приложений
ASO  оптимизация и продвижение мобильных приложенийASO  оптимизация и продвижение мобильных приложений
ASO оптимизация и продвижение мобильных приложений
 

Почему Mojolicious?