JPA セミナー #1 (Session 2 Catalyst 改)

1. Plugin

プラグインの使用を控える
  • 間違った使用方法、実装方法で定義されていることが多い
プラグインの使いどころ
  • リクエストディスパッチのロジックを監視、変更する場合のみ
  • リクエストパラメーターの変換、Catalyst のメソッド実行チェーンの変更を含む
本当に使わない方向で
  • Catalyst::Plugin::* の中にはそもそもプラグインとして実装されるべきでないものが多い
  • コンテキストオブジェクト ($c) にメソッドを追加する実装がそもそも良くない手法
  • 大半のプラグインはモデルとして実装されるべき
  • それ以外はそもそも存在するべきがどうかさえ疑問 (eg.Catalyst::Plugin::Message)
Catalyst::Plugin::Authentication はどうなの?
  • とはいえ、例外はある
  • 認証系とセッション系はプラグインで存在しなければならない意味がある
  • 認証プラグインは一番最初のコントローラーアクションを実行する前にセッションオブジェクトを具現化しておく必要がある
  • Catalyst::Plugin::Authorization はアプリケーションレベルでディスパッチの流れを変える必要があるから--なお以上のことはコントローラーアクションとしても実装可能
  • Root の begin でセッションオブジェクトをインフレートし、ユーザー復元し、ACL 確認も実現できる
$c->user, $c->session
  • Web アプリケーションを実装する上で必要不可欠
  • アプリケーショングローバルで使用
  • プラグインとして実装されることを肯定する必要充分な理由
  • これらのような充分な理由が無い Catalyst プラグインを書いて CPAN に登録すると、Catalyst コアチーム、mst が悲しむ

2. デバッギング

perl 5.10's "Unknown Error"
  • メソッドアトリビュートを読み込む段階での構文エラー発生時によく出るエラー
  • 問題解決のパッチはあるが多くのレポジトリにまだ適応されてない
  • perl -cw で実行すれば構文エラーは明確に表示される
?dump_info=1
  • さまざまな情報を取得できる
  • 環境変数 CATALYST_DEBUG=1 を設定すれば、ソースに -Debug フラグが無くてもデバッグモードで起動する
  • TT なら、[%USE dumper%][%dumper.dump_html(valiable)%] で変数の内容を表示できる
テストを書く
  • Test::WWW::Mechanize::Catalyst で自動テストが大変書きやすくなる
  • Controller のバグ早期発見につながる

3. 設定

config()
package MyApp::Controller::Foo;
__PACKAGE__->config(
	'foo' => 'bar'
);
  • どのコンポーネントも設定用の config アクセサが実装されているが、原則初期化終了前にする
  • 初期化終了後で変更すると予想困難なバグの発生につながる
  • 先行順位を高く設定するには、アプリケーションレベルで設定する
MyApp->config->(
	'Controller::Foo' => {
		'foo' => 'bar'
	}
);
has 'foo' => (
	is  => 'rw',
	isa => 'Str',
);
  • 以前までの Class::Accessor::Fast 方式であれば以下のように
__PACKAGE__->mk_accessors('foo');
$self を使う
  • アクセサを作らないのであれば $self 内でマージされている値を参照することも可能
$self->{'foo'}
  • 同様に myapp_local 設定ファイルに指定があれば、その値がコンポーネントに設定される
  • もしなければ、順番に myapp.conf, アプリケーション, コンポーネント本体の順に適用される値が検索される
これは止めましょう
package Controller::Foo;
__PACKAGE__->config('foo' => 'bar');

sub method : Local {
	my ($self, $c) = @_;
	$c->config->{'Controller::Foo'}->{'foo'};
}
  • 大抵のケースで多分正常に動くが、確実ではない
  • この場合は、 $self->{'foo'} で取り出すのが正しい
package Controller::Foo;
__PACKAGE__->config('foo' => 'bar');

sub COMPONENT {
	my ($self, $c, $config) = @_;
	$config->{'foo'}; # NO!
}
  • 先ほどの例はなんとなく動くが、こちらは多分動かない
常に $self を使おう
  • コンポーネント範囲の設定は $self を利用するのが理想
  • アプリケーションレベルの設定は $c->config から呼び出しても良いが、それも本当にアプリケーション全般に渡って必要な設定に限って使用したほうがよい
Config は使い過ぎでちょうど良い

4. コントローラー

より良いコントローラー
  • 薄ければ薄いほど良い
  • ベースクラスを利用して薄いコントローラーを実装する
ベースクラス
  • 多くのコントローラーは機能ごとに大まかに分類することが出来る
  • 大半は設定から動作をカスタマイズできるように実装することが可能
  • 先ほどの設定の適用方法の延長で、ベースコントローラーから機能を継承しつつ、Model に最大限の機能を委譲することによって、ほとんど空の Controller を実装していくことが可能
設定だけの Controller
  • うまくやれば時には Controller の実装はそれ用の設定を指定するのみのクラスになる
  • DBIC を使って CRUD 操作をするアプリケーションなどはこのような方法で実装することが可能
  • Catalyst::Controller::DBIC::API

5. Chained

基本的な考え方
  • 経路を繋げていく
  • 経路を分けることにより、ログを取ったり、後々変更が容易に
  • Action != URI
  • URI とは公開される URI であって、内部で呼び出されるメソッド自体と関係している必要はない
  • 内部で使用されているだけのメソッド類が URI 定義に影響を及ぼすのは変な感じ
実際に使用されるケース
  • auto アクションは各コンポーネントで1回ずつ実行されるが、Chained の場合、経路で繋げた全てのアクションで実行することが可能
  • Chained に切り替えてから一回も auto を使ったことが無い
  • 実際の Chained の使い方は github にあるサンプルで
  • http://github.com/jshirley/ (catalyst-example-chained)

6. デプロイ方式

External FastCGI
  • ゼロ・ダウンタイム
  • unix ソケットだと、ひとつのソケットで複数アプリケーションを同時に待機させることが可能
  • 新しいバージョンをデプロイする際に、古いバージョンを停止する前に、新しいバージョンを起動すればダウンタイム無しで交換が可能
  • アプリケーションを再起動するのに Web サーバーを再起動する必要がない
  • mod_perl を使わなければいけない用途をちゃんと分かっていないのなら、mod_perl を使う必要はない
HTTP::Prefork
  • C関数にできるだけのことを割り当てているため軽くて安定
  • だが今のところ高負荷もしくは認知度があるサイトでの事例は無い
  • unix ソケットの裏技は使えない
  • ポートを分けることによる分散などでダウンタイムを最低限に抑えることはできる

7. ログ

Catalyst::Log::Log4perl
  • Log::Log4perl の応用性と機能をそのまま $c->log から使用可能
  • Catalyst::Log 以外のログオブジェクトを使う場合、極力標準の debug, info, warning, error, fatal を使うことを推奨
  • 基本的に必要な機能は全て得られるし、それ以上を使うメリットはさほどない
  • 標準メソッドのみを使えば、ログオブジェクトを変更しても、アプリケーション側を変更する必要はない
$c->_dump()
  • あまり知られていない
  • 標準ログメソッドではないのでドキュメントには書いてない
  • Data::Dump を使用して構造体を簡単に読めるように
  • Catalyst::Log と Catalyst::Log::Log4perl の両方に実装
  • 出力レベルは info

8. Action('Classes')

Catalyst 5.7 でアクションクラスとして実装されているものは 5.8 では遥かに便利な Role として再実装されている
Catalyst::Controller::ActionRole
  • ActionClass の概念を Role と入れ替えることができる
  • Role とは、「あるオブジェクトの特徴・動作を表現する」ためのものなので Catalyst の Action を Role で実装するのは自然なこと
sub action : Does('moo')
  • Role の概念をまだ理解してなかったり、使ったことがなければとりあえず今は無視
  • 気になったら Moose::Role を参照のこと
ActionClass は Action の動作内容を Catalyst 外のメソッドにラップすることができる
Catalyst::Action::REST
  • アクションの名前と HTTP リクエストのメソッドを検証し、適切な REST 操作が可能なメソッドに処理を割り振ることが可能
使い時
  • meta と思われる副アクションが本アクション以外に実行する必要のある時に有効
  • 実装例は、アクセスされたページのプロパティを抜き出してスタッシュに保存するなど
  • これは Model でも実装できるが、Action の Role を実装すると構文がすっきりしつつ、リクエストディスパッチにカスタムロジックを注入できるようになる

9. local::lib

Vendor Perl = Not Good
  • ベンダーの提供する Perl に依存すると、ベンダーが管理する Perl のバージョンや、彼らが混入させるバグ等に縛られることもある
  • 酷いわけではないが、良くも無い
  • local::lib の初期導入のコストの低さとメリットを考えると使わない理由がそれほどない
Makefile.PL を使う
  • 管理をきちんとすれば、依存関係のあるモジュール類のインストールやエンドユーザー環境での動作も簡単に保障できる
  • local::lib と一緒に使えばインストールされたパッケージが実際にアプリケーションが使っているパッケージだということも保障できる
  • 複数ユーザーのシステムで同じアプリケーションを複数バージョン運用することも可能
アプリケーション権限はユーザー権限で
  • 極力 root で実行しない
  • 依存関係も root を必要とするべきではない
  • External FastCGI を local::lib でデプロイすれば、サーバー設定以外のアプリケーションのデプロイと実行は root 権限が全くなくても行うことが可能
perl -Mlocal::lib
  • .bashrc や .cshrc に適用する環境変数を表示する
  • $HOME に perl5/ ディレクトリを作成してくれる
  • あとは cpan 経由でインストールすれば自分専用のディレクトリにモジュールがインストールされるようになる
  • 失敗した場合は rm -Rf $HOME/perl5 するだけ
  • 初期設定では $HOME/perl5 だが、それ以外のパスでも複数運用可能

10. 参加

Catalyst に貢献するには
  • 簡単
  • 大半は技術力が必要というわけではない
  • ドキュメントの提供
  • テスト
  • ブログ、宣伝活動
アプリケーションを公開する
  • アプケーション増 = 開発者増
  • 作ったときの経験を語る
  • よりよい開発者がより多く集まる
  • Perl が終わったという意見が浸透してる理由
    • 新しいサイトが Perl を使っていることについてオープンに語らないから
    • Vox は Catalyst で開発されていることを知らない人は多い

JPA セミナー #1 (Session 1 Better Perl Practices 最新 Perl 開発手法のススメ)

自己紹介

ベストではなくベターを目指す

  • どれだけやっても不満は残るもの
  • 最初からうまくやらなくてもいい徐々に上を目指そう
  • 失敗したらよく考え次は成功させる

設計

  • ゴールをはっきりと
  • 背伸びはしないさせない

テスト

  • テストはゴールではない
  • テストではなく API を設計するところから
  • カバレッジ率に執着しない

リファクタリング

  • 避けられない運命
  • やるからには意義のあるものに
  • 失敗から学ぶ

つまりは API

  • 自分のためにシンプルに
  • 使いやすく分かり易く包括的な API を作り生産性をあげバグを減らす

大事なこと

習慣にするには

  • 大変だと思わせない
  • 正しいことはしやすく
  • 間違ったことはしづらく

テストの仕方

  • スキーマクラス
  • アプリケーション
    • Test::Class, Test::FITesque
    • ワークフローテスト

テスト

  • Test::Class
  • Email::Send::Test
  • Test::WWW::Mechanize

設計の仕方

  • まずは動くものを作る
  • 大まかな使い方を考える
  • ひとつひとつゴール(メソッド)を設定する

ユニークじゃなくても良い

  • 同じことをしようとした人は他にもいるはず
  • 似たような機能を探そう
  • Google で他のアルゴリズムを検索したり
  • テストも拝借できる CPAN モジュールがベター

何度も繰り返す

  • 煮つめてかさを減らす
  • それが「秘伝のタレ」になる
  • ソフトは液体、意志ではない
  • ユニットテストAPI のテストが済んだら後は組み立てるだけ
  • 雨だれ石をうがつ

Web != Desktop

  • 環境をコントロールできる
  • インストール先もコントロールできる
  • 遅い?スケーラビリティ!サーバーを追加

ベターアプリのために

ベター Perl

シンプルだけど

my $foo = $request->param->{foo};
my $bar = $request->param->{bar};

良いコードはタイプ数が少し増える

my $data = $request->params;
my $foo = $data->{foo};
my $bar = $data->{bar};

タイプしなければいいってものでもない

my $s = ($api ? $api->params : $request->params) || $request->params;
${"__PACKAGE__::$_"} = ($s->{$_}) for keys %$s;

コードの短さを競うゲームではない

use strict;
use warnings;

Test::Class

  • テストモジュールとしてはベスト
  • chromatic や Ovid もこれについて書いている http://modenperlbooks.com/

Test::Class の理由

  • パッケージベース
  • Test::名前空間 にテストコードをまとめられる
  • .t ファイルより柔軟に書ける(コードの再利用)
  • テストの設定もし易くなる

ベースクラスを利用する

  • 共通の機能をまとめる
  • 変更もかんたん
  • Perl のいいところ(多重継承をサポート)
  • それぞれのクラスでどこが同じでどこが違うか考え構築する

少ない手数でより多くのことを

  • コードをより良く
  • 手数は少なく
  • その後は use Moose

必要なものを使う

  • CPAN にはオブジェクト指向API モジュールがありすぎ
  • Moose はそれらの機能の大部分をカバーしている
  • そこまで必要なければ use Mouse で

Moose でハードコードを減らす

  • 考えられる全てを設定可能に
  • やり方はすぐに分かるようになる
  • やればやるほど楽になる
  • MooseX::SimpleConfig

お気に入り

with 'MooseX::SimpleConfig';
with 'MooseX::Getopt';
has +configfile => (
    default =>
        (
         grep { defined $_ and -f $_ } @places_to_loook
        )[0] || ""
);

複数パスから設定ファイルを抽出し、その中からオブジェクトに has() などで指定した要素を初期化してくれる

まとめ

  • 書くコードを減らす(ベースクラス)
  • 大事なところはテストする
  • Moose(書くコードを減らす)
    • 設定で動作変更可能に

Class::MOP

Moose = ベター API

  • まともなアクセッサー
  • 初期化コードの遅延評価
  • コードは少なく
  • テストは多く

自家製ではない

  • 自分で書くより Moose を使う方が良い
    • 多くの人の手が入っている
    • 膨大な量のテストがある
  • Moose を使えば出来ることが広がる

遅い?

  • Moose は別に遅くない
  • 他のモジュールと比べて遅いだけ
  • しかもほとんどは起動時の問題
    • 線形スケーラビリティ(かかる時間は一定)
    • 遅いと思ったらハードウェアを追加

少しずつ拡張していけば良い

すぐに使いたいなら

  • 型チェック
  • 'ArrayRef[MyObject]' なんてことも可能

注意

  • そのうちなんでもロールに見えてくるようになる
  • それが普通
  • でも誘惑にまけないように
  • それでも必要だと思ったらロールに

JPA セミナー #1 (代表理事挨拶)

活動内容

対企業で新人研修など

その他

  • 大阪で 5/14 に JPA セミナー#2 開催
  • 今週中にアナウンス
  • 企業会員、個人会員、ボランティア、募集中!

補足

研修の料金やコース詳細については、以下に詳しく載っています。
http://japan.perlassociation.org/jpa/service/training

JPA セミナー #1 参加報告まとめ

昨日、4/21 秋葉原 UDXJPA の第一回セミナーがあったので参加してきました。

同時翻訳の受信機が先着40名だったので、心配だったのですが、翻訳したスライドが用意されていたので大分助かりました。
スライドの翻訳だけではなく、プリントアウトされたものも配布していただいたので、会場が広いのもあったので、視力があまり良くない自分としては大分助かりました。

フリースポットもあったので、講演を聴きながら CPAN にアクセスできたりするのも良かったです。

講演終了後、個人的に牧さんに質問させていただきましたが、とても親切に回答してくださいました。牧さんありがとうございます。

各セッション毎にエントリ分けてまとめましたので、ブックマークする方は、今日の日付でブックマークすると良いと思います。

代表理事挨拶
1部 Better Perl Practices 最新 Perl 開発手法のススメ
2部 Catalyst 改

JPA では会員だけでなく、ボランティアも募集しているようなので、Perl コミュニティに貢献するべく、活動に参加して行きたいと思いました。技術的なことでなくとも、手伝えることは色々あるそうなので安心しました。とりあえず、個人会員・ボランティアから初めたいと思います。