• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
「モダンPerl入門」の入門
 

「モダンPerl入門」の入門

on

  • 7,547 views

株式会社ガイアックスでは、若手メンバーが多いながらも、新しい技術を取り入れたプロダクト作りに取り組んでおります。

株式会社ガイアックスでは、若手メンバーが多いながらも、新しい技術を取り入れたプロダクト作りに取り組んでおります。
今回は、Catalyst5.8や、CatalystのAPI化といったトピックを、プロダクトとして実装したときに出てきた問題点とその解決策についてお話しします。

Statistics

Views

Total Views
7,547
Views on SlideShare
7,510
Embed Views
37

Actions

Likes
4
Downloads
42
Comments
0

3 Embeds 37

http://www.slideshare.net 29
http://s.deeeki.com 7
http://www.linkedin.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

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

    「モダンPerl入門」の入門 「モダンPerl入門」の入門 Presentation Transcript

    • 「モダンPerl入門」の入門 Songhee Han Kazuya Shono
    • 自己紹介 • 韓 松熙(song) • 韓国出身のPerlエンジニア • Perl歴4年目のnewbieです! • 荘野 和也(miniturbo) • SBMカウンタの開発者 • Perl歴半年のnewbieです! 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 2
    • サービス紹介 • スクールガーディアン • 世界初の学校裏サイト・ネットいじめ対策サービス • インターネット上からネットいじめに関する書き込みなどを収集 し学校に対策を提案するサービス • 元々手動でこなしていたサービスを自動化することに 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 3
    • プロジェクトの紹介 • スクールガーディアンツール • 掲示板やプロフなどから特定の学校の学校裏サイトの情報を 収集するツールです • 学校の先生が内容を確認できるように、サイト画面全体のスク リーンショットや投稿データを取得できます 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 4
    • モダンPerl との出会い 2008年9月 2009年1月 2009年4月 2009年7月 2009年9月 モダンPerl Catalyst5.8 YAPC::Asia 入門発売 リリース モダンPerl の入門の入門 モダン Perl界隈 JPAセミナー#1 モダンPerlの現場 Catalyst プロジェクト 企画 5.7ベースで Catalyst 5.8で開発 スケジュール 調査/設計 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 5
    • Catalyst & API 設計 Presented by Songhee Han
    • アプリケーションの構成 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 7
    • アプリケーションの分割 • Catalyst • SchoolG::Client (エンドユーザ機能) • SchoolG::Work (管理者機能) • ジョブ • SchoolG::Batch ( TheSchwartz Job ) • 共通 • SchoolG (共有モジュール/API) 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 8
    • フォルダ構造 app_root/ SchoolG-Client/ lib/ root/ CatalystApp script/ template/ SchoolG-Work/ lib/ root/ CatalystApp script/ template/ SchoolG-Batch/ lib/ script/ バッチ t/ SchoolG/ config/ extlib/ lib/ 共通部分 script/ t/ template/ 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 9
    • 実装 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 10
    • 使いたかった技術 • Catalyst 5.8 + Moose • API • Web::Scraper • TheSchwartz • local::lib 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 11
    • Catalyst 5.8 • local::libで運用 • 開発環境でCatalyst5.7と5.8を共存させたかった • Catalyst::UpgradingのPODを参考にした • Catalystをextendsしていた • Pluginは極力使わないようにした 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 12
    • 最小限のPlugin • ログイン関連 • Catalyst::Plugin::Authentication • Catalyst::Plugin::Authorization::Roles • Session関連 • Catalyst::Plugin::Session • Catalyst::Plugin::Session::Store::Memcached • Catalyst::Plugin::Session::State::Cookie • その他 • Catalyst::Plugin::FillInForm 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 13
    • API化までの試行錯誤 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 14
    • APIへの第一歩 • モダンPerl入門 これをより汎用的にして他のスクリプトからも呼べるようにするには、$c->model() が呼び出された時にCatalyst依存のMyApp::Model::Userではなく単体で 動作するオブジェクトを返すようにしてしまえばいいのです。 「モダンPerl入門」 より引用 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 15
    • Modelの分離 • Controllerにロジックを書いていた時代 • Controllerの見通しが悪くなっていった • Controllerからロジックを分離する • ロジックはModelに切り出した • 但し、ModelはCatalystに依存したまま • Modelからロジックを分離する • Model::Adaptorを利用してModelとロジックをマ ッピングさせた 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 16
    • Modelの分離 • Model::Adaptorで一つ一つマッピングするの は意外と大変 • Model::MultiAdaptorでつなぐようにした 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 17
    • Modelの分離(API) package SchoolG::Work::Model::API::Logic; use strict; use warnings; use parent 'Catalyst::Model::MultiAdaptor'; 1; 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 18
    • Modelの分離(YAML) Model::API::Logic: package: 'SchoolG::API::Logic' lifecycle: Singleton except: - 'Plugin::Filter' 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 19
    • Modelの分離はいったん完成 でも画面を書いていくうちに、 APIの中身がごちゃごちゃに… これでAPI? 分離するだけは何かが足りない… 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 20
    • API? • Wikipedia Application programming interface (API) is an interface in computer science that defines the ways by which an application program may request services from libraries and/or operating systems The API initialism may sometimes be used as a reference, not only to the full interface, but also to one function, or even a set of multiple APIs provided by an organization. Thus, the scope of meaning is usually determined by the person or document that communicates the information. Wikipediaより引用 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 21
    • なら、APIは自分たちなりに 定義して 決めたらいいの? 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 22
    • 社内での議論(1) • 分離したロジックはなぜごちゃごちゃになっている? • APIモジュール群がうまく分類されていなくて、どこにどの処 理が書いてあるのか見失いやすくなった • 結局ロジックを書く場所が変わっただけ? • 分離したロジックを整理していかなければいけない 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 23
    • 社内での議論(1) • WebアプリケーションはDB処理が多い • 至るところで繰り返し呼び出されるDB処理(CRUD処 理)と、一連の処理の流れ(ビジネスロジック)を整理す ることでAPIの見通しがよくなるのではないかと考えた • それぞれどこに、どのように書くべきか? 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 24
    • 社内での議論(2) A案:API≒CRUD処理派 SchoolG API CRUD処理 Logic ビジネスロジック DBIC DBICの接続 B案:API≒ビジネスロジック派 SchoolG DBIC CRUD処理(DBICの接続) API ビジネスロジック 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 25
    • 社内での議論(3) • APIは隠ぺい化された機能 • CRUD処理も ビジネスロジックも、隠蔽化さ れた機能として(どのコンテキストからも呼び 出せるように)実装していきたい • つまりCRUD処理もビジネスロジックもAPI! 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 26
    • 社内での議論(4) SchoolG API Data CRUD処理 最終 案 Logic ビジネスロジック 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 27
    • 実装してフィードバック、 また修正してフィードバック、 … 出来上がってきた! 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 28
    • API API::Data APIの構成 API::Logic API • API::Data • DBへの接続 • SQLの発行 • API::Logic • ビジネスロジック • Dataを呼び出してデータを取得・整形 • API • API::Jobqueue • API::Plugin 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 29
    • API API::Data API::Logic API API::Data 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 30
    • API API::Data API::Data API::Logic API • 役割 • DBへの接続とSQLの発行を行う • 子クラスにCRUD処理を記述する • 機能 • レプリケーション管理 • コネクションプーリング • 返値のデータ形式の統一 • 実装のポイント • 子クラスはテーブル毎に作るようにした 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 31
    • API::DataとDBICのつなぎ方 package SchoolG::API::Data; has _master_schema => ( is => 'rw', required => 1, isa => 'DBIx::Class::Schema', default => sub { # Singleton化した SchoolG::DBIC::Singleton->instance->_master } ); sub master { my ( $self, $table_name ) = @_; $table_name ||= $self->_table_name; return $self->_master_schema ->resultset($table_name); } 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 32
    • API::Dataのデータの返し方 package SchoolG::API::Data; # DBICのsearchは直接利用せずに親クラス(このクラス)のsearchを利用する sub search { my ( $self, $args ) = @_; my $conditions = $args->{conditions}; my $options = $args->{options}; # searchの場合はslaveのschemaを利用 my $resultset = $self->slave->search( $conditions, $options ); # DBICのオブジェクトではなくHashRefかArrayRefで返すようにした $resultset->result_class ('DBIx::Class::ResultClass::HashRefInflator'); return exists $options->{page} && exists $options->{rows} ? { result => [ $resultset->all ], pager => $resultset->pager } : [ $resultset->all ]; } 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 33
    • API API::Data API::Logic API API::Logic 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 34
    • API API::Data API::Logic API::Logic API • 役割 • 子クラスにビジネスロジックを記述する • Catalyst のComponentにはビジネスロジックは極力書かない • CRUD処理はAPI::Dataに記述し、API::Logicから呼び出す • API::Logicの子クラスで行う処理の流れ • Validation処理 • 一連のCRUD処理(トランザクション管理も含む) • CRUD処理結果の加工 • 実装のポイント • Catalystアプリケーション及びジョブの両方からAPI::Logicを呼び出 せるようにした 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 35
    • package SchoolG::API::Logic::ManageStaff; extends 'SchoolG::API::Logic'; sub create { my ( $self, $args ) = @_; my $created_by = delete $args->{created_by}; my $validation = $self->validate( $args->{columns}, 'create' ); return $validation unless $validation->{success}; delete $args->{columns}->{cancel}; delete $args->{columns}->{submit}; $args->{columns}->{staff_created_by} = $created_by; $args->{columns}->{staff_updated_by} = $created_by; my $txn = sub { $self->data('MasterStaff')->create($args); }; $self->txn($txn); } 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 36
    • API API::Data API::Logic API API 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 37
    • API API::Data API::Logic API API • 役割 • API::DataとAPI::Logicの親クラス • 機能 • API::DataとAPI::Logicのアクセサの提供 • API::DataとAPI::Logicで共通メソッドの提供 • 実装のポイント • ジョブからAPIを経由してAPI::DataとAPI::Logic両方を簡 単に呼べるようにした 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 38
    • API API::Data APIの最終形 API::Logic API Catalyst からも ジョブからもAPIを呼べる API Data Catalyst Job DB Logic 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 39
    • 実装:Catalystからの呼び出し 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 40
    • package SchoolG::Work::Controller::Manage::Staff::Create; sub execute : Local { my ( $self, $c ) = @_; my $result = $c->model('API::Logic::ManageStaff') ->create( { columns => $c->req->params, created_by => $c->user->staff_seq } ); $c->res->redirect( $c->uri_for('/manage/staff') ); } 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 41
    • package SchoolG::API::Logic::ManageStaff; extends 'SchoolG::API::Logic'; sub create { my ( $self, $args ) = @_; my $created_by = delete $args->{created_by}; my $validation = $self->validate( $args->{columns}, 'create' ); return $validation unless $validation->{success}; delete $args->{columns}->{cancel}; delete $args->{columns}->{submit}; $args->{columns}->{staff_created_by} = $created_by; $args->{columns}->{staff_updated_by} = $created_by; my $txn = sub { $self->data('MasterStaff')->create($args); }; $self->txn($txn); } 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 42
    • package SchoolG::API::Data::MasterStaff; use Moose; extends 'SchoolG::API::Data'; sub BUILD { my $self = shift; $self->_table_name('MasterStaff'); $self->_table_prefix('staff'); $self->_default_conditions( { staff_delete => 0, staff_seq => { '>' => 1 } } ); $self->_default_options( { order_by => [qw/staff_office/] } ); } 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 43
    • package SchoolG::API::Data; use Moose; has _table_prefix => ( is => 'rw', isa => 'Str', ); sub create { my ( $self, $args ) = @_; my $prefix = $self->_table_prefix; my $columns = $args->{columns}; my $result = $self->master->create($columns); return $result ? { success => 1 } : { success => 0 }; } 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 44
    • 実装:ジョブからの呼び出し 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 45
    • package SchoolG::Batch::Job::CountTask; sub work { my ( $class, $job ) = @_; my $api = SchoolG::API->new(); my $result = $api->logic('CountTask') ->get_profile_count( $job->arg ); $job->completed; } 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 46
    • package SchoolG::API::Logic::CountTask; extends 'SchoolG::API::Logic'; sub get_profile_count { my ( $self, $args ) = @_; undef my $counts; return $counts if $args->{operation} == 3; $counts->{count_profile} = $self->data('DataProfile')->count_for_count_task( { school_seq => $args->{school_seq}, status => 0 } ); return $counts; } 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 47
    • package SchoolG::API::Data::DataProfile; use Moose; extends 'SchoolG::API::Data'; sub count_for_count_task { my ( $self, $args ) = @_; my $conditions; $conditions->{profile_school_seq} = $args->{school_seq}; $self->SUPER::count( { conditions => $conditions } ); } 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 48
    • APIの設計・リファクタを振りかえって 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 49
    • APIを設計しながら • 機能単位の分割するのが難しかった • ルールをすべて守るのが難しかった • リファクタリング5回くらい!!! • まとまってきれいにかけた 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 50
    • まとめ • API設計 • CRUD処理はAPI::Dataに、ビジネスロジックは API::Logicに分けることで見通しがよくなった • Catalystからもジョブからも呼べるような構成となった • Catalyst 5.8 • 今回CatalystのComponentではMooseの機能は使って いない • Mooseの機能をCatalyst内で使わない限りは5.7とほとん ど同じように書くことができた 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 51
    • 今後に向けて • 別のプロジェクトでも通用するのか試してみたい • ガイアックスでは今回APIをこのように考えて実装し てみました • 「APIってこんな考え方もあるよ」などの意見があれ ば是非教えて下さい • パフォーマンス向上などこれからも新しいことに挑戦 していきます 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 52
    • 参考にさせていただきました • Catalyst::Upgrading • http://search.cpan.org/~flora/Catalyst-Runtime- 5.80011/lib/Catalyst/Upgrading.pod • モダンPerlの世界へようこそ - 第6回 Catalyst::Upgrading:検証はお早めに • http://gihyo.jp/dev/serial/01/modern-perl/0006 • Moosification: Catalyst 5.8に移行した際にちょっと 気づいた事。 • http://mt.endeworks.jp/d-6/2009/05/moosification-catalyst- 58.html 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 53
    • まだ終わってないです! Perlじゃないって言われても 気にしません! 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 54
    • おまけ:Canvasでスクリーンショット Presented by Kazuya Shono
    • スクリーンショットの要件 • 学校裏サイトのスクリーンショッ トが欲しかった • サムネイルではなく、ページ全 体のスクリーンショットが必要 だった • 長いページでもページ全体を 撮る必要があった • 実装にあたって、2つのアプ ローチがありました 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 56
    • アプローチ • Xvfb案 • Xvfb(Xの仮想環境)にブラウザを立ち上げて、Xvfb 自体をキャプチャ! • Canvas案 • FirefoxのCanvas要素でWebページをキャプチャ! • まずはXvfbの実装から試してみることに!! 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 57
    • 案① • Xvfbでキャプチャ! • XvfbにFirefoxを起動し、 取得 X Window Dumpで 範囲 ファイルとして保存する • …この案では、 Xの仮 想環境の高さまでしかペ ージのキャプチャが取得 できない! 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 58
    • 案② • Canvasでキャプチャ! • Firefoxで、Canvas要素 へWebサイトを描画し、 それをファイルとして保 存する 取得 範囲 • …コンテンツ量の多いサ イトで、メモリ不足になり、 キャプチャが取得できな いときがある! 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 59
    • 案③ • Canvasでキャプチャ! 取得 • Canvas要素でスクリーン 範囲 ショットを取得 • 工夫として、撮影領域の 高さを固定し、分割して キャプチャするようにした • →高さを固定できるので、 取得 1回のキャプチャのメモリ 範囲 使用量の上限を固定でき る 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 60
    • 結果… • Canvas案を採用しました! • この案をもとに、開いたページのスクリーンショットを 撮るFirefoxのアドオンを制作しました • Canvasでスクリーンショットを取得 • XPCOMでディスクへファイルとして書き込み 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 61
    • 実装 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 62
    • CanvasでWebページを描画 • canvas要素を作成し、Webページを描画する • toDataURL()を用いて描画したデータの data:URLを取得する var canvas = window.document.createElement(‘canvas’); var ctx = canvas.getContext('2d'); // Webページの描画 ctx.drawWindow(window, X開始点, Y開始点, X終了点, Y終了点, ‘rgb(0,0,0)’); ctx.restore(); // 描画したデータをBASE64エンコードしたdata:URLを取得 var url = canvas.toDataURL(‘image/png’); 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 63
    • ファイルの保存 • nsIURIオブジェクトの生成 • nsILocalFileでファイルオブジェクトを生成 • nsIWebBrowserPersistでファイルに保存する var Cc = Components.classes; var Ci = Components.interfaces; // URIオブジェクトの生成 var URI = Cc['@mozilla.org/network/io-service;1'] .getService(Ci.nsIIOService).newURI(url, null, null); // ファイルオブジェクトの生成 var file = Cc["@mozilla.org/file/local;1"] .createInstance(Ci.nsILocalFile); file.initWithPath(保存先のファイルパス); // ファイルに保存 var wbp = Cc['@mozilla.org/embedding/browser/nsWebBrowserPersist;1'] .createInstance(Ci.nsIWebBrowserPersist); wbp.saveURI(url, null, null, null, null, file); 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 64
    • 分割キャプチャ 以上の実装を、ブラウザの高さで 分割して、繰り返しキャプチャするようにした var max = window.document.height; var width = window.outerWidth; var fromY = window.scrollY; var height = window.innerHeight; while (fromY <= max) { var toY = (fromY + height) > max ? max : fromY + height; // キャプチャするメソッド capture(window, width, fromY, toY); if (fromY + height > max) break; fromY = toY; } 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 65
    • 実演 • デモをご覧ください 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 66
    • 参考にさせていただきました • SCRAPBLOG : canvas要素によるWebペー ジのスクリーンショット保存機能 • http://www.xuldev.org/blog/?p=37 • File I/O – MDC • https://developer.mozilla.org/ja/Code_snippets/File_I %2F%2FO 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 67
    • 最後に告知 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 68
    • 仲間募集中! • ガイアックスでは、小さなチームで新しい技術を積極的に取り入れながら 自社プロダクトを開発しています。 • 一緒にチャレンジし、成長していく意欲のある開発者を募集中です。 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 69