• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Mojoliciousでつくる! Webアプリ入門
 

Mojoliciousでつくる! Webアプリ入門

on

  • 9,313 views

YAPC::Asia 2013

YAPC::Asia 2013
2013/09/21
Yusuke Wada a.k.a. yusukebe

Statistics

Views

Total Views
9,313
Views on SlideShare
6,636
Embed Views
2,677

Actions

Likes
21
Downloads
26
Comments
0

17 Embeds 2,677

http://yusukebe.com 1235
http://yapcasia.org 1113
http://cloud.feedly.com 203
https://twitter.com 71
http://digg.com 13
http://www.feedspot.com 12
http://u.throttleapp.me 7
http://localhost 6
http://www.google.co.jp 4
http://summary 4
https://www.google.co.jp 2
http://cache.yahoofs.jp 2
http://www.newsblur.com 1
http://webcache.googleusercontent.com 1
http://s.deeeki.com 1
http://feedly.com 1
http://nuevospowerpoints.blogspot.com 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

CC Attribution License

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Mojoliciousでつくる! Webアプリ入門 Mojoliciousでつくる! Webアプリ入門 Presentation Transcript

    • Mojoliciousでつくる! Webアプリ入門 2013/09/21 YAPC::Asia 2013 Yusuke Wada a.k.a. yusukebe Some papix photos are in this slides.Thanks to papix!
    • イントロダクション
    • 自己紹介 • 和田裕介 1981/12/23 生 • 慶應義塾大学制作メディア研究科修了 • 株式会社ワディット代表取締役 • 株式会社オモロキ取締役兼最高技術責任者 • http://yusukebe.com/ or @yusukebe
    • メインワーク
    • 問いかけ
    • Perlは大規模Webサービス で使われているが... 初心者がWebアプリに入門する資料が少ない...?
    • あえて去年を振り返る 「新しい」を生み出すためのWebアプリ開発とその周辺
    • 何をつくるかは分かった そのための 実装について 本日の主題
    • 対象オーディエンス • Webアプリケーションをつくりたい方 • アイデアはあるが実装できない... って方 • 最近のWAFについて知りたい方 • Web Application Framework = WAF • Mojoliciousを使った具体的なアプリ構成を 知りたい方
    • 方針 当たり前に使っている概念、実装、キーワード 噛み砕いて解説 => GoogleやCPANで検索できるように! 実はすごく周辺からは分かりにくい...?
    • アジェンダ • 例題:占いアプリについて • WebアプリケーションとFramework • Mojoliciousの紹介 • Mojolicious::Liteを使う • より実践的なアプリへ • CPANモジュールとの組み合わせと工夫 • 今後へ
    • 0. 例題:占いアプリについて
    • 名前に応じて占い結果を出す • 占い結果はまず3種類 • 良い事が起こるでしょう • 出会いがあるかも? • 不幸になります • 入力された名前に対して必ず同じ結果 • yusukebe => 「出会いがあるかも?」
    • ハッシュ関数 my $name = "yusukebe"; my $max = 3; my $number = 0; # 文字列を一文字ずつ分解 for my $char (split //, $name) { # 文字に対応する数値を得る $number += ord $char; } # 想定される最大値で割った余りを得る my $result = $number % $max; print "$resultn"; 文字列 数値 固定値で割る 余りが結果
    • スクリプトで実現する ようは診断メ○カーみたいな?
    • 1. WebアプリケーションとFramework
    • Webアプリケーションを定義する Webが誰かと特徴的な インタラクション をする場合 Webアプリケーション
    • Webのインタラクション Web アプリケーション ユーザー 例えば自分の名前を 入力する 占いの結果を見る JSの動作 外部のWeb API ミドルウェア etc. ブラウザ プログラム スマホアプリ
    • Web Application Framework • 通称 WAF(ワッフ) • 例えば Ruby on Rails • Webアプリケーションをつくるための土台 • MVCモデルに基づく場合が多い MVCってなんぞー?
    • Model View Controller MVC MVCである意味は...?
    • MVC以前
    • 何がイケてないって? • 色々混じってる • ヘッダー出力 • ロジック処理 • HTMLの描画 • ファイルごとにルーティングする • 重複が起こる *CGIはデプロイ方法の 一つなのでCGI自体が 良くないわけではない
    • 愚直に.cgiを書くと use CGI qw/param header/; my $name = param('name'); my @list = qw/良い事が起こるでしょう 出会いがあるかも? 不幸になります/; my $num = 0; $num += ord ($_) for split //, $name; my $index = $num % scalar @list; my $message = $list[$index]; print header('text/html; charset=utf-8'); print "<html><body>"; print "<center><b>$message</b></center>"; print "</body></html>";
    • HTMLだけでも分離させると... use CGI qw/param header/; use Text::MicroTemplate qw/render_mt/; use Data::Section::Simple qw/get_data_section/; my $name = param('name'); my @list = qw/良い事が起こるでしょう 出会いがあるかも? 不幸になります/; my $num = 0; $num += ord ($_) for split //, $name; my $index = $num % scalar @list; my $message = $list[$index]; my $template = get_data_section('index.mt'); my $html = render_mt($template, $message)->as_string(); print header('text/html; charset=utf-8'); print $html; __DATA__ @@ index.mt <html> <body> <center><b><?= $_[0] ?></b></center> </body> </html>
    • 冗長になるが 見通しがよくなる! さらにテンプレートをファイルに分けると... メンテナンス性、再利用性の向上 冗長性はフレームワークが吸収してくれる?
    • とりあえずMVCで考える意味 • 混在している固まりを役割で分ける • 理解をすれば冗長になるが開発効率が上がる
    • "分けるとは分かること"
    • 切り分け方 1. Router 2. Controller 3. Model / Logic 4. DB層 / OR Mapper 5. View / Static files ビジネスロジックを扱う 出力や見た目に関する部分 個別のリクエストに基づく処理 データベースにまつわる URL/METHODに応じて振り分ける
    • 役割を分けること = フレームワーク的思考へ
    • 処理の流れ Router Controller Model / Logic DB / OR Mapper View 1. リクエスト 2. ディスパッチ 3. モデル呼び出し 4. DB呼び出し 5. DB結果返却 6. 結果 7. レンダリング 8. HTMLなど 9. レスポンス
    • PerlのWAF達 • Catalyst • Dancer • Amon2 • Kossy • Pickles • Voson • Mojolicious • 自作WAF
    • 自作WAFと既存WAF • MVC?を実現するモジュールは揃っている • Plack::Request • Router::Simple • Text::Xslate • ただアプリを書きながらWAFもはキツい • 勉強用に車輪の再発明は多いに歓迎 • でもとりあえずWAFを使いましょうね ♥
    • 2. Mojoliciousの紹介
    • Mojolicious ! • 属に言う「軽量WAF」の一種 • 最新Ver.は「4.35」2013年9月12日時点 • 作者は「Sebastian Riedel」氏
    • 特徴1. VCだけサポート • Routing / Controller • デフォルトではMojo::Templateを使うView • のみサポートし「Model」は対象外 Mojo::Baseその他でクラスつくったりOR Mapper 使ったりして自力で実装してね ♪ っていう... 逆にそれがいい Model/Logic層はWebから切り離すべき
    • 特徴2. Not full-stack but full-stack Ruby on Rails DBを扱うまで全てこれ一つで出来る フルスタック Mojolicious HTTPのRequestやUserAgentまで Mojoliciousで使うライブラリが全て自作 フルスタック コア以外のCPANモジュールに依存しない!
    • $ cpanm Mojolicious
    • Mojoliciousなら一発
    • 特徴3. その他 • アップデートが頻繁 $self->render_json( $ref ); # 4.00 で廃止 # => $self->render( json => $ref ); ただし依存が無いのでMojoliciousだけ追っていればよい • Mojolicious::Lite を使えばファイル一つで • 工夫すればCGIでも動作可能 • Perl 5.10.1 以上必須、5.16 以上を推奨 • 開発用サーバmorbo、本番用hypnotoad • もちろんPSGI互換
    • 小さなアプリから大きなWebアプリまで 徐々に学べるフレームワーク Mojolicious::Lite Mojolicious CPANモジュールの組み合わせ
    • 3. Mojolicious::Liteを使う
    • mojoコマンドによるスケルトン $ mojo generate lite_app myapp.pl Mojolicious::Lite
    • はじめてのMojolicious::Lite #!/usr/bin/env perl use Mojolicious::Lite; get '/' => sub { my $self = shift; $self->stash->{message} = 'Hello Mojo!'; $self->render('index'); }; app->start; __DATA__ @@ index.html.ep <html> <body> <p><%= $message %></p> </body> </html> Controllerに該当 View(テンプレート) Routingしてる
    • 立ち上げ方 $ morbo -l "http://*:5000" myapp.pl morboを使う $ plackup -p 5000 myapp.pl plackupで立ち上げる
    • Hello World から学ぶ get '/' => sub {}; ルーティングとコントローラ GET http://localhost:5000/ get '/entry/:id' => sub { my $entry_id = $self->stash->{id}; }; post '/entry' => sub {};POST http://localhost:5000/entry GET http://localhost:5000/entry/1
    • Hello World から学ぶ get '/' => sub { my $self = shift; $self->stash->{message} = 'Hello Mojo'; ...; } テンプレートにデータを渡す $self->render('index'); # index.html.ep を描画 ...; <p><%= $message %></p> テンプレートの記述とレンダー
    • もちろん占いアプリも!
    • Short live coding !?
    • #!/usr/bin/env perl use Mojolicious::Lite; use utf8; ...; get '/' => sub { my $self = shift; $self->render('index'); }; ...; @@ index.html.ep <p>名前を入力してください</p> <form action="/result"> <input type="text" name="name" /> <input type="submit" value="占う" /> </form> トップページを描画
    • ...; get '/result' => sub { my $self = shift; my $name = $self->req->param('name'); my @list = qw/良い事が起こるでしょう 出会いがあるかも? 不幸になります/; my $num = 0; $num += ord ($_) for split //, $name; my $index = $num % scalar @list; $self->stash->{message} = $list[$index]; $self->stash->{name} = $name; $self->render('result'); }; ...; @@ result.html.ep <p><%= $name %>さんの結果「<%= $message %>」</p> 結果を出力
    • Controller内での操作 • 全ては「$self」のメソッドを扱う my $value = $self->req->param('key'); $self->render('entry'); $self->render( json => { key => $value } ); Mojolicious::Controller を継承するのでそのドキュメントを読めばOK! $self->redirect_to('/');
    • Mojo::Template周り • Perl-ish templates => Perl書ける! % for my $entry (@$entries) { <h2><%= $entry->{title} %></h2> % } Mojo::Template / Mojolicious::Plugin::DefaultHelper • テンプレート向けhelper @@ index.html.ep % layout 'default'; Hi, <%= $name %> @@ layouts/default.html.ep <html> <body><%= content %></body> </html>
    • Mojolicious::Liteアプリを拡張する • public/ => 静的ファイルを置く • templates/ => テンプレートファイルを独立 ./ !"" myapp.pl !"" public/ #   !"" css/ #   !"" favicon.ico #   !"" images/ #   %"" js/ %"" templates/ !"" layouts/ #   %"" default.html.ep %"" root/ %"" index.html.ep
    • 4. より実践的なアプリへ
    • Mojolicious::Liteだと1ファイルがでかくなるよー そこで ::Lite じゃないMojoliciousアプリ! モジュールをいい感じに分けてつくれる
    • Mojoliciousアプリをつくるコツ • $ mojo generate app MyApp では無く MyApp::Web みたいなネームスペースで $ mojo genearate app Uranai::Web • なぜならUranaiがWeb層だけではないかも • Uranai::Model / Uranai::Logic • Uranai::CLI
    • だいたいこんな構成 ./ !"" Uranai/ #   !"" DB/ #   #   %"" Schema.pm #   !"" DB.pm #   !"" Model/ #   #   %"" OneModel.pm #   !"" Web/ #   #   %"" Controller/ #   #   %"" Root.pm #   %"" Web.pm %"" Uranai.pm DBレイヤー / Teng etc. ビジネスロジック / Perl Module Webレイヤー / 主にControllerとルーティング Uranai.pm では パス解決と設定ロードを実装
    • ::Liteからの移行 #!/usr/bin/env perl use Mojolicious::Lite; get '/' => sub { my $self = shift; $self->stash->{message} = 'Hello Mojo!'; $self->render('index'); }; app->start; __DATA__ @@ index.html.ep <html> <body> <p><%= $message %></p> </body> </html> lib/Uranai/Web.pm lib/Uranai/Web/Controller/* Mojolicious::Controllerを継承 templates/ Mojo::Templateに準ずる
    • すんなり移行出来る!
    • 占いアプリを実装してみる
    • 実装方針 • 占いのロジック部分をModelとして切り出す • Uranai::Model::Uranai • それをControllerから適宜呼び出す • ViewはMojolicious::Liteと同じものを 別ファイルにする
    • Uranai::Model::Uranai package Uranai::Model::Uranai; use Mouse; has 'list' => ( is => 'ro', isa => 'ArrayRef[Str]', default => sub { [qw/良い事が起こるでしょう 出会いがあるかも? 不幸になります /]} ); sub uranau { my ($self, $name) = @_; my $num = 0; $num += ord ($_) for split //, $name; my $index = $num % scalar @{$self->list()}; return $self->list->[$index]; } __PACKAGE__->meta->make_immutable();
    • ModelはCLIからも使える use Uranai::Model::Uranai; use feature 'say'; my $uranai = Uranai::Model::Uranai->new; say $uranai->uranau('yusukebe'); ってことは単体でテスト出来る!
    • Uranai::Web::Controller::Root package Uranai::Web::Controller::Root; use Mojo::Base 'Mojolicious::Controller'; use Uranai::Model::Uranai; sub index { my $self = shift; $self->render('index'); } sub result { my $self = shift; my $name = $self->req->param('name'); return $self->redirect_to('/') unless $name; my $uranai = Uranai::Model::Uranai->new; my $message = $uranai->uranau($name); $self->stash->{message} = $message; $self->render('result'); } 1;
    • アプリをつくるフロー • Modelを書く • (テストする) • Routing / Controller を書く • テンプレートを書く • テストサーバを起動しておく • ブラウザで確認 • 繰り返し...
    • 5. CPANモジュールとの組み合わせと工夫
    • Mojoliciousだけでは足りない • CPANモジュールを組み合わせてつくる • Like LEGO blocks Mojolicious OR Mapper FormValidator FillInForm etc.
    • use FormValidator::Lite; • 入力値の妥当性をチェックする • 例:メールアドレス、郵便番号、文字数 FormValidator::Lite->load_constraints(qw/Japanese Email/); my $validator = FormValidator::Lite->new($self->req); my $res -> $validator->check( name => [qw/NOT_NULL/], mail => [qw/EMAIL/], { mails => [qw/mail mail_confirm/] } => ['DUPLICATION'] ); if($validator->has_error) { $self->stash->{messages} = $validator->get_error_messages(); return $self->render; } ...;
    • use Teng; • データベースを操作する OR Mapper • とってもシンプル • Controllerからは操作せずModelから触る my $teng = Teng::Schema::Loader->load( dbh => $dbh, namespace => 'Uranai::DB', ); my $row = $teng->insert(result => { text => 'あなたは結婚出来ません', });
    • DBを用いた占いアプリの応用 • 固定だった3つの選択肢を増やせるようにしたい
    • ちなみにやったこと CREATE TABLE result ( id INT UNSIGNED AUTO_INCREMENT, text VARCHAR(200) NOT NULL, created_at DATETIME NOT NULL, PRIMARY KEY (`id`) ); 1. DBをつくって... lib/Uranai/DB.pm lib/Uranai/DB/Schema.pm 2. TengのDB/スキーマつくって... lib/Uranai/Model/Uranai.pm 3. Modelから操作するようにして... lib/Uranai/Controller/Root.pm 5. Controllerから呼び出す templates/root/index.html.ep 6. Viewの変更 t/01_model.t 4. 簡単なテスト書いて... できた!
    • その他実践で使ってるモジュール • HTML::FillInForm::Lite • Data::Validator • Mouse • SQL::Maker • Carton • Devel::NYTProf / Devel::KYTProf • Test::mysqld • Harriet • Cinnamon • Server::Starter • Starman / Starlet • etc.... Thanks to great Module Authors !
    • Tips
    • DELETE/PUTを擬似的にサポートさせる $self->hook( before_dispatch => sub { my $c = shift; if($c->req->method eq 'POST' && $c->req->param('_method')) { my $methods = [qw/GET POST PUT DELETE/]; if ( grep { $_ eq uc $c->req->param('_method') } @$methods ) { $c->req->method( $c->req->param('_method') ); } } } ); my $r = $self->routes; $r->delete('/entry/:id')-> to( controller => 'Entry', action => 'delete' );
    • helperでFillInFormをお手軽に # Uranai::Web $self->helper( render_fill => sub { my ($self, $name) = @_; my $html = $self->render(template => $name, partial => 1); return $self->render( text => HTML::FillInForm::Lite->fill($html, $self->req->params), format => 'html' ); } ); # Uranai::Web::Controller::* sub form { my $self = shift; ...; if ($validator->error) { $self->stash->{messages} = $validator->get_error_messages(); return $self->render_fill('form'); } }
    • Uranai->config(); # Uranai sub config { my $mode = $ENV{PLACK_ENV} || 'development'; my $fname = File::Spec->catfile( Uranai->base_dir() , $mode . '.pl' ); my $config = undef; if( -f $fname ){ $config = do $fname or die "Cannnot load configuration file: $fname"; }else{ die "Cannot find configuration file: $fname"; } return $config; }
    • Mojoliciousのセッションについて • デフォルトはクライアントにクッキーとして保持 • 気に入らない場合は... • Plack::Middleware::Session • 自作セッション管理
    • 6. 今後へ
    • 紹介したこと • WAFとMVC的な構成について • 役割を適切に分けることでスッキリと • 対応するMojoliciousを使った実装 • 占いアプリを例にあげた
    • Webアプリをつくるには? • 例えば今回の占いアプリ • Mojolicious::Liteで実装してみる • 出来た!俺ってばスゲー体験 その1 • Mojoliciousアプリで拡張してみる • 出来た!俺ってばスゲー体験 その2 • Tengを学習し占いのパターンを増やす • 出来た!俺ってばスゲー体験 その3
    • 俺ってばスゲー体験 少しずつ"動いて" "分かる"
    • 扱わなかった主な点 • よりツッコんだMojoliciousの使い方 • テスト => Test::More / Test::Mojo • 生に近いDB/SQL操作 • その他ミドルウェア => memcached / Redis • デプロイ => サーバ構成 / アプリサーバ • パフォーマンス計測、チューニング • Perl以外のこと => JavaScript / CSS / HTML
    • まとめ
    • Mojoliciousではじめよう • 薄いWAFゆえ理解しやすい • Mojolicious::Lite のように少しずつつくれる • 他のWAFにも応用出来る 徐々に学べるフレームワーク
    • キーワードは... 分けることで分かる 少しずつやろう
    • 終わり ご質問は個別に!