Your SlideShare is downloading. ×
Mojoliciousでつくる! Webアプリ入門
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

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

11,942

Published on

YAPC::Asia 2013 …

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

Published in: Technology
0 Comments
21 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
11,942
On Slideshare
0
From Embeds
0
Number of Embeds
23
Actions
Shares
0
Downloads
39
Comments
0
Likes
21
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Mojoliciousでつくる! Webアプリ入門 2013/09/21 YAPC::Asia 2013 Yusuke Wada a.k.a. yusukebe Some papix photos are in this slides.Thanks to papix!
  • 2. イントロダクション
  • 3. 自己紹介 • 和田裕介 1981/12/23 生 • 慶應義塾大学制作メディア研究科修了 • 株式会社ワディット代表取締役 • 株式会社オモロキ取締役兼最高技術責任者 • http://yusukebe.com/ or @yusukebe
  • 4. メインワーク
  • 5. 問いかけ
  • 6. Perlは大規模Webサービス で使われているが... 初心者がWebアプリに入門する資料が少ない...?
  • 7. あえて去年を振り返る 「新しい」を生み出すためのWebアプリ開発とその周辺
  • 8. 何をつくるかは分かった そのための 実装について 本日の主題
  • 9. 対象オーディエンス • Webアプリケーションをつくりたい方 • アイデアはあるが実装できない... って方 • 最近のWAFについて知りたい方 • Web Application Framework = WAF • Mojoliciousを使った具体的なアプリ構成を 知りたい方
  • 10. 方針 当たり前に使っている概念、実装、キーワード 噛み砕いて解説 => GoogleやCPANで検索できるように! 実はすごく周辺からは分かりにくい...?
  • 11. アジェンダ • 例題:占いアプリについて • WebアプリケーションとFramework • Mojoliciousの紹介 • Mojolicious::Liteを使う • より実践的なアプリへ • CPANモジュールとの組み合わせと工夫 • 今後へ
  • 12. 0. 例題:占いアプリについて
  • 13. 名前に応じて占い結果を出す • 占い結果はまず3種類 • 良い事が起こるでしょう • 出会いがあるかも? • 不幸になります • 入力された名前に対して必ず同じ結果 • yusukebe => 「出会いがあるかも?」
  • 14. ハッシュ関数 my $name = "yusukebe"; my $max = 3; my $number = 0; # 文字列を一文字ずつ分解 for my $char (split //, $name) { # 文字に対応する数値を得る $number += ord $char; } # 想定される最大値で割った余りを得る my $result = $number % $max; print "$resultn"; 文字列 数値 固定値で割る 余りが結果
  • 15. スクリプトで実現する ようは診断メ○カーみたいな?
  • 16. 1. WebアプリケーションとFramework
  • 17. Webアプリケーションを定義する Webが誰かと特徴的な インタラクション をする場合 Webアプリケーション
  • 18. Webのインタラクション Web アプリケーション ユーザー 例えば自分の名前を 入力する 占いの結果を見る JSの動作 外部のWeb API ミドルウェア etc. ブラウザ プログラム スマホアプリ
  • 19. Web Application Framework • 通称 WAF(ワッフ) • 例えば Ruby on Rails • Webアプリケーションをつくるための土台 • MVCモデルに基づく場合が多い MVCってなんぞー?
  • 20. Model View Controller MVC MVCである意味は...?
  • 21. MVC以前
  • 22. 何がイケてないって? • 色々混じってる • ヘッダー出力 • ロジック処理 • HTMLの描画 • ファイルごとにルーティングする • 重複が起こる *CGIはデプロイ方法の 一つなのでCGI自体が 良くないわけではない
  • 23. 愚直に.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>";
  • 24. 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>
  • 25. 冗長になるが 見通しがよくなる! さらにテンプレートをファイルに分けると... メンテナンス性、再利用性の向上 冗長性はフレームワークが吸収してくれる?
  • 26. とりあえずMVCで考える意味 • 混在している固まりを役割で分ける • 理解をすれば冗長になるが開発効率が上がる
  • 27. "分けるとは分かること"
  • 28. 切り分け方 1. Router 2. Controller 3. Model / Logic 4. DB層 / OR Mapper 5. View / Static files ビジネスロジックを扱う 出力や見た目に関する部分 個別のリクエストに基づく処理 データベースにまつわる URL/METHODに応じて振り分ける
  • 29. 役割を分けること = フレームワーク的思考へ
  • 30. 処理の流れ Router Controller Model / Logic DB / OR Mapper View 1. リクエスト 2. ディスパッチ 3. モデル呼び出し 4. DB呼び出し 5. DB結果返却 6. 結果 7. レンダリング 8. HTMLなど 9. レスポンス
  • 31. PerlのWAF達 • Catalyst • Dancer • Amon2 • Kossy • Pickles • Voson • Mojolicious • 自作WAF
  • 32. 自作WAFと既存WAF • MVC?を実現するモジュールは揃っている • Plack::Request • Router::Simple • Text::Xslate • ただアプリを書きながらWAFもはキツい • 勉強用に車輪の再発明は多いに歓迎 • でもとりあえずWAFを使いましょうね ♥
  • 33. 2. Mojoliciousの紹介
  • 34. Mojolicious ! • 属に言う「軽量WAF」の一種 • 最新Ver.は「4.35」2013年9月12日時点 • 作者は「Sebastian Riedel」氏
  • 35. 特徴1. VCだけサポート • Routing / Controller • デフォルトではMojo::Templateを使うView • のみサポートし「Model」は対象外 Mojo::Baseその他でクラスつくったりOR Mapper 使ったりして自力で実装してね ♪ っていう... 逆にそれがいい Model/Logic層はWebから切り離すべき
  • 36. 特徴2. Not full-stack but full-stack Ruby on Rails DBを扱うまで全てこれ一つで出来る フルスタック Mojolicious HTTPのRequestやUserAgentまで Mojoliciousで使うライブラリが全て自作 フルスタック コア以外のCPANモジュールに依存しない!
  • 37. $ cpanm Mojolicious
  • 38. Mojoliciousなら一発
  • 39. 特徴3. その他 • アップデートが頻繁 $self->render_json( $ref ); # 4.00 で廃止 # => $self->render( json => $ref ); ただし依存が無いのでMojoliciousだけ追っていればよい • Mojolicious::Lite を使えばファイル一つで • 工夫すればCGIでも動作可能 • Perl 5.10.1 以上必須、5.16 以上を推奨 • 開発用サーバmorbo、本番用hypnotoad • もちろんPSGI互換
  • 40. 小さなアプリから大きなWebアプリまで 徐々に学べるフレームワーク Mojolicious::Lite Mojolicious CPANモジュールの組み合わせ
  • 41. 3. Mojolicious::Liteを使う
  • 42. mojoコマンドによるスケルトン $ mojo generate lite_app myapp.pl Mojolicious::Lite
  • 43. はじめての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してる
  • 44. 立ち上げ方 $ morbo -l "http://*:5000" myapp.pl morboを使う $ plackup -p 5000 myapp.pl plackupで立ち上げる
  • 45. 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
  • 46. Hello World から学ぶ get '/' => sub { my $self = shift; $self->stash->{message} = 'Hello Mojo'; ...; } テンプレートにデータを渡す $self->render('index'); # index.html.ep を描画 ...; <p><%= $message %></p> テンプレートの記述とレンダー
  • 47. もちろん占いアプリも!
  • 48. Short live coding !?
  • 49. #!/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> トップページを描画
  • 50. ...; 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> 結果を出力
  • 51. Controller内での操作 • 全ては「$self」のメソッドを扱う my $value = $self->req->param('key'); $self->render('entry'); $self->render( json => { key => $value } ); Mojolicious::Controller を継承するのでそのドキュメントを読めばOK! $self->redirect_to('/');
  • 52. 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>
  • 53. Mojolicious::Liteアプリを拡張する • public/ => 静的ファイルを置く • templates/ => テンプレートファイルを独立 ./ !"" myapp.pl !"" public/ #   !"" css/ #   !"" favicon.ico #   !"" images/ #   %"" js/ %"" templates/ !"" layouts/ #   %"" default.html.ep %"" root/ %"" index.html.ep
  • 54. 4. より実践的なアプリへ
  • 55. Mojolicious::Liteだと1ファイルがでかくなるよー そこで ::Lite じゃないMojoliciousアプリ! モジュールをいい感じに分けてつくれる
  • 56. Mojoliciousアプリをつくるコツ • $ mojo generate app MyApp では無く MyApp::Web みたいなネームスペースで $ mojo genearate app Uranai::Web • なぜならUranaiがWeb層だけではないかも • Uranai::Model / Uranai::Logic • Uranai::CLI
  • 57. だいたいこんな構成 ./ !"" 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 では パス解決と設定ロードを実装
  • 58. ::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に準ずる
  • 59. すんなり移行出来る!
  • 60. 占いアプリを実装してみる
  • 61. 実装方針 • 占いのロジック部分をModelとして切り出す • Uranai::Model::Uranai • それをControllerから適宜呼び出す • ViewはMojolicious::Liteと同じものを 別ファイルにする
  • 62. 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();
  • 63. ModelはCLIからも使える use Uranai::Model::Uranai; use feature 'say'; my $uranai = Uranai::Model::Uranai->new; say $uranai->uranau('yusukebe'); ってことは単体でテスト出来る!
  • 64. 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;
  • 65. アプリをつくるフロー • Modelを書く • (テストする) • Routing / Controller を書く • テンプレートを書く • テストサーバを起動しておく • ブラウザで確認 • 繰り返し...
  • 66. 5. CPANモジュールとの組み合わせと工夫
  • 67. Mojoliciousだけでは足りない • CPANモジュールを組み合わせてつくる • Like LEGO blocks Mojolicious OR Mapper FormValidator FillInForm etc.
  • 68. 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; } ...;
  • 69. use Teng; • データベースを操作する OR Mapper • とってもシンプル • Controllerからは操作せずModelから触る my $teng = Teng::Schema::Loader->load( dbh => $dbh, namespace => 'Uranai::DB', ); my $row = $teng->insert(result => { text => 'あなたは結婚出来ません', });
  • 70. DBを用いた占いアプリの応用 • 固定だった3つの選択肢を増やせるようにしたい
  • 71. ちなみにやったこと 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. 簡単なテスト書いて... できた!
  • 72. その他実践で使ってるモジュール • 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 !
  • 73. Tips
  • 74. 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' );
  • 75. 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'); } }
  • 76. 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; }
  • 77. Mojoliciousのセッションについて • デフォルトはクライアントにクッキーとして保持 • 気に入らない場合は... • Plack::Middleware::Session • 自作セッション管理
  • 78. 6. 今後へ
  • 79. 紹介したこと • WAFとMVC的な構成について • 役割を適切に分けることでスッキリと • 対応するMojoliciousを使った実装 • 占いアプリを例にあげた
  • 80. Webアプリをつくるには? • 例えば今回の占いアプリ • Mojolicious::Liteで実装してみる • 出来た!俺ってばスゲー体験 その1 • Mojoliciousアプリで拡張してみる • 出来た!俺ってばスゲー体験 その2 • Tengを学習し占いのパターンを増やす • 出来た!俺ってばスゲー体験 その3
  • 81. 俺ってばスゲー体験 少しずつ"動いて" "分かる"
  • 82. 扱わなかった主な点 • よりツッコんだMojoliciousの使い方 • テスト => Test::More / Test::Mojo • 生に近いDB/SQL操作 • その他ミドルウェア => memcached / Redis • デプロイ => サーバ構成 / アプリサーバ • パフォーマンス計測、チューニング • Perl以外のこと => JavaScript / CSS / HTML
  • 83. まとめ
  • 84. Mojoliciousではじめよう • 薄いWAFゆえ理解しやすい • Mojolicious::Lite のように少しずつつくれる • 他のWAFにも応用出来る 徐々に学べるフレームワーク
  • 85. キーワードは... 分けることで分かる 少しずつやろう
  • 86. 終わり ご質問は個別に!

×