<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Eorzea Lounge</title>
    <link rel="alternate" type="text/html" href="http://blog.eorzea.asia/" />
    <link rel="self" type="application/atom+xml" href="http://blog.eorzea.asia/atom.xml" />
    <id>tag:blog.eorzea.asia,2009-06-28://1</id>
    <updated>2010-12-10T17:03:48Z</updated>
    <subtitle>Eorzea System Works開発日誌 - FF14.nameの開発日誌です。近々ブログを移転する予定です。</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type Pro 4.261</generator>

<entry>
    <title>DBIx::ObjectMapper、または私は如何にして心配するのを止めてData Mapperパターンを愛するようになったか</title>
    <link rel="alternate" type="text/html" href="http://blog.eorzea.asia/2010/12/post_94.html" />
    <id>tag:blog.eorzea.asia,2010://1.94</id>

    <published>2010-12-08T16:34:12Z</published>
    <updated>2010-12-10T17:03:48Z</updated>

    <summary>DBIx::ObjectMapperという、PoEAA(Patterns of ...</summary>
    <author>
        <name>Gardejo</name>
        
    </author>
    
        <category term="雑記" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="amikeco" label="Amikeco" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="cpan" label="CPAN" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="dbic" label="DBIC" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="moosemouse" label="Moose/Mouse" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="orマッパー" label="O/Rマッパー" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="Perl" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.eorzea.asia/">
        <![CDATA[<p><a href="http://search.cpan.org/perldoc?DBIx::ObjectMapper"><code>DBIx::ObjectMapper</code></a>という、PoEAA(<a href="http://www.martinfowler.com/eaaCatalog/">Patterns of Enterprise Application Architecture</a>, <a href="http://capsctrl.que.jp/kdmsnr/wiki/PofEAA/">エンタープライズアプリケーションアーキテクチャパターン</a>)の<a href="http://www.martinfowler.com/eaaCatalog/dataMapper.html">the Data Mapper pattern</a>（<a href="http://capsctrl.que.jp/kdmsnr/wiki/PofEAA/?DataMapper">データマッパーパターン</a>）に則った新手の<a href="http://ja.wikipedia.org/wiki/%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E9%96%A2%E4%BF%82%E3%83%9E%E3%83%83%E3%83%94%E3%83%B3%E3%82%B0">O/Rマッパー</a>に興味を惹かれました。その一因は、現在進行形で開発している<a href="http://eorzea.asia/amikeco">Amikeco</a>に於いて、<a href="http://www.martinfowler.com/eaaCatalog/activeRecord.html">the Active Record pattern</a>（<a href="http://capsctrl.que.jp/kdmsnr/wiki/PofEAA/?ActiveRecord">アクティブレコードパターン</a>）指向である<a href="http://search.cpan.org/perldoc?DBIx::Class"><code>DBIx::Class</code></a>を用いて、ドメインモデルの細かな機微をどこまで表現するか悩んでいることにあります。</p>

<p>本稿では、現在の悩みの詳細、つまり<code>DBIx::Class</code>でテーブル継承系パターンを強引に実現している現状をご紹介しつつ、<code>DBIx::ObjectMapper</code>へ期待を抱くに至った経緯を簡単に記してみます。</p>

<p><ins title="tokuhiromさんのブログへの言及" datetime="2010-12-11T01:21:00+09:00"><em>追記</em> : <a href="http://d.hatena.ne.jp/tokuhirom/20101210/1291941762">tokuhiromさんに素晴らしいご指摘をいただきました！</a>　本稿でSingle Table Inheritanceを実現できないと嘆いていたのは、Active Recordであることそれ自体が原因ではありません。パターンとモジュールをやや混同して書いてしまいましたので、お詫びします。また、その記事では、<code>DBIx::Class</code>でもSingle Table Inheritanceを実現していたとのご紹介をいただいているので、（本文中にも弁解を書いていたように（弱気だなぁ））<code>DBIx::Class</code>の実装というよりも、私の使い方が今ひとつであることが原因のようです。愚直に書いただけでパターンを実現できない現状について、何が直接の原因となっているのかということを、落ち着いて・突き詰めてよく考えるべきであることを悟りました。拙い論考に対して鮮やかな反証をご提示いただいて、感激しています。本当にどうもありがとうございました！</ins></p>

<p><ins title="nekokakさんたちのtweetへの言及" datetime="2010-12-11T01:59:00+09:00"><em>追記</em> : <a href="http://togetter.com/li/77587">nekokakさんやeiskeoishiさんたちの会話</a>は、示唆に富んでいます。要件や現実世界が複雑だからといって、脊椎反射して腕まくりしてホイホイとモデリングをがっつりやるのは、多くの場合は再考の余地がある働き方だと感じます。いかに無理・無駄を省いてシンプルなものにしていくか、勉強を深めて参りたいです。</ins></p>
]]>
        <![CDATA[<h2>モデルを精緻化すればするほどインピーダンスミスマッチが生じる</h2>

<p>いわゆるエンタープライズアプリケーションでは、モデリングを精緻に行えば行うほど、、山のような数のクラスが複雑に絡み合うドメインモデルになりがちです。そのこと自体は<a href="http://ja.wikipedia.org/wiki/%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E9%A7%86%E5%8B%95%E8%A8%AD%E8%A8%88">DDD(ドメイン駆動設計)</a>に鑑みると良い傾向にあります。ところが、それらのオブジェクトをデータストアへ永続化しようとした途端に、めくるめくインピーダンスミスマッチの世界に飛び込むことになります。</p>

<p>それらを解決する方策の一つがO/Rマッパーであり、Perlで最も広く使われているO/Rマッパーの一つが<code>DBIx::Class</code>であるため、<code>Amikeco</code>でもこれまで<code>DBIx::Class</code>を前提として設計・開発を行って来ました。</p>

<p>そうしたこれまでの経験を踏まえた感想は、「O/Rマッパーは<a href="http://ja.wikipedia.org/wiki/%E9%8A%80%E3%81%AE%E5%BC%BE%E4%B8%B8">銀の弾丸</a>ではない」ということです。その論拠は色々ありますが、本稿ではインピーダンスミスマッチへの対応に絞って述べて参ります。</p>

<h2>DBIx::Classでインピーダンスミスマッチを強引に解決する策</h2>

<p>まず、現在の<code>Amikeco</code>での解決法を、ご参考までにご紹介しておきます。これは、DBICでもテーブル継承系パターンを<em>使えないことはない</em>、ということの実証にもなるかも知れません。</p>

<p>PoEAAの第12章で掲げられたObject-Relational Structural patterns（オブジェクトリレーショナル構造パターン）のそれぞれについて、コードとクラス図を用意してみました。それらは<a href="http://gist.github.com/732055">gist: 732055</a>で公開してあります（<a href="http://gist.github.com/gists/732055/download">一式をダウンロード</a>することもできます）。</p>

<h3>備考</h3>

<ul>
<li>私は<a href="http://search.cpan.org/perldoc?Moose"><code>Moose</code></a>厨なので、以下の具体例では<a href="http://search.cpan.org/perldoc?DBIx::Class::Core"><code>DBIx::Class::Core</code></a>を継承したResultクラスを（よせばいいのに）<code>Moose</code>に基づいたクラスで記述しています。</li>
<li>オブジェクトが持つべきデータのバリデーション（検証）を、データストアでのドメイン（この場合は定義域≒型制約の意味）のみに任せず、<a href="http://search.cpan.org/perldoc?Moose::Manual::Types"><code>Moose</code>の型制約</a>を使っています。具体的には、列へのアクセッサーに対して<code>before</code>メソッドモディファイヤーを仕込み、それがミューテーター（セッター）として呼ばれた際の引数の型を（<a href="http://search.cpan.org/perldoc?MooseX::Params::Validate"><code>MooseX::Params::Validate</code></a>によって）検証する、ということをしています。さらに、各クラスにそうした処理を仕込んで回る手間を省くべく、それらを（<a href="http://search.cpan.org/perldoc?MooseX::Role::Parameterized"><code>MooseX::Role::Parameterized</code></a>による）parameterized role（変数化したロール）として括り出しています。
<ul>
<li>型の検証云々については、<a href="http://search.cpan.org/perldoc?DBIx::Class::MooseColumns"><code>DBIx::Class::MooseColumns</code></a>を使うと、アトリビュートを生やす<code>has</code>のオプションとして<code>add_column</code>を使えるので、より宣言的に記述できると思います。ただ、私がこれを評価した当時のバージョンは（<a href="http://search.cpan.org/perldoc?MooseX::DBIC::AddColumn"><code>MooseX::DBIC::AddColumn</code></a>から改名された直後の）<code>0.10</code>でしたので、<code>Moose</code>党<code>lazy</code>派閥でもある私は評価を保留した経緯があります。</li>
</ul></li>
<li>コードは5.8.1以上のPerlと、<code>Moose</code>, <code>DBIx::Class</code>関係のいくつかのCPANモジュールに依存します。<code>bin</code>以下のスクリプトでは5.10.1以上のPerlを要求していますが、これは<code>say</code>や<code>//</code> (defined-or演算子)で無精をしたかったためです。労を厭わなければ勿論5.8.1でも動きます。</li>
</ul>

<p>いずれにせよ、これらの備考は本稿の本筋ではないので、この辺で仕舞いにしておきます。</p>

<h3>Single Table Inheritance</h3>

<p>まずは一番単純な<a href="http://www.martinfowler.com/eaaCatalog/singleTableInheritance.html">the Single Table Inheritance pattern</a>（<a href="http://capsctrl.que.jp/kdmsnr/wiki/PofEAA/?SingleTableInheritance">シングルテーブル継承パターン</a>）です。関連する各クラスが一つのテーブルにマッピングされるというものです。</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="an example implementation for the Single Table Inheritance pattern with DBIx::Class" src="http://blog.eorzea.asia/2010/12/09/single_table_inheritance.gif" width="640" height="370" class="mt-image-none" style="" /></span></p>

<ul>
<li><code>bin/</code>
<ul>
<li><a href="http://gist.github.com/raw/732055/7de1986ff5ac60746ee6f66184dff048045e44e6/single_table_inheritance.pl"><code>single_table_inheritance.pl</code></a></li>
</ul></li>
<li><code>lib/</code>
<ul>
<li><code>MyApp/</code>
<ul>
<li><code>SingleTableInheritance/</code>
<ul>
<li><a href="http://gist.github.com/raw/732055/28db8e53f4a358d491c358e856c1c3aca9d3c8dc/Schema.pm"><code>Schema.pm</code></a></li>
<li><code>Schema/</code>
<ul>
<li><code>Result/</code>
<ul>
<li><a href="http://gist.github.com/raw/732055/e6b0183296737b227745210723b77b2f8b635d10/Bowler.pm"><code>Bowler.pm</code></a></li>
<li><a href="http://gist.github.com/raw/732055/77386f3b80462d366c987ed4187055300d22e67d/Cricketer.pm"><code>Cricketer.pm</code></a></li>
<li><a href="http://gist.github.com/raw/732055/947a4d4870f321cc58d577435406bc85acf99904/Footballer.pm"><code>Footballer.pm</code></a></li>
<li><a href="http://gist.github.com/raw/732055/97379b747ee0a0ff12d87b4a2270a868891d8efc/Player.pm"><code>Player.pm</code></a></li>
</ul></li>
</ul></li>
</ul></li>
<li><code>Role/</code>
<ul>
<li><code>Schema/</code>
<ul>
<li><code>Result/</code>
<ul>
<li><a href="http://gist.github.com/raw/732055/626a3c553c386f8abc74c3be469125782a67486e/Validatable.pm"><code>Validatable.pm</code></a></li>
</ul></li>
</ul></li>
</ul></li>
</ul></li>
</ul></li>
</ul>

<h4>透過的に<code>type</code>を扱う</h4>

<p>このパターンの特徴の一つである<code>type</code>列の制御は素直に行えました。この<code>type</code>列とは、ただ一つのテーブルである<code>players</code>の各行の出自、つまりどのクラスのオブジェクトを格納したものであるかを表現するものです。Resultクラスで以下のように仕込んでおけば、これは簡単に実現できます。</p>

<ul>
<li><code>insert</code>をオーバーライドして、<code>CREATE</code>のタイミングにフックして、<code>type</code>列へ自らの（具象）クラス名を突っ込む</li>
<li><code>update</code>をオーバーライドして、<code>UPDATE</code>のタイミングにフックして、<code>type</code>列が妙な値で上書きされないように（引数であるハッシュリファレンスから<code>type</code>キーを落とすことで）防衛する</li>
</ul>

<h4>抽象クラスで全アトリビュートを持つという乱暴な実装</h4>

<p>ここでは、抽象クラス<code>MyApp::SingleTableInheritance::Schema::Result::Player</code>に<code>add_columns</code>を全て仕込んでおき、これをそれぞれの具象クラスが継承しています。各クラスはすべて<code>__PACKAGE__-&gt;table('players');</code>としてマッピングしています。</p>

<p>抽象クラスが<code>players</code>テーブルに引き摺られてしまっているので、パターン本来のクラス図からは逸脱しています。そのため、例えば<code>Footballer</code>で<code>bowling_average</code>を設定することができてしまう問題があります。</p>

<p>初っ端からオレオレルールを発動してしまうと、クラスの使い方を気をつけてこの問題を回避してしまおうという、身も蓋もない方法もあります。さすがに乱暴過ぎるので、具象クラスで<code>insert</code>, <code>update</code>をフックして、余所様のクラス用の列については受け付けないようにすると良いかも知れません。</p>

<h3>Concrete Table Inheritance</h3>

<p>続いて、理想と現実の均衡が取れた<a href="http://www.martinfowler.com/eaaCatalog/concreteTableInheritance.html">the Concrete Table Inheritance pattern</a>（<a href="http://capsctrl.que.jp/kdmsnr/wiki/PofEAA/?ConcreteTableInheritance">具象テーブル継承パターン</a>）です。具象クラス毎にテーブルが存在し、各クラスの持つアトリビュート全てが当該テーブルにマッピングされるというものです。</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="an example implementation for the Concrete Table Inheritance pattern with DBIx::Class" src="http://blog.eorzea.asia/2010/12/09/concrete_table_inheritance.gif" width="640" height="270" class="mt-image-none" style="" /></span></p>

<ul>
<li><code>bin/</code>
<ul>
<li><a href="http://gist.github.com/raw/732055/e0b578baa5dcdce08a1c81af35b8d5c8dc15ddc4/concrete_table_inheritance.pl"><code>concrete_table_inheritance.pl</code></a></li>
</ul></li>
<li><code>lib/</code>
<ul>
<li><code>MyApp/</code>
<ul>
<li><code>ConcreteTableInheritance/</code>
<ul>
<li><a href="http://gist.github.com/raw/732055/7f560063952e9880be2a647cf4fcfe1d04178295/Schema.pm"><code>Schema.pm</code></a></li>
<li><code>Schema/</code>
<ul>
<li><code>Base/</code>
<ul>
<li><code>Result/</code>
<ul>
<li><a href="http://gist.github.com/raw/732055/edd1d523e05a89dacd7fe2845e43f50917088093/Player.pm"><code>Player.pm</code></a></li>
</ul></li>
</ul></li>
<li><code>Result/</code>
<ul>
<li><a href="http://gist.github.com/raw/732055/74d784f13225889ed12e26f91c177c46df6da7fa/Bowler.pm"><code>Bowler.pm</code></a></li>
<li><a href="http://gist.github.com/raw/732055/35b91aef44c592d66f4a4a00fd08394d5cd5d3ca/Cricketer.pm"><code>Cricketer.pm</code></a></li>
<li><a href="http://gist.github.com/raw/732055/7b20eb9290a4151dcf0d3d2c1ed0c65e9e0c6d77/Footballer.pm"><code>Footballer.pm</code></a></li>
</ul></li>
</ul></li>
</ul></li>
<li><code>Role/</code>
<ul>
<li><code>Schema/</code>
<ul>
<li><code>Result/</code>
<ul>
<li><a href="http://gist.github.com/raw/732055/626a3c553c386f8abc74c3be469125782a67486e/Validatable.pm"><code>Validatable.pm</code></a></li>
</ul></li>
</ul></li>
</ul></li>
</ul></li>
</ul></li>
</ul>

<h4>クラス図通りにできた！　......できた　......できた？</h4>

<p>今回のクラス図はとても綺麗で、寸分の違いもなくパターンを忠実に実装したように見えます。PK（主キー）のための<code>id</code>列は抽象クラス<code>MyApp::ConcreteTableInheritance::Schema::Base::Result::Player</code>にあって然るべきですので、PoEAAにある設計段階のクラス図を実装段階のクラス図として書けば、おそらく十中八九こうなるかと思います。</p>

<p>コードの着目点としては、抽象クラスにある<code>__PACKAGE__-&gt;table('__PLACEHOLDER__');</code>というインチキが挙げられます。基底クラスで<code>__PACKAGE__-&gt;add_columns</code>しておけば、派生クラスはそれらの列を同様に使えるのですが、その<code>add_columns</code>自体は<code>__PACKAGE__-&gt;table</code>が済んでいることを要求するからです。</p>

<p>具象クラス（派生クラス）側では（それぞれのクラスに紐付くテーブルを定義するために）再び<code>__PACKAGE__-&gt;table('footballers');</code>などとするので、怪しげな<code>__PLACEHOLDER__</code>が上書きされるので大丈夫だ、という安易な判断でした。ともあれ求めるスキーマはできたような気がします。</p>

<p>なお、わざわざ具象クラス用の名前空間<code>MyApp::ConcreteTableInheritance::Schema::Result</code>ではなく、<code>MyApp::ConcreteTableInheritance::Schema::Base::Result</code>以下にしたのは、<code>MyApp::ConcreteTableInheritance::Schema</code>で（他のパターンと同様に）<code>__PACKAGE__-&gt;load_namespaces;</code>だけ書きたかったからです。名前空間を混ぜてしまっても、テーブルに紐付くクラスを粒で指定すれば良いので、どちらの道を行くかは好みで決めても構いません。</p>

<p>ともあれ、ほら、なんかうまく行ったっぽいですよ？　一抹の不安はありますけれども！</p>

<h4>ゴミindexの恐怖</h4>

<p>さて、この辺から雲行きが怪しくなって来ます。「怪しげな」「安易な判断」「できたような気がします」などと不安を煽る文言をちりばめましたが、このパターンの最大の泣き所は、やはり<code>__PLACEHOLDER__</code>にありました。</p>

<p>今回の例では、各パターンとも<code>name</code>に対して<code>UNIQUE</code>制約を付けているのですが、<code>SQL::Translator</code>を見たり、DDLを見たり、直接DBを開けたりすれば分かる通り、ゴミindexが張られてしまっているのです。</p>

<p>SQLiteの場合では、<a href="http://gist.github.com/raw/732055/e0b578baa5dcdce08a1c81af35b8d5c8dc15ddc4/concrete_table_inheritance.pl"><code>concrete_table_inheritance.pl</code></a>でも例示していますが、<code>.dump</code>すると以下のような闇を垣間見られます。</p>

<pre><code>... (snip) ...
CREATE UNIQUE INDEX __PLACEHOLDER___name ON bowlers (name);
CREATE UNIQUE INDEX __PLACEHOLDER___name02 ON cricketers (name);
CREATE UNIQUE INDEX __PLACEHOLDER___name03 ON footballers (name);
CREATE UNIQUE INDEX bowlers_name ON bowlers (name);
CREATE UNIQUE INDEX cricketers_name ON bowlers (name);
CREATE UNIQUE INDEX cricketers_name02 ON cricketers (name);
CREATE UNIQUE INDEX footballers_name ON footballers (name);
</code></pre>

<p>なんじゃあこりゃあ！<del>（声の出演：松田優作）</del></p>

<p>しかしこれを落ち着いて考えれば、当たり前ですが道理が通っていて、例えば<code>Footballer</code>の場合では、</p>

<ol>
<li><code>Player</code>クラスが<code>__PLACEHOLDER__</code>テーブルと結び付こうとする</li>
<li><code>Player</code>クラスが<code>add_unique_constraints</code>する（つまり<code>__PLACEHOLDER__</code>テーブルにインデックスがあるものとされ、自動で採番されるインデックス名が<code>__PLACEHOLDER__name</code>などになる）</li>
<li><code>Footballer</code>クラスが<code>Player</code>クラスを継承する</li>
<li><code>Footballer</code>クラスが<code>footballers</code>テーブルと結び付こうとする</li>
<li><code>Footballer</code>クラスが<code>add_unique_constraints</code>を（再度）呼ぶ（今度は<code>footballers</code>テーブルにインデックスがあるものとされ、インデックス<code>footballers_name</code>が追加される）</li>
<li>継承ツリーの末端であるので、以上で<code>Footballer</code>クラスの定義がひとまず完了する（<code>SQL::Translator</code>のデータ構造が安定する）</li>
<li>これを<code>deploy</code>すると、上記の状態がデータストア側へも反映される</li>
</ol>

<p>......というように<code>footballers</code>テーブル用に2回、より深い継承ツリーを辿る<code>bowlers</code>では都合3回も<code>add_unique_constraints</code>が呼ばれることが分かります。</p>

<p><code>SQL::Translator</code>をdumpしてみたり、コードを或る程度追った限りでは、これ以外の明白かつ重大な問題は見つけかねましたが、既にこの段階で敗戦気分が蔓延して来ました。</p>

<h3>Class Table Inheritance</h3>

<p>最後が、理想主義の<a href="http://www.martinfowler.com/eaaCatalog/classTableInheritance.html">the Class Table Inheritance pattern</a>（<a href="http://capsctrl.que.jp/kdmsnr/wiki/PofEAA/?ClassTableInheritance">クラステーブル継承パターン</a>）です。抽象クラスにも具象クラスにも全てテーブルが存在し、派生クラスで特化した（既定クラスに存在しない）アトリビュートのみが当該テーブルにマッピングされるというものです。</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="an example implementation for the Class Table Inheritance pattern with DBIx::Class" src="http://blog.eorzea.asia/2010/12/09/class_table_inheritance.gif" width="640" height="340" class="mt-image-none" style="" /></span></p>

<ul>
<li><code>bin/</code>
<ul>
<li><a href="http://gist.github.com/raw/732055/c64388066dd91bb0e00eec7abbc539afec9f9c02/class_table_inheritance.pl"><code>class_table_inheritance.pl</code></a></li>
</ul></li>
<li><code>lib/</code>
<ul>
<li><code>MyApp/</code>
<ul>
<li><code>ClassTableInheritance/</code>
<ul>
<li><a href="http://gist.github.com/raw/732055/393aea8762a48ac31f17c4536613a621ca69d763/Schema.pm"><code>Schema.pm</code></a></li>
<li><code>Schema/</code>
<ul>
<li><code>Base/</code>
<ul>
<li><code>Result/</code>
<ul>
<li><a href="http://gist.github.com/raw/732055/523995eb516912a106be2966464b14aaf12a862c/Bowler.pm"><code>Bowler.pm</code></a></li>
<li><a href="http://gist.github.com/raw/732055/44767ee9cc4cfa6645d0e261650e6d31c40a7ed4/Cricketer.pm"><code>Cricketer.pm</code></a></li>
<li><a href="http://gist.github.com/raw/732055/af395b17986ace80be2a5a61e5e9ec61742729ab/Footballer.pm"><code>Footballer.pm</code></a></li>
<li><a href="http://gist.github.com/raw/732055/12c413a5a909465fea1a4016b208efc8e632a93e/Player.pm"><code>Player.pm</code></a></li>
</ul></li>
</ul></li>
<li><code>Result/</code>
<ul>
<li><a href="http://gist.github.com/raw/732055/11c296c017ae088872277ff263e71611c2afb83f/Bowler.pm"><code>Bowler.pm</code></a></li>
<li><a href="http://gist.github.com/raw/732055/9ad576d60c2710c1845fc18fd45ecbd4bd36bcc5/Cricketer.pm"><code>Cricketer.pm</code></a></li>
<li><a href="http://gist.github.com/raw/732055/f01bc716722619bd4a90bd6b95aab6e5213db6f5/Footballer.pm"><code>Footballer.pm</code></a></li>
<li><a href="http://gist.github.com/raw/732055/62f578e22d8c1ec0dfd741af8d710361a67e8019/Player.pm"><code>Player.pm</code></a></li>
</ul></li>
</ul></li>
</ul></li>
<li><code>Role/</code>
<ul>
<li><code>Schema/</code>
<ul>
<li><code>Result/</code>
<ul>
<li><a href="http://gist.github.com/raw/732055/626a3c553c386f8abc74c3be469125782a67486e/Validatable.pm"><code>Validatable.pm</code></a></li>
</ul></li>
</ul></li>
</ul></li>
</ul></li>
</ul></li>
</ul>

<h4>コンポジションによって複数テーブル操作を実現</h4>

<p>例えば<code>Bowler</code>を一人追加したい場合には<code>bowlers</code>と<code>cricketers</code>と<code>players</code>をつついて回ることになりますが、これはリレーションで実現するのが手っ取り早いです。<code>ON UPDATE CASCADE</code>や<code>ON DELETE CASCADE</code>の違和感もありません。</p>

<h4>クラスの存在感が重い</h4>

<p>今回も<code>__PLACEHOLDER__</code>の策動があるものの、怪しげなindexは張られません。しかし、テーブルと紐付かない（<code>MyApp::ClassTableInheritance::Schema::Base::Result</code>名前空間の）抽象クラスでビジネスロジック（蹴ったり打ったり投げたりするだけですが）を実装し、テーブルと紐付けるためだけに具象クラスを用意するなど、かなり面倒くさい実装になっています。</p>

<p>面倒くさいというのはすなわちバグの温床であると見ることができるので、これは大いなる不安を引き起こす設計だと断じてしまいたいところです。こんな混沌としたクラス群をちまちまいじっているだけで、気分はたちまち滅入ってしまうことでしょう。</p>

<h4>貴様ッ、その手に抱えている<code>name</code>メソッドは何だ！</h4>

<p>「3つもパターンがあれば、さすがにそのうち1つくらいは満足に実装できるだろう」と思いきや、<code>MyApp::ClassTableInheritance::Schema::Base::Result::Bowler</code>で多くのメソッドが明示的に生えている点が気懸かりです。</p>

<p>実はこのパターンでの落とし穴はここにありました。例えば、なぜ<code>name</code>メソッドを<code>Bowler</code>で実装しなければならないのでしょうか。これもまた落ち着いて考えれば道理は通っていて、</p>

<ol>
<li><code>Bowler</code>に相対するテーブル<code>bowlers</code>には<code>name</code>列が存在しない</li>
<li><code>name</code>列が存在している<code>Player</code>に手を伸ばさなければならない</li>
<li><code>$self-&gt;cricketers-&gt;players-&gt;name</code>として、継承ツリーではなく、リレーションを手繰り寄せる必要がある</li>
</ol>

<p>......というあんばいです。しかも具合の悪いことに、<code>Cricketer</code>に生えている<code>bat</code>メソッドも（よせばいいのに）内部で<code>name</code>を使っているため、<code>Bowler</code>ではこれもオーバーライドしなければなりません。</p>

<p>理論上の継承と物理面の制約との取りなしをドメインレイヤーのクラス内部で隠蔽しているので、クラスを使う側（サービスレイヤーのクラス）ではこうした絡み合いを気にする必要はないのですが、それは結局誰に泣いてもらうかというようなジョーカーの押し付け合いでしかないような気がします。</p>

<p>ああ面倒くさい！　もう止めだ止めだッ！</p>

<h3>結論：欠点に目をつぶる度胸次第</h3>

<p>かようにして、Active Record指向の<code>DBIx::Class</code>を馬鹿正直に使っただけでは、</p>

<ul>
<li>テーブル継承パターンを「使えないことはない」だけで「大船に乗ったつもりで使える」わけでないこと</li>
<li>強引に実装したのであれば、その際に仕込んだ落とし穴に留意しておく必要があること</li>
</ul>

<p>......などを学んで参りました。</p>

<p>もっと上手な方法はいくらでもありそうですが、少なくとも、愚直に取り組むと悲惨な目に遭うことがわかりました。もっとも、<code>after</code>などを使った時点で愚直でも何でもなくて悪足掻きと見ることもできるかも知れません。ともあれPoEAAのクラス図と上述のクラス図を対比してすぐ気付くように、やりたいことのために設計を歪めていることは大変心苦しいです。また、<code>__PACKAGE__-&gt;table('__PLACEHOLDER__');</code>の副作用も把握しきれていません。</p>

<p>こうした浮ついた理解でプロダクトにパターンを適用することは、何としても避けなければなりません。</p>

<p>実際のところ、本業ではとてもそんなことはしていないものの、<code>Amikeco</code>ではがっつり適用してしまっているわけですが......。</p>

<h2>Data Mapperは銀の弾丸になるか</h2>

<p>クラスに生えているアトリビュートとテーブルの列との整合性を力尽くで合わせることが諸悪の根源である（というかO/Rマッパーの使い方を間違えている）のであれば、現状に拘泥せずに、それらが完全にぶった切られた世界のことを知る必要がありそうです。</p>

<p>その世界、つまりData Mapperは必ずしも理想郷ではないかも知れませんが、PoEAAのData Source Architectural Patterns（データソースのアーキテクチャーに関するパターン）でActive Recordと並立して紹介されていることからも分かるように、少なくとも実現可能性評価をしておかなければならない存在にあることは確かでしょう。</p>

<p>実はごく最近に.NETで<a href="http://www.nhibernate.org/"><code>NHibernate</code></a>（Javaで最も有名なO/Rマッパーの一つである<a href="http://www.hibernate.org/"><code>Hibernate</code></a>の.NET版)を使う案件があったので、エンタープライズアプリケーションに於けるData Mapperの威力の片鱗は肌感覚として感じています。</p>

<h2>新星、<code>DBIx::ObjectMapper</code></h2>

<p>そんな折、色々な意味でリハビリ中の折に、YAPC::Asia 2010での<a href="http://twitter.com/eiskeoishi">@eiskeoishi</a>さんによる<a href="http://eisuke.github.com/yapcasia2010/"><code>DBIx::ObjectMapper</code>の発表スライド</a>を拝見して、このData Mapper指向のORMがPerlにもあることを知ったのです。</p>

<p>それではここで、「Object-Relational Structural patterns、どんと来いです」（意訳）としている<code>DBIx::ObjectMapper</code>選手が、こうした問題をたちどころに解決してくれる（らしい）ことを見て回りましょう。</p>

<h3>パターン通りのクラス！</h3>

<p>クラスとテーブルとの紐付けをmapperに任せ、かつ、その紐付けが「全テーブルの列と全クラスのアトリビュートを一旦ご破算にして、それらを粒で紐付けて回る」ものである以上、データストアのことを全く気にせず、クラスをパターン通りに書けることは当然です。POPO(Plain Old Perl Object)は、今こそデータストアの桎梏から逃れ、大空を自由に飛び回ることができるのです。</p>

<p>これだけでも上述の問題の過半は解消しているのですが、そのほかにも各パターン固有の問題についても確認しておきます。</p>

<h3>Single Table Inheritanceでは<code>type</code>を宣言的に記述可能！</h3>

<p>スライド（pp. <a href="http://eisuke.github.com/yapcasia2010/#64">64</a>-<a href="http://eisuke.github.com/yapcasia2010/#69">69</a>）を拝見すると、<code>type</code>も宣言的に記述できます。</p>

<h3>Concrete Table Inheritanceからはゴミindexが一掃！</h3>

<p>変なことをしなければ変な結果は生まれないわけで、ゴミindexの生まれる余地がないことが分かります。</p>

<h3>Class Table Inheritanceでは無駄なメソッド記述が不要に！</h3>

<p>テーブルの列が同時に複数のクラスのアトリビュートと結び付いても良いため、例えば<code>Bowler</code>で<code>name</code>を生で呼んでも、mapperが面倒を見てくれる結果、<code>cricketers</code>テーブルの<code>name</code>列を触りに行ってくれます。手作り感溢れるマッピングは不要になるわけです。</p>

<h3>全国の<code>DBIx::ObjectMapper</code>使用者の喜びの声（使用者の感想であり効果を保証するものではありません）</h3>

<p>素晴らしい、<code>DBIx::ObjectMapper</code>！　後は、</p>

<ul>
<li><code>DBIx::ObjectMapper</code>で栄転の辞令を貰いました！</li>
<li><code>DBIx::ObjectMapper</code>でTOEICのスコアが300点も上がりました！</li>
<li><code>DBIx::ObjectMapper</code>で身長が10cm伸びました！</li>
<li><code>DBIx::ObjectMapper</code>で宝くじの2等を当てました！</li>
<li><code>DBIx::ObjectMapper</code>で彼女ができました！</li>
</ul>

<p>......などという体験談を仕込むと完璧です。最後のものは割と本気で期待しているのですが、誠に遺憾ながら、今年のクリスマスも中止とすべきようです。</p>

<h2>苦悩からの解放とその代償</h2>

<h3>簡素かつ愚直にすべき......なのだけれども</h3>

<p>閑話休題。そろそろテーブル継承が辛くなってきたので、この苦悩から解放してくれるのなら、神でも悪魔でも頼りたいという気分でありました。しかし計算機上の魔術の基本も等価交換であって、学術的に素晴らしいものでも、それが現実と遊離していると使えないので注意が必要です。その端的な例が、「テーブルをどこまで正規化するか」という命題でしょう。徹底的に正規化されたことによる洗練度の高さを学術的に評価されるスキーマであっても、更新頻度と実行時性能と開発・保守生産性を勘案して、ある程度までで留めておくというのは、大変よくある事例です。</p>

<p>他にも『<a href="http://www.amazon.co.jp/dp/4798119172">モダンPerl入門</a>』のpp.97-101辺りで言及されているような、</p>

<ul>
<li><code>JOIN</code>が必要となるような複雑なテーブルはORMではできるだけ触らない</li>
<li>読み込み用のキャッシュ的テーブルと、書き込み用のテーブルを分ける</li>
</ul>

<p>......などの技巧は地に足の着いたもので、大いに納得するところです。「そもそもテーブル継承が必要な作りにすること自体が間違いなのだ」という論には、強い説得力があります。つまりは<a href="http://ja.wikipedia.org/wiki/KISS%E3%81%AE%E5%8E%9F%E5%89%87">Keep It Simple and Stupid</a>ということですね。</p>

<p>今回の場合、Data Mapperはマッパーというレイヤーを新たに一つ設ける営みであるため、抽象度が増す、つまり複雑度が増すということは厳然たる事実です。</p>

<h3>富豪的プログラミング万歳</h3>

<p>一方で、<a href="http://www.amazon.co.jp/dp/4797354364">4Gbpsを超えるようなシステム</a>を業務として開発・運用する場合と、日曜プログラミングの場合とを比較すると、問題への接近方法が少なからず異なってくるようにも思えます。言い換えるならば、大規模なサービスやミッションクリティカルなサービスでない限り、いわゆる「<a href="http://www.pitecan.com/fugo.html">富豪的プログラミング</a>」が許される場面が少なからずあるはずだ、と考えます。</p>

<p>自分で複雑な物を作り上げてしまうのではなく、複雑なことを隠蔽してくれる便利な道具を使うのであれば、市井のエンドユーザーであり間抜けでもある自分が「複雑なことをして自滅する」ことは回避できるはずです。</p>

<p>それは例えば、</p>

<ul>
<li><a href="http://search.cpan.org/perldoc?Data::Model"><code>Data::Model</code></a>や<a href="http://search.cpan.org/perldoc?DBIx::Skinny"><code>DBIx::Skinny</code></a>なども素敵だけれども、敢えて<code>DBIx::Class</code>を</li>
<li><a href="http://search.cpan.org/perldoc?Class::Accessor::Fast"><code>Class::Accessor::Fast</code></a>なども質実剛健だけれども、敢えて<code>Moose</code>を</li>
<li><a href="http://amon.64p.org/"><code>Amon</code></a>なども巧妙だけれども、敢えて<a href="http://search.cpan.org/perldoc?Catalyst"><code>Catalyst</code></a>や<a href="http://github.com/typester/ark-perl"><code>Ark</code></a>を</li>
</ul>

<p>......選択するという、つまり小気味良い軽薄短小ではなく、鈍重かもしれなくても重厚長大なフレームワークにお世話になるという戦略の一環と見なすこともできるでしょう。</p>

<h3>徒労感溢れる作業をいかに低減するか、あるいは甘受するか</h3>

<h4>マッピング地獄</h4>

<p>光にばかり目を奪われずに、影についても検討してみましょう。Data Mapperの鬼門は、やはりマッピング地獄にあります。全ての列と全てのクラスアトリビュートがばらばらになった後、誰がその紐付けを定義するのか。それは自分なのです。こうして、いわゆるXML地獄がその大きな口を開けているという素敵な構図が浮かび上がります。<a href="http://www.google.com/search?q=Hibernate+%E5%9C%B0%E7%8D%84">全国のHibernate使用者の喜びの声</a>にもあるように、私も痛い目に遭いました。</p>

<p>前述の通り.NETで<code>NHibernate</code>を使った際に、3桁になんなんとするテーブルを取り扱う都合上、マッピング用の設定ファイルやらドメインレイヤーのクラスやらを手作りではなく自動生成で出そうとしました。関係がぶった切られるとはいえども、テーブルの列とクラスのアトリビュートが1:1で結び付く割合はかなり高いからです。そして、インピーダンスミスマッチが起こる箇所や、追加で何かをしたい箇所にのみ、生成後のファイルやクラスを修正するという手順を考えていました。</p>

<p>しかし、スキーマを読み取ってそれらを生成する既存のツールには一長一短がありました。結局Perl + <a href="http://search.cpan.org/perldoc?SQL::Translator"><code>SQL::Translator</code></a> + <a href="http://search.cpan.org/perldoc?Text::Xslate"><code>Text::Xslate</code></a>でオレオレジェネレーターを作ってしまったという、仕様もない落ちもあったりします。<code>NHibernate</code>は<code>Hibernate</code>然として使えますが、周辺ツール類まで<code>Hibernate</code>級の存在感を期待するのはお門違いだったのかも知れません。大いに反省しています。</p>

<h4>自動生成という「隣の青い芝」</h4>

<p>さて、これは一つの示唆であるように思えます。「ためにする作業」は徒労感が募りますし、コード量の増加はバグの増加に直結します。そもそも私がPerlへ惹かれている理由の一つは、「簡単に書けること」であったはずです。</p>

<p>例えば<code>DBIx::Class</code>を使う場合、データストア側かドメインレイヤーのクラス側のどちらかの作業を自動化することが少なくありません。</p>

<ul>
<li>MySQL WorkbenchなどでERモデリングを行い、DDLを自動生成し、<code>DBIx::Class::Schema::Loader</code>でそれを読み込む（DDLとドメインレイヤーのクラスを自動生成する）</li>
<li>ドメインレイヤーのクラスを自分で書き上げ、<code>DBIx::Class::Schema::Deploy</code>でそれを反映する（DDLを自動生成する）</li>
</ul>

<p>もしそうでないとしたら？　ERモデリングにも全力で取り組んで、ドメインモデリングにも全力で取り組むというだけの熱意・根気・義務感・勤勉さ・緻密さ・夢・希望・愛・その他諸々は、今の私のポケットのどこをはたいても出て来ません。いや、誇張がありましたので軌道修正すると、「隣の青い芝」が気になってしまいます。</p>

<p>スライドを拝見した限りでは、<code>$mapper-&gt;metadata-&gt;table</code>の引数たるハッシュで、値を<code>autoload</code>とすれば、1:1マッピングにかかる仕事が終わるようにお見受け致しました。しかしドメインレイヤーのクラス群を書く仕事は残っています。例えば<code>DBIx::ObjectMapper::Metadata::Loader</code>（仮称）のようなものが、<code>SQL::Translator</code>でスキーマを読み取りつつ、その結果を回して（<code>Moose</code>ベースのクラスであれば）<code>has</code>を吐いて回るようだと、かなり無精になれそうです。</p>

<p>NHibernate用ジェネレーターのアドホックな実装経験を活かせれば良いのですが、オレオレイカサマジェネレーターで大火傷を負う未来絵図も脳裏に浮かぶので、ここは慎重になりたいところです。</p>

<h4>冒険すべき時と場合・冒険すべきでない時と場合</h4>

<p>自動生成という名の青い鳥を追い求めるのは、果たして是か非か。自動生成がないからといってこれまで通りの混沌とした設計を貫き通すのか。これはなかなか深刻な命題ですが、<a href="http://ja.wikipedia.org/wiki/%E3%83%99%E3%83%BC%E3%83%91%E3%83%BC%E3%82%A6%E3%82%A7%E3%82%A2">ヴェイパーウェア</a>疑惑が付いて回る<code>Amikeco</code>では、もはや冒険をすべき時期ではなくなっていると考えます。<a href="http://ja.wikipedia.org/wiki/%E6%8A%80%E8%A1%93%E7%9A%84%E8%B2%A0%E5%82%B5">技術的負債</a>を償却するための良い機会ではありますが、そこでさらに償却方法についても背伸びをしてしまうのはやり過ぎだと悟りました。</p>

<p>手作りして回ったとしても、Active Recordで突き進んで破滅するよりは遙かに優れた結果を得ることができるはずなので、まずは手作りで頑張ってみようと思います。</p>

<h2>まとめ ～ 適用可否を本気で検討したい</h2>

<p>......などと、冒頭に「簡単に記してみます」などと書いておきながら、延々と自問自答しないと新しいものに手を出せない私は、もう少し素直に生きた方が良いと思います（<del>だから彼女ができないんですね</del>）。</p>

<p>もとい。選択肢があるなら試してみたいし、開発・保守の生産性や、実行性能を比較してみたい。これが現在の正直な気持ちです。ERモデリングもドメインモデリングも行うかわりに、混沌とした設計を脱する方が生産性が高いのか。抽象化をさらに推し進めたData Mapperで、それなりに満足の行く実行性能を叩き出せるのか。今から楽しみでなりません。</p>

<p>今後は<code>Amikeco</code>への適用可否の検証を通して<code>DBIx::ObjectMapper</code>を評価し、その結果を別稿としてまとめていきたい、と考えています。その際には、（<code>DBIx::ObjectMapper</code>のスライドで語り尽くされた感もありますが）<code>DBIx::ObjectMapper</code>で仕上げた場合の実例も（今回の例示法に基づいて）載せるつもりです。</p>
]]>
    </content>
</entry>

<entry>
    <title>試訳「Mooseの未来」 ～ Moose開発ブログより</title>
    <link rel="alternate" type="text/html" href="http://blog.eorzea.asia/2010/11/post_93.html" />
    <id>tag:blog.eorzea.asia,2010://1.93</id>

    <published>2010-11-30T14:48:35Z</published>
    <updated>2010-12-01T03:17:56Z</updated>

    <summary>Here is a Japanese translation of the entry &quot;The Future of Moose&quot; on &quot;Call of the Moose&quot; which blogged by Moose dev team. / Moose開発チームがブログ「Mooseの呼び声」に書いた「Mooseの未来」という記事の日本語訳です。</summary>
    <author>
        <name>Gardejo</name>
        
    </author>
    
        <category term="雑記" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="moosemouseperl" label="Moose/Mouse Perl" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.eorzea.asia/">
        <![CDATA[<p class="original" lang="en">Here is a Japanese translation of the entry &quot;<a href="http://blog.moose.perl.org/2010/11/the-future-of-moose.html">The Future of Moose</a>&quot; on &quot;<a href="http://blog.moose.perl.org/">Call of the Moose</a>&quot; which blogged by the <a href="http://moose.perl.org/">Moose</a> development team. The original text and the translation are licensed under a <a href="http://creativecommons.org/licenses/by-sa/3.0/">Creative Commons License</a>.</p>

<p class="translation" lang="ja"><a href="http://moose.perl.org/">Moose</a>開発チームがブログ「<a href="http://blog.moose.perl.org/">Mooseの呼び声</a>」に書いた「<a href="http://blog.moose.perl.org/2010/11/the-future-of-moose.html">Mooseの未来</a>」という記事の日本語訳です。原文とこの翻訳は<a href="http://creativecommons.org/licenses/by-sa/3.0/">Creative Commons License</a>でライセンスされています。</p>

<p class="original" lang="en">I knew that Moose will be modified greatly on the post via the <a href="http://twitter.com/lestrrat/status/8794466244624384">tweet by lestrrat</a>. It is so attractive for me who is an end-user. In a related matter, MooseX::* extensions will march greatly on modification, and I may have an unexpected injury in a case of that I put my codes into complicated with Moose. Fortunately, Moose seems to be proposed to such a release plan as Perl itself (as will be appreciated from the notation of version number), so I want to go over my codes radically before the actual release comes out.</p>

<p class="translation" lang="ja">Mooseに少なからぬ変更が入ることを、<a href="http://twitter.com/lestrrat/status/8794466244624384">lestrratさんのtweet</a>を経由して、この記事で知りました。エンドユーザーの私から見れば大変魅力的な変更です。MooseX::*拡張モジュールもこれに紐付いて変更への大行進が行われるようですし、自分のコードでMooseの込み入ったことをやっていると、思わぬ怪我をすることもあるかもしれません。幸いにして（バージョン表記法からも分かるように）Perl本体のようなリリース計画が敷かれるようなので、正式版が出るまでの間に徹底的にコードを見直すようにしたいものです。</p>

<p class="original" lang="en">I apologize for the fairly irresponsible translation. Any feedback on the translation are welcome.</p>

<p class="translation" lang="ja">訳は相当でたらめです。ごめんなさい。訳のツッコミがありましたら是非。</p>
]]>
        <![CDATA[<h2 class="original" lang="en">The Future of Moose</h2>

<h2 class="translation">Mooseの未来</h2>

<p class="original" lang="en">By Jesse Luehrs on November 17, 2010 11:36 PM</p>

<p class="translation" lang="ja">ジェシー・ルアズによる、2010年11月17日 午後11時36分の投稿</p>

<h3>第1段</h3>

<p class="original" lang="en">A complaint that has come up multiple times over the past few months is that, as important as Moose is becoming in the Perl ecosystem, it should be more concerned with backwards compatibility.</p>

<p class="translation" lang="ja">過去数ヶ月の間に複数回寄せられた不満というのは、次のようなものである。<a href="http://search.cpan.org/perldoc?Moose">Moose</a>はPerlの生態系<span class="annotation">(<span class="original" lang="en">ecosystem</span>)</span>と同様に重要なものとなったので、後方互換性<span class="annotation">(<span class="original" lang="en">backwards compatibility</span>)</span>へさらなる関心を持つべきである、と。</p>

<p class="original" lang="en">After a series of discussions, the Moose development team has come up with a support policy that seems to satisfy most people; you can read about it <a href="https://github.com/moose/moose/blob/master/lib/Moose/Manual/Support.pod">here</a>.</p>

<p class="translation" lang="ja">一連の議論の後で、Moose開発チームは、たいていの人が満足するようなサポートポリシーを考え出した。それは<a href="https://github.com/moose/moose/blob/master/lib/Moose/Manual/Support.pod">ここ</a>で読むことができる。</p>

<p class="original" lang="en">The main points are: Moose will be moving to a time-boxed release cycle of three months between (major) releases.</p>

<p class="translation" lang="ja">その概要は、(大規模)リリース<span class="annotation">(<span class="original" lang="en">(major) releases</span>)</span>の間隔を3ヶ月とする、タイムボックス化された<span class="annotation">(<span class="original" lang="en">time-boxed</span>, 訳注:あらかじめ期限を区切っておくこと)</span>リリースサイクルへ、Mooseが移行するというものだ。</p>

<p class="original" lang="en">Bug fixes and minor features can be added in between major releases as long as they don't break backwards compatibility (and we will put more effort into making sure they don't).</p>

<p class="translation" lang="ja">バグの修正と小規模な機能追加は、それが後方互換性を壊さない間、大規模リリースの合間<span class="annotation">(のリリース)</span>に加えることができる(そして我々は、後方互換性が壊されていないことを確認することへ、より多くの工数を割くだろう)。</p>

<p class="original" lang="en">Major releases can break backwards compatibility, but we will release at least one (ideally more than one) trial release before the actual release comes out, so that people can test their own systems with the new features, and report back with issues they may have.</p>

<p class="translation" lang="ja">大規模リリースは後方互換性を壊しうるが、我々は最低でも1つ、理想としては1つ以上の試行版<span class="annotation">(<span class="original" lang="en">trial release</span>)</span>を、正式版<span class="annotation">(<span class="original" lang="en">actual release</span>)</span>を出すより先に公開するつもりだ。だから、皆さんは新機能を備えた各自のシステムをテストできるし、もしあれば問題を報告することもできる。</p>

<p class="original" lang="en">We will also do our best to assist maintainers of Moose extensions with updating their modules for major changes, but not to the point of taking over maintainership of extensions that have become unmaintained.</p>

<p class="translation" lang="ja">我々はまた、Mooseの拡張モジュールのメンテナーに対して、それらのモジュールの、大規模な<span class="annotation">(Moose本体の)</span>変更に追従するための更新を補助することについても、最善を尽くすだろう。ただし、既にメンテナンスされなくなっている拡張モジュールについては、この限りではない。</p>

<p class="original" lang="en">If you rely on a Moose extension whose maintainer has abandoned it, feel free to find someone willing to take up maintainership, and come talk to us on #moose, we'll be more than willing to help you get up to speed.</p>

<p class="translation" lang="ja">メンテナーが保守を断念しているMooseの拡張モジュールをあなたが当てにしているならば、保守を引き継いでくれるような人を気軽に捜して欲しい。そしてIRCの#mooseチャネルで我々に話しかけて欲しい。我々はあなたが予備知識を得るのを十分に手助けするつもりだ。</p>

<h3>第2段</h3>

<p class="original" lang="en">Now, on to the fun part(: The next Moose release will contain several exciting new improvements, both for users and extension authors.</p>

<p class="translation" lang="ja">さて、現在はユカイな<span class="annotation">(訳注:大変な)</span>状態にある。Mooseの次のリリースでは、ユーザーと拡張モジュールの作者の双方にとって、刺激的かつ新しい改善点がいくつか含まれる。</p>

<p class="original" lang="en">The first is that there has been a significant effort to speed up Moose's compilation time, through several means.</p>

<p class="translation" lang="ja">まず、いくつかの手段によるMooseのコンパイル時間の速度向上へ、かなりの工数が費やされている。</p>

<p class="original" lang="en">The largest and most obvious is that Package::Stash, the module that Moose uses to do its symbol table manipulation (for adding and retrieving methods, among other things), has been rewritten entirely in XS.</p>

<p class="translation" lang="ja">最大かつ最も明白な成果としては、<a href="http://search.cpan.org/perldoc?Package::Stash">Package::Stash</a>がある。これは、Mooseが(とりわけ、メソッドを追加および取得するために)シンボルテーブル<span class="annotation">(<span class="original" lang="en">symbol table</span>)</span>を操作するために使っているものだ。これが全面的にXSで書き直されている。</p>

<p class="original" lang="en">Since Moose spends over a third of its compilation time doing symbol table manipulation, this seemed like a good optimization target, and this turns out to have been correct - it resulted in a 10-15% speedup across the board for Moose application compile times.</p>

<p class="translation" lang="ja">Mooseはシンボルテーブルを操作するためにコンパイル時間の3分の1以上を費やしていたので、最適化の格好の対象であったろうし、直されるべきものでもあった。結果として、Mooseアプリケーションのコンパイル時間の全般にわたって、10～15%の高速化が実現された。</p>

<p class="original" lang="en">Another advantage to this is that it fixes a couple (admittedly minor) long-standing bugs in the Class::MOP::Package API, since the symbol table API available from pure perl has several inherent issues itself.</p>

<p class="translation" lang="ja">その他の利点として、<a href="http://search.cpan.org/perldoc?Class::MOP::Package">Class::MOP::Package</a>のAPIについての(明らかに小規模な)いくつかの積年のバグが、これによって修正されることが挙げられる。それはシンボルテーブルAPIについての、それがピュアPerlから使えるようになって以来の、いくつかの固有の問題であった。</p>

<p class="original" lang="en">Another area that should see significant improvement is in code which uses the native delegation attribute traits.</p>

<p class="translation" lang="ja">重要な改善点とみなされるべきもう一つの分野は、ネイティブな委譲アトリビュートトレート<span class="annotation">(<span class="original" lang="en">native delegation attribute traits</span>)</span>を使うコードに存在する。</p>

<p class="original" lang="en">Previously (ever since the rewrite in 1.15), the traits themselves were loaded lazily (i.e. Moose::Meta::Attribute::Native::Trait::Bool wasn't loaded unless you actually declared an attribute with traits => ['Bool']), but the implementations of each native delegation were all loaded at once, when the trait itself was loaded.</p>

<p class="translation" lang="ja">以前には、つまり1.15<span class="annotation">(訳注:バージョン1.15のMoose)</span>で書き直されて以来ずっと、このトレートは自分自身を遅延ロードしていた<span class="annotation">(<span class="original" lang="en">loaded lazily</span>)</span>。すなわち、<code>traits => ['Bool']</code>というオプションをアトリビュートへ明確に記述しない限り、<a href="http://search.cpan.org/perldoc?Moose::Meta::Attribute::Native::Trait::Bool">Moose::Meta::Attribute::Native::Trait::Bool</a>はロードされなかった。しかしこのネイティブ委譲のそれぞれの実装は、トレートがロードされた時点で、一度に全てがロードされるというものであった。</p>

<p class="original" lang="en">This has been fixed, and should be another fairly large speedup for applications which use only a couple native delegations from the traits they use (which is the case the vast majority of the time).</p>

<p class="translation" lang="ja">これが修正されるばかりでなく、トレートを使ってネイティブ委譲のセットのみを使う(ために大部分の時間を要していた)アプリケーションについての、かなり大幅な高速化が実現された。</p>

<p class="original" lang="en">Finally, the way method metaobjects are cached has been improved, which speeds up the introspection of methods (which happens frequently during compilation) a small but noticeable amount.</p>

<p class="translation" lang="ja">最後に、メソッドメタオブジェクト<span class="annotation">(<span class="original" lang="en">method metaobjects</span>, 訳注:「メソッド」オブジェクト)</span>のキャッシュ方法が改善された。それは(コンパイルの間に頻繁に発生する)イントロスペクション<span class="annotation">(<span class="original" lang="en">introspection</span>, 訳注:オブジェクトの中身を実行時に参照すること)</span>を、小さいが顕著な量ごとに高速化したということだ。</p>

<p class="original" lang="en">Here are some links to some relevant profiling data (run on my netbook under full profiling, which is why the times are so high): <a href="http://tozt.net/moose/nytprof-kioku/">&quot;perl -MKiokuDB -e1&quot; with Moose 1.19</a>: 8.60s, <a href="http://tozt.net/moose/nytprof-kioku-new/">&quot;perl -MKiokuDB -e1&quot; with Moose git</a>: 6.38s, <a href="http://tozt.net/moose/nytprof-markdent/">&quot;perl -MMarkdent::Simple::Document -e1&quot; with Moose 1.19</a>: 13.9s, <a href="http://tozt.net/moose/nytprof-markdent-new/">&quot;perl -MMarkdent::Simple::Document -e1&quot; with Moose git</a>: 10.6s.</p>

<p class="translation" lang="ja">それではここで、関連するプロファイリングのデータを示すリンクのいくつかをお見せしよう。これらは全て私のネットブックでプロファイリングしたものだから、やや高めの値が出ている。まず、<a href="http://tozt.net/moose/nytprof-kioku/"><kbd>&quot;perl -MKiokuDB -e1&quot;</kbd> をMoose 1.19で動かす</a>と8.60秒かかるのに対して、<a href="http://tozt.net/moose/nytprof-kioku-new/"><kbd>&quot;perl -MKiokuDB -e1&quot;</kbd>をgit<span class="annotation">(訳注:のリポジトリ上にある開発中)</span>のMooseで動かす</a>と6.38秒かかる。また、<a href="http://tozt.net/moose/nytprof-markdent/"><kbd>&quot;perl -MMarkdent::Simple::Document -e1&quot;</kbd>をMoose 1.19で動かす</a>と13.9秒かかるのに対して、<a href="http://tozt.net/moose/nytprof-markdent-new/"><kbd>&quot;perl -MMarkdent::Simple::Document -e1&quot;</kbd>をgitのMooseで動かす</a>と10.6秒かかる。</p>

<p class="original" lang="en">These changes should have minimal compatibility impact (and none at all if you don't use the Class::MOP::Package API); a more detailed discussion is in Moose::Manual::Delta.</p>

<p class="translation" lang="ja">これらの変更は互換性へわずかに影響を及ぼす。ただしClass::MOP::PackageのAPIを使っていないのであれば全く影響はない。その詳細な考察については<a href="http://search.cpan.org/perldoc?Moose::Manual::Delta">Moose::Manual::Delta</a>を参照して欲しい。</p>

<h3>第3段</h3>

<p class="original" lang="en">In terms of features, we have made a fairly significant change to how attribute metaroles work.</p>

<p class="translation" lang="ja">機能については、アトリビュートメタロール<span class="annotation">(<span class="original" lang="en">attribute metaroles</span>, 訳注:「アトリビュート」ロール)</span>の働きについて、我々はかなり重大な変更を加えている。</p>

<p class="original" lang="en">Previously, when a role was applied to a class, it would copy the attributes from the role into the class using the <em>class's</em> default attribute metaclass, prior to applying the traits specified in the attribute definition.</p>

<p class="translation" lang="ja">以前のそれは、つまりロールがクラスに適用されていた時のそれは、アトリビュートの定義部で指定されたトレートが適用されるより前に、<em>クラスの</em>デフォルトのアトリビュートメタクラス<span class="annotation">(<span class="original" lang="en">attribute metaclass</span>, 訳注:「アトリビュート」クラス)</span>を使っているクラスへと、アトリビュートをロールからコピーするという挙動であった。</p>

<p class="original" lang="en">This is obviously incorrect with a bit of thought - attribute metaclasses completely define how the attribute works, including things like how accessors are generated.</p>

<p class="translation" lang="ja">これは少し考えても分かるように、明らかに誤っていた。アトリビュートメタクラスは、アクセッサーの生成の挙動を含めて、アトリビュートの挙動を完全に定義するものだ。</p>

<p class="original" lang="en">If a role contains an attribute and some methods, those methods need to be able to know what method name the accessor is going to be installed under, or the role won't work.</p>

<p class="translation" lang="ja">もしロールがアトリビュートやいくつかのメソッドを含んでいるならば、それらのメソッドはどのメソッド名がアクセッサーとしてインストールされようとしているのかを知ることができなければならない。そうでないのならロールは動作しないであろう。</p>

<p class="original" lang="en">A good example of this is a class which uses MooseX::FollowPBP consuming a role which doesn't - currently, this completely breaks the role.</p>

<p class="translation" lang="ja">その好例は、<a href="http://search.cpan.org/perldoc?MooseX::FollowPBP">MooseX::FollowPBP</a>を使うクラスが(現在は)動かないロールを消費<span class="annotation">(<span class="original" lang="en">consuming a role</span>, 訳注:<code>with</code>構文でクラスやロールにロールを取り込むこと)</span>していることである。</p>

<p class="original" lang="en">With this change, roles now have their own default attribute metaclass, separate from any class.</p>

<p class="translation" lang="ja">この変更によって、ロールはデフォルトで自身のアトリビュートメタクラスを備えるようになり、どのクラスからも分離されるようになった。</p>

<p class="original" lang="en">This also allows for an additional feature - when writing extensions, you can specify the 'applied_attribute' option to the 'role' block in 'apply_metaroles' to specify a set of default traits that all attributes defined in that role will receive when they are applied to a class.</p>

<p class="translation" lang="ja">これにより、新たな機能も実現される。拡張モジュールを記述するときに、全てのアトリビュートが定義済みであるデフォルトのトレートのセットを指定するために、<code>'apply_metaroles'</code>の中で、<code>'role'</code>ブロックへ<code>'applied_attribute'</code>オプションを指定することができるようになるのだ。これはロールがクラスへいつ適用されるのかを受け取るために実現される。</p>

<p class="original" lang="en">This should work identically to the 'attribute' option in the 'class' block, and should allow extensions which add default attribute metaroles (such as MooseX::Aliases) to work identically in both classes and roles (unlike currently, where the trait must be applied explicitly in role attributes).</p>

<p class="translation" lang="ja">これは<code>'class'</code>ブロックにある<code>'attribute'</code>オプションと全く同様に働くし、クラスとロールを同一の挙動にするために、(<a href="http://search.cpan.org/perldoc?MooseX::Alias">MooseX::Aliases</a>のような)デフォルトのアトリビュートメタロールを追加するという拡張を講じることもできる。現在はそうではなく、ロールのアトリビュートではトレートを明示的に適用しなければならない。</p>

<p class="original" lang="en">The downside to this is that it breaks backwards compatibility in a potentially confusing way: if you were assuming and relying on role attributes using the class's attribute metaclass, your roles will break, and there isn't really a way to detect this.</p>

<p class="translation" lang="ja">この弱点として、潜在的な勘違いに基づくコードについては、後方互換性を壊すことが挙げられる。あなたが、ロールアトリビュートがクラスのアトリビュートメタクラスを使用すると想定して、そのような挙動を当てにしているのであれば、それは動作しなくなるだろう。そしてそれは間違いに気付く真の手段ではないはずだ。</p>

<p class="original" lang="en">The solution will be to use the same extensions in your roles that you do in the classes that consume those roles, but as noted previously, attribute metaroles don't currently work in roles.</p>

<p class="translation" lang="ja">これらの<span class="annotation">(訳注:MooseX::Aliasなどの)</span>ロールを消費するクラスの中で、いくつかの拡張モジュールをあなたのロールで使用することが、解決法となるだろう。しかし前述のように、アトリビュートメタロールは現在はロールの中では動かない。</p>

<p class="original" lang="en">These extensions will be fixed by the time we make an actual release.</p>

<p class="translation" lang="ja">我々が正式版を作る時までに、これらの<span class="annotation">(訳注:MooseX::Aliasなどの)</span>拡張モジュールは修正されるであろう。</p>

<h3>第4段</h3>

<p class="original" lang="en">Finally, there is also some good news for extension authors: the inlining API should be much more sane, and the code itself should be much more readable, so adding inlined method generation support to your modules which affect accessor or constructor/destructor generation should be much, much easier now.</p>

<p class="translation" lang="ja">最後に、拡張モジュールの作者への良い知らせがもう一つある。APIのインライン化<span class="annotation">(<span class="original" lang="en">inlining API</span>)</span>はより健全なものになり、それらのコードはより読みやすいものになる。インライン化されたメソッドの生成は、アクセッサーやコンストラクターとデストラクターの生成に関係するあなたのモジュールについて、それらをとてもとても簡単に行えるように支援するようにもなる。</p>

<p class="original" lang="en">Some highlights include: the attribute metaclass and class metaclass controlling entirely how the bodies of the methods they generate are created (so there should no longer be a need to write accessor or constructor metaclass traits), accessor generation in Class::MOP and Moose going through one much simplified codepath (read: removed the obscene amount of code duplication between Class::MOP and Moose), so figuring out how a given accessor is generated should be pretty trivial now, and constructors now asking the attribute metaclass how to initialize attributes at construction time, rather than doing it themselves with a bunch of duplicated code (so in the case of simple attribute traits which affect accessor generation, manually modifying the constructor generation shouldn't even be necessary).</p>

<p class="translation" lang="ja">これにはいくつかのハイライトが含まれる。まず、アトリビュートメタクラスとクラスメタクラス<span class="annotation">(<span class="original" lang="en">class metaclass</span>, 訳注:「クラス」クラス)</span>は、生成されるメソッドの本体をどのように作成するかを、完全に制御するようになる。また、<a href="http://search.cpan.org/perldoc?Class::MOP">Class::MOP</a>とMooseでのアクセッサーの生成は、ただ一つの単純化されたコードパスによって行われるようになる。Class::MOPとMooseで重複していた気持ち悪いくらいの量のコードは取り除かれたのだ。従って、与えられたアクセッサーの生成方法を解明することは、もはや相当に些細な問題になる。そしてコンストラクターは、これからは、コンストラクト時にアトリビュートをどのように初期化すべきかを、複製されたコードの一群と共にコンストラクター自身が行うのではなく、アトリビュートメタクラスに対して確認するようになる。なお、アクセッサーの生成を行う単純なアトリビュートトレートの場合、コンストラクターの生成を手動で修正する必要すらなくなる。</p>

<p class="original" lang="en">The downside to this is, as you may have guessed, the API for doing code inlining has been changed pretty radically.</p>

<p class="translation" lang="ja">これについての推測されるであろう欠点は、コードのインライン化を行うAPIが根本的に変更されるということだ。</p>

<p class="original" lang="en">This will require some work on the part of extension authors, in order to use the new API (since there's not really a non-insane way to support both APIs), but again, we'll be working with extension authors to make sure this happens before our actual release, and we'll be releasing a few dev releases prior to the actual release to allow people with non-CPAN code to have a chance to update their code.</p>

<p class="translation" lang="ja">これは一部の拡張モジュール作者に対して、新たなAPIを使うための、いくらかの作業を要求するものだ。それは<span class="annotation">(新旧)</span>両方のAPIをサポートするための、それほど突飛ではない方法が存在するようになってからだ。しかし思い起こしてもらいたいのは、それらが問題なく動作することを確認するために、我々の正式版のリリースよりも前に、我々が拡張モジュールの作者たちと共に作業するであろうということだ。そして我々は、CPANモジュールでないコードを使っている皆さんが、自身のコードを更新するための機会を確保できるよう、いくつかの開発版<span class="annotation">(<span class="original" lang="en">dev releases</span>)</span>を正式版よりも前にリリースするだろう。</p>

<h3>第5段</h3>

<p class="original" lang="en">As far as a plan goes, we're looking to have our first trial release out by the end of this month, and are aiming for the actual release to happen sometime in late December or early January.</p>

<p class="translation" lang="ja">計画通りに行けば、我々は今月末<span class="annotation">(訳注:2010年11月末)</span>までに最初の試行版を出せるだろう。そして、我々は正式版を12月後半または1月前半に出すことを目指している。</p>

<p class="original" lang="en">If you have any questions about the new release and support process, or about any of these new features, definitely let us know - we're very open to feedback, either here, on the Moose mailing list, or on #moose-dev on IRC.</p>

<p class="translation" lang="ja">この新しいリリースやサポート工程について質問があるか、またはこれらの新機能について何か我々に明確に知らせておきたい事柄があるのなら、我々はそのフィードバックを歓迎している。ここ<span class="annotation">(訳注:<a href="http://blog.moose.perl.org/2010/11/the-future-of-moose.html">元記事</a>への英文コメントやトラックバック)</span>か、Mooseのメーリングリストか、IRCの#moose-devチャネルまでお寄せいただきたい。</p>
]]>
    </content>
</entry>

<entry>
    <title>人肌のPerl</title>
    <link rel="alternate" type="text/html" href="http://blog.eorzea.asia/2010/02/post_92.html" />
    <id>tag:blog.eorzea.asia,2010://1.92</id>

    <published>2010-02-21T00:38:52Z</published>
    <updated>2010-02-23T03:49:39Z</updated>

    <summary>「文法最速マスター」というタイムリーなネタに半ば悪のりしてしまいましたが、はてブ...</summary>
    <author>
        <name>Gardejo</name>
        
    </author>
    
        <category term="雑記" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="moosemouse" label="Moose/Mouse" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="Perl" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.eorzea.asia/">
        <![CDATA[<p>「文法最速マスター」というタイムリーなネタに半ば悪のりしてしまいましたが、<a href="http://b.hatena.ne.jp/entry/perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html">はてブ</a>や<a href="http://clip.livedoor.com/page/http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html">Livedoorクリップ</a>などで拙稿の「<a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html">Moose &amp; Mouse基本文法最速マスター/The Fastest Way to Mastering Moose &amp; Mouse</a>」が先週末にホッテントリ入りしたようです。ご覧いただきましてどうもありがとうございます。</p>

<p>日本ではYAPC::Asia 2008などが契機となったのか、2008年の半ばにMoooooooooooooooooooose!の潮流が大きく促進されました。そして2010年の現在、<a href="http://search.cpan.org/perldoc?Moose"><code>Moose</code></a>はもうPerlハッカーの方々だけのものではなく、私のような一般のPerlユーザーにもとても近い存在になっています。そうした土壌があることも、奏功した一因かと考えています。</p>

<p>思い返せば、私が<code>Moose</code>を触り始めたのは2008年の後半でした。2009年2月に出た<a href="http://mt.endeworks.jp/d-6/">lestrratさん</a>の『<a href="http://www.amazon.co.jp/dp/4798119172">モダンPerl入門</a>』には大いに感銘を受けました。5月には2万行くらいの私的な開発案件に投入して、その威力を再確認しました。7月に<a href="http://github.com/jpa">GitHubのJPAリポジトリ</a>にpushされた<a href="http://d.hatena.ne.jp/charsbar/">charsbarさん</a>による<a href="http://github.com/jpa/Moose-Doc-JA"><code>Moose::Manual</code>と<code>Moose::Cookbook</code>の邦訳版</a>は、<a href="http://perldoc.perlassociation.org/pod/Moose-Doc-JA/">JPAのドキュメント和訳プロジェクトでの公開</a>を待たずして、<a href="http://blog.perlassociation.org/2009/07/perldoc-in-japanese.html">JPAの発表</a>を知ったその日にPODをHTML化して印刷し、当初から印刷していた原語版共々愛読しています。これにはかなり助けられました。そして10月。<a href="http://conferences.yapcasia.org/ya2009/talk/2192">YAPC::Asia特別研修「Moose入門」</a>が開催され、中の人である<a href="http://sartak.org/">sartakさん</a>直々の仕込みに<a href="http://blog.eorzea.asia/2009/09/post_65.html">ひたすら感激しました</a>。「最速マスター」を書けるようになったのも、ひとえにこうした方々の成果があったためです。私は日々皆さんに感謝しながらコードを書いています。</p>

<p>そうした感動を何とか還元したくて、<a href="http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=gitmo/moose-presentations.git;a=tree;f=moose-class">スライド</a>を<a href="http://blog.eorzea.asia/2009/10/post_70.html">和訳してみたり</a>、<a href="http://blog.eorzea.asia/2010/02/post_91.html">クイックリファレンスシート（チートシート）を書いたり</a>しました。今回の「最速マスター」もその一環として位置付けたつもりです。</p>

<p>二ヶ月弱もこのブログを放っておいたので、「最速マスター」をここで公開しようかとも考えましたが、<a href="http://blog.eorzea.asia/2010/02/post_90.html">先日書いた</a>通り、<a href="http://perl-mongers.org">perl-mongers.org</a>にお世話になることにしました。理由をもう少し捕捉しておくと、公益性が多少ありそうな入門記事を折角書いたのだから、ここのような「どこの馬の骨とも知れない場末ドメインのインチキブログ」で公開するよりは、「多くの方にご覧頂けそうで、かつ、公益性があって信頼の出来る場所」に公開したいと考えたからです。</p>

<p>公益性を感じられるドメイン名が既にあり、登録すれば誰でも寄稿出来る仕組みが既にあり、実際に多くの記事が既に投稿されている。この環境はとても素晴らしいものだと思います。perl-mongers.orgを立ち上げた<a href="http://vkgtaro.jp/">vkgtaroさん</a>、サイトを現在ホストしている<a href="http://blog.woremacx.com/">woremacxさん</a>に、とても感謝しているところです。</p>

<p>言語や処理系へ大会社のサポートがあるといっても、それらは実際には大して頼りにならず、そのうえ日々「バグだ」「いや仕様漏れだ」「何だと、瑕疵担保条項を発動するぞ」「そもそも要件定義からして腐っていたんだ」などと前から後ろから弾丸が飛び交う場所で設計・開発・試験して、祈りながら実行して飯を食べている私は、コミュニティーに感謝しながら楽しく設計・開発・試験して、実行結果を安心して見守れるPerlを心のオアシスとして生きているのかも知れません。</p>

<p>これは完全な私感になりますけれども、<a href="http://ja.wikipedia.org/wiki/Ruby#Ruby.E5.93.B2.E5.AD.A6">Rubyでプログラミングを楽しめる</a>一方で、PerlにはCPANやコミュニティーを含めた楽しさや居心地の良さを他の言語よりも強く感じます。</p>

<p>Perlコミュニティーにはperl-users.jpや各地の*.pmもあります。<a href="http://d.hatena.ne.jp/perlcodesample/20091226/1264257759">基本文法</a>や<a href="http://d.hatena.ne.jp/chaichanPaPa/20100206/1265436393">オブジェクト指向</a>や<a href="http://d.hatena.ne.jp/gfx/20100202/1265091606">XS</a>などの「最速マスター」シリーズも盛んです。勿論、こんな美味しい方法論が放っておかれるわけもなくて、他の言語の暖かいコミュニティーでもhogehoge-usersが出来たり、「hogehoge文法最速マスター」が公開されたりしています。でも、それらの嚆矢がPerlであったということは、Perlユーザーは誇ってもいいと思うのです。</p>

<p>私はそんなPerlが大好きです。</p>

<p>今般<code>Moose</code>/<code>Mouse</code>を使い始めようとする方に奉仕するのは、私の義務であり喜びでもあります。どうか、<code>Moose</code>/<code>Mouse</code>による楽しいプログラミングを、Perlコミュニティーの体温を感じながら味わってください。</p>

<p>ところで、体温といえば、私は投稿した日に風邪を引いたらしくて摂氏37度になりました。ぎゃふん。</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Moose &amp; Mouseの私家版クイックリファレンスシート(チートシート)を作りました</title>
    <link rel="alternate" type="text/html" href="http://blog.eorzea.asia/2010/02/post_91.html" />
    <id>tag:blog.eorzea.asia,2010://1.91</id>

    <published>2010-02-19T14:44:24Z</published>
    <updated>2010-02-21T00:33:02Z</updated>

    <summary><![CDATA[Moose &amp; Mouseの私家版クイックリファレンスシート（チートシー...]]></summary>
    <author>
        <name>Gardejo</name>
        
    </author>
    
        <category term="雑記" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="moosemouse" label="Moose/Mouse" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="Perl" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.eorzea.asia/">
        <![CDATA[<p><a href="http://search.cpan.org/perldoc?Moose"><code>Moose</code></a> &amp; <a href="http://search.cpan.org/perldoc?Mouse"><code>Mouse</code></a>の私家版クイックリファレンスシート（チートシート）を作ってみました。</p>

<p>PDF版とODT版の両方を置いておきます。</p>

<ul>
<li><a href="http://perl.ermitejo.com/moose_quick_ref.pdf">Moose &amp; Mouse QUICK REFERENCE (PDF)</a></li>
<li><a href="http://perl.ermitejo.com/moose_quick_ref.odt">Moose &amp; Mouse QUICK REFERENCE (ODT: OpenDocument Text for OpenOffice.org Writer)</a></li>
</ul>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="moose_quick_ref.png" src="http://blog.eorzea.asia/2010/02/20/moose_quick_ref.png" width="640" height="450" class="mt-image-none" style="" /></span></p>

<p><a href="http://ja.openoffice.org/">OpenOffice.orgは無料で入手出来ます</a>ので、オレオレチートシートの元ネタとしてもお使いいただけるかも知れません。</p>

<p>そもそもMooseには<a href="http://sites.google.com/site/gorwits/">Oliver Gorwitsさん</a>による<a href="http://tinyurl.com/moosequickref">Moose Quick-Ref Card</a>というチートシートが昔からあります。これは奥深い<code>Moose</code>の世界が端的にまとめられた素晴らしいものです。ただ、幾つかオレオレ仕様にしたい点がありました。</p>

<p>そんな日々を送っていると、『<a href="http://ascii.asciimw.jp/books/books/detail/978-4-04-868411-8.shtml">Web制作の現場で使うjQueryデザイン入門</a>』の付録にフルカラーのjQueryチートシートが付いていることを知りました。これに触発されて作り始めたという経緯があります。</p>

<p>当初はこの2倍くらいの量があったのですが、だったら流行りの「基本文法最速マスター」に悪のりしてしまおうとしたのが「<a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html">Moose &amp; Mouse基本文法最速マスター/The Fastest Way to Mastering Moose &amp; Mouse</a>」という副産物です。</p>

<p>ところで、上述のjQuery本はプログラマー向けというよりは意匠デザイナー向けの本であるので、カラフルなチートシートで間口を広く取るのは大正解だと思います。一方、今回作った<code>Moose</code> &amp; <code>Mouse</code>チートシートは白黒灰の3色かつ無味乾燥な作りになっているので、初学者向けのチートシートにはなっていません。カラフルでA4両面くらに日本語の説明文をふんだんに盛り込んだ初学者向けのシートも併せて作りたかったのですが、意匠センスが決定的に不足しているので断念しました。</p>

<p><code>Moose</code>/<code>Mouse</code>の素敵なプログラミングを体験する人が増えることを期待していますので、ナウなヤングにバカウケなイけてるシートを公開してくださる偉い人の登場を心待ちにしています。</p>

<p>とはいえ今回のシートも多少は物を考えて書いたつもりです。苦心した点を以下に簡単にまとめておきます。</p>
]]>
        <![CDATA[<h2>カカオ増量、砂糖減量</h2>

<p>クイックリファレンスというのは、「読む」ものではなく「見る」ものだと考えています。従って、自然言語、つまり英語（や日本語）の説明文を極力省くことで、必要なコードスニペットだけが目に飛び込んでくるようになります。</p>

<p>私はクイックリファレンスをそれ自体で単独で完結させようとはせず、<code>Moose</code>の基本的な構文を「最速マスター」の水準で理解できていることを前提として記述しました。</p>

<p>いくつかの例を元にもう少し詳しく説明します。</p>

<h3>自明な箇所の解説は除いた</h3>

<p>端的な例は<code>extends @superclasses</code>です。</p>

<p>見ての通りsuperclassesをextendするので、class inherits superclassesなどという説明文は不要ですね。自明な処理はコメントしないという鉄則を守らないと、コードを逐行で日本語訳して立派な「クラス仕様書」をこしらえるどこかの会社の轍を踏んでしまいます。</p>

<p>Moose Quick-Ref Cardでもあまりにも自明な解説文は省いていますが、しかしどちらかというと親切な記述になっているようにお見受けしました。多少間口を狭くした方がかえって利便性が増す可能性があるのではないだろうか、と思います。</p>

<h3>コードで書けるものは極力コードで書く</h3>

<p>他にも、Moose Quick-Ref Cardではメソッドモディファイヤーのコードリファレンスに渡ってくる引数について</p>

<blockquote>
  <p><code>around</code> is passed <code>($next_method, $self, @args)</code>.</p>
</blockquote>

<p>と書かれていますが、これは以下のようにコードだけで書くこともできます。</p>

<pre><code>around @methods =&gt; sub {
    my ($next, $self, @args) = @_; ...
};
</code></pre>

<p>ついでに<code>my @return_values = $self-&gt;$next(@args); ...</code>という記述も追加して、<code>override</code>/<code>super()</code>との違いが分かるようにもしました。</p>

<h3>元々甘い<code>Moose</code></h3>

<p>いかにもそれっぽい理由付けを書きましたが、こうでもしないと内容をA4へ収めきれないという切実な問題が一番の理由だったりします。</p>

<p>ただし、<code>Moose</code>のシュガー関数はそれ自体が「甘い」ので、さらなる砂糖を振り掛けなくても美味しくいただけるということが分かります。宣言的プログラミングが病み付きになる所以ですね。</p>

<h2>痒いところに孫の手を</h2>

<h3><code>Any::Moose</code>対応</h3>

<p>クラスやロールのスケルトンなどで<code>Any::Moose</code>を使った書き方にしています。</p>

<p><code>Any::Moose</code>の仕様が分かっていれば、シートに相当して<code>Moose</code>, <code>Moose::Role</code>, <code>MooseX::Types</code>を生で<code>use</code>する記述も書けると思います。というか、流石に<code>use Moose;</code>することを知らないと<code>Moose</code>クラスは書けないと思います。</p>

<h3><code>MooseX::Types</code>前提</h3>

<p><code>Moose::Util::TypeConstraints</code>ではなく<code>MooseX::Types</code>を使うことを前提にしています。</p>

<p><code>My::App::Types</code>以下の名前空間に勝手に入ってくれたりするので、あれやこれや気を遣ったり、注意を促す文言を書くよりは、すっぱり<code>MooseX::Types</code>を使った方が楽だと思ったからです。</p>

<p>勿論<code>Any::Moose</code>に対応した書き方をしています。</p>

<h3>ネイティブトレートのヘルパーメソッドを網羅</h3>

<p>私家版チートシート作成の動機は、ひとえに名前空間が深い<code>Moose::Meta::Attribute::Native::Trait::Array</code>などを<code>perldoc</code>すると疲れることでした。</p>

<p>ということで、4段組のうちまるまる1段を使ってヘルパーメソッドの一覧を羅列しました。</p>

<ul>
<li><code>abs</code>がアトリビュートの値を汚すこと（汚さないなら単に<code>abs $obj-&gt;attr</code>）</li>
<li><code>sort</code>がアトリビュートの値を汚さないこと（汚すなら<code>sort_in_place</code>）</li>
</ul>

<p>などという点で引っ掛かりそうだったので、相当する素のPerl構文も併記しています。</p>

<h3><code>MooseX::*</code>拡張モジュールに言及</h3>

<p>モジュールの名前を羅列するだけでなく、空間が余ったので使い方をごく簡単に書きました。</p>

<p><code>use MooseX::Clone;</code>なのか<code>with qw(MooseX::Clone);</code>なのかと、拡張モジュールの呼び方をすぐ忘れてしまうからです。</p>

<p>そのモジュールで書けるようになる構文も、ほんの触りだけ記述しています。</p>

<h3><code>has</code>オプションをカテゴライズしつつオレオレソート</h3>

<p>これは「最速マスター」の意図としてもご紹介しましたが、<code>has</code>のオプションをベタに羅列するのではなく、或る程度関連性のある内容を小分けにしています。</p>

<p><a href="http://d.hatena.ne.jp/hakobe932/">hakobe932さん</a>によるKansai.pm #9での<code>Moose</code>入門の発表「<a href="http://www.slideshare.net/hakobe/moose">初めてのMoose</a>」などでもネタにされるように、<code>has</code>のオプションはかなり多いです。情報を鉄砲水のように浴びせられると心が折れてしまいかねないので、多少は考慮しました。</p>

<p>また、これは完全にオレオレルールなのですが、<a href="http://blog.eorzea.asia/2009/10/post_73.html">Mooseアトリビュートのオプション指定順についての私案</a>の順番の通りに並べています。自分であんな記事を書いておきながら、まだ順番を手で覚えるまでには至っていないため、自分のためのアンチョコとして記述しています。</p>

<h2>判型と組版</h2>

<p>Moose Quick-Ref CardはA4縦で、上下方向に2つ折りにしてA5横両面で使うことを想定した組版となっています。私家版では以下のような点を考慮して変更しています。</p>

<h3>A4横1片面1枚に収めた</h3>

<p>キーボードの手前に空いているスペースはA4横の縦辺だったという理由ですが、「jQuery Cheat Sheet」など、色々なチートシートを見てもA4横が多かったので、この寸法を採用しました。</p>

<h3>4段組にした</h3>

<p>私は「机の天板に透明シートを敷いて、その下に資料を挟み込む」ということをしていません。トナーが裏移りするだとか、梅雨時にべたつきかねないだとかの理由によります。</p>

<p>従って、クリアファイルやアクリルケースに入れて使うことを想定していますが、場合によっては2つ折りや4つ折りで使うことも考えられます。さっと手にとって目を通せるという意味では、卒業式の答辞で手に持つような縦長の張扇型の方が好ましかったりするからです。</p>

<p>具体的にはオライリー刊『<a href="http://www.oreilly.co.jp/books/4873111544/">UMLデスクトップリファレンス</a>』(A5変判)などのデスクトップリファレンスシリーズなどを想定しています。</p>

<p>日本IBM刊『エンタープライズ・システム体系/370便覧』(N:GX20-0406-00)という旧世紀の遺物を例示しようとしましたが、同僚以外に分かってもらえそうにありません。<a href="http://ja.wikipedia.org/wiki/EBCDIC">EBCDIC</a>のページだけコピーしてチートシートにしたことはいい思い出です......。</p>

<p>ということで、折っても見られるような均等4段組で割り付けることにしました。電車の中での読み易さなどを考慮してか、最近では毎日に続いて読売や朝日も偶数段で組版していますね。</p>

<p>などと書いてから実際に4つ折りにしてみると、左右のマージンの考慮が漏れていて、折り目を跨いでしまっていることが判明しました。機会があれば直しておきます......。</p>

<h3>関係性を目で追えるようにした</h3>

<p>ネタは以下のように割り付けています。</p>

<ol>
<li>基本的な内容
<ul>
<li>(題名)</li>
<li>CLASSES</li>
<li>ROLES</li>
<li>METHOD MODIFIERS</li>
<li>CONSTRUCTION AND DESTRUCTION</li>
</ul></li>
<li><code>has</code>のオプション
<ul>
<li>ATTRIBUTE CONSTRUCTION OPTIONS</li>
</ul></li>
<li>型と、場所が余ったので<code>MooseX::*</code>
<ul>
<li>TYPE CONSTRAINTS &amp; COERCIONS</li>
<li>MooseX::* EXPANSION MODULES</li>
</ul></li>
<li>ネイティブトレートのヘルパーメソッド
<ul>
<li>HELPER METHODS FROM NATIVE TRAITS</li>
</ul></li>
</ol>

<p>この構成は以下のようなシナリオを想定して意図しています。</p>

<ul>
<li>1段目にあるクラスやロールのスケルトンで<code>has</code>があり、<code>has</code>のオプションが見たくなる。cf. ATTRIBUTE CONSTRUCTION OPTIONSとして飛び先を指示されるが、それはすぐ右の第2段にあるので、目で自然に追える。</li>
<li>2段目の<code>isa</code>でcf. TYPE CONSTRAINTS AND COERCIONSとして飛び先を指示されるが、それはすぐ右の第3段にあるので、目で自然に追える。</li>
</ul>

<p>ただ、流石にネイティブトレートは無理でした。それだけで第4段を占拠してしまっているので、<code>handles</code>に関連する内容として飛ばそうと思っても、第3段の型とは相乗り出来ないためです。</p>
]]>
    </content>
</entry>

<entry>
    <title>Moose &amp; Mouse基本文法最速マスターをperl-mongers.orgへ寄稿しました</title>
    <link rel="alternate" type="text/html" href="http://blog.eorzea.asia/2010/02/post_90.html" />
    <id>tag:blog.eorzea.asia,2010://1.90</id>

    <published>2010-02-17T17:15:12Z</published>
    <updated>2010-02-19T03:22:25Z</updated>

    <summary>二ヶ月弱のご無沙汰でしたが、あ、ありのまま起こったことを（略）。 MooseのM...</summary>
    <author>
        <name>Gardejo</name>
        
    </author>
    
        <category term="雑記" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="moosemouse" label="Moose/Mouse" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="Perl" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.eorzea.asia/">
        <![CDATA[<p>二ヶ月弱のご無沙汰でしたが、あ、ありのまま起こったことを（略）。</p>

<p><code>Moose</code>の<a href="http://tinyurl.com/moosequickref">Moose Quick-Ref Card</a>というクイックリファレンスカード（チートシート）へ<a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#helper_methods_from_native_traits">ネイティブトレートによるヘルパーメソッド</a>だけ追加して今風にするつもりで私家版チートシートを書いていたら、いつの間にか「<a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html"><code>Moose</code> &amp; <code>Mouse</code>基本文法最速マスター/The Fastest Way to Mastering <code>Moose</code> &amp; <code>Mouse</code></a>」になってしまいました。</p>

<p>下書きをしていたら流行りの「基本文法最速マスター」のような内容になったので、折角なので各種の情報を参考にしつつ、説明文などを追加して公開してみました。「基本」文法でないものも少なからず混じっていますが、副産物なのでご容赦ください。また、Moose用語は可能な限り元の英語を併記していますが、Moose用語以外の英語への訳出はいい加減です。ごめんなさい。</p>

<p>誤っている点, ご不明な点, 冗長すぎてかえって初学者を混乱させかねないため削除すべき点などがありましたら、上記記事へのコメントやトラックバックなどでお寄せいただければ幸いです。適宜改訂します。また、<a href="http://creativecommons.org/licenses/by/2.1/jp/">CC-BYライセンス</a>なので、「とても見ていられないので俺が全面的に書き直してしまえ」という企ても歓迎です。</p>
]]>
        <![CDATA[<h3>公開場所の選定基準</h3>

<p>出来上がったものをどこに晒そうか迷ったのですが、Perl界隈にはせっかく<a href="http://perl-users.jp">perl-users.jp</a>や<a href="http://perl-mongers.org">perl-mongers.org</a>という素敵なサイトがあるので、この場末ドメインのブログではない公の場に寄稿すことにしました。</p>

<p>昨年末にYappoさんにCodeReposのコミット権をいただいたのでperl-users.jpの方に書こうかとも考えましたが、</p>

<ul>
<li>ブログだとコメントやトラックバックなどを受け付けられ、perl-mongers.orgではすぐにでもブログ記事を書ける</li>
<li>今回のネタはperl-users.jpの単独コンテンツほど精錬されていないように思えた</li>
</ul>

<p>などの事情に鑑みて、今回はperl-mongers.orgにお世話になることにしました。</p>

<h3>苦心したこと・書くまで気付かなかったこと</h3>

<ul>
<li>何と言うこともないものですが、アトリビュート構築オプションを分類して記述してみました。羅列すると圧迫感を感じるのは人間として無理からぬことだと思うので、或る程度の関連性のあるものを小分けにしてまとめています。</li>
<li>ネイティブトレートの引数と挙動を書きました。<code>abs</code>を使ったことがなかったため、アトリビュートの値を汚すことは知りませんでした。</li>
<li>「設定」と「指定」の使い分け。アトリビュートの値をセットすることを（<code>default</code>などでセットされること）を「設定」・コードに各種のメタ操作を定義すること、記述することを「指定」と書いていますが、結構曖昧ですね......。「格納」と「記述」とかでも良かったかも知れません。</li>
<li>「オブジェクト」と「インスタンス」の使い分け。これも微妙ですが、an objectとan instance of a classの関係を気にしました。</li>
<li><code>handles</code>指定時に<code>isa</code>指定が必須であることなどは知りませんでした。私は「Moose入門研修」で「型は動的チェックなので、多用すると遅くなる」というお話を伺ったにもかかわらず偏執狂的に<code>isa</code>をほぼ必須指定しているので、なかなか気付きにくい仕様でした。</li>
</ul>

<h3>余談</h3>

<p>CodeRepos.orgやLivedoor.comのOpenIDだとサインイン出来なかったので（原因は追えていません）他の方を参考にMyOpenID.comにアカウントを作ったり、Markdownフォーマットだと<code>Wide character in subroutine entry</code>エラーが出たので素のフォーマットで書いたりと、色々ありました。</p>

<p>そしてさらに、細かな修正を行おうとしても<code>mt.cgi</code>がしばらく503になって再ログイン出来ない状態を引き起こしてしまいました（当日の昼には復帰していました）。何か私が悪いことをしてしまったか心配です。ごめんなさい。</p>

<p>ということで、取り急ぎtwitterで<a href="http://vkgtaro.jp/">vkgtaroさん</a>へお詫びというかご報告というかを差し上げました。</p>

<h3>目次（完全版）</h3>

<p>目次が膨大すぎるとかえって読む気が失せそうなので、先方には簡略版の目次だけ掲げています。当初書こうとしていた目次は、もう少し階層を深く掘った以下のようなものです。単語だけ眺めると、<code>Moose</code>のイロハは網羅できているのかな、と思っています。</p>

<p><code>role_type</code>, <code>duck_type</code>, 無名型, <code>handles</code>にロールを渡した場合の挙動, <code>DEMOLISHALL</code>, <a href="http://search.cpan.org/perldoc?Moose::Exporter"><code>Moose::Exporter</code></a>等々の記述を省いたくせにカリー化辺りが入っているのは私の独断と偏見によります。</p>

<p>Parameterized Typesが<code>Moose 0.26+</code>であるとか、かなり昔から存在する機能についてはバージョンを明記しないようにしています。ただ、その閾値の見極めは難しいです。</p>

<ul>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#classes">クラス/Classes</a>
<ul>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#turning_on_pragmas_and_importing_sugar_functions">プラグマの有効化とシュガー関数のインポート/Turning on Pragmas and Importing Sugar Functions</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#class_has_attributes">アトリビュート/Attributes</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#class_implements_methods">メソッド/Methods</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#class_extends_superclasses">スーパークラス/Superclasses</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#class_consumes_roles">ロール/Roles</a></li>
</ul></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#roles">ロール/Roles</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#sugar_functions">シュガー関数/Sugar Functions</a>
<ul>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#attribute_installation">アトリビュートの設定/Attribute Installation</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#class_inheritance">クラスの継承/Class Inheritance</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#consuming_roles">ロールの消費/Consuming Roles</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#interfaces">インターフェース/Interfaces</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#method_modifiers">メソッドモディファイヤー/Method Modifiers</a></li>
</ul></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#attribute_constructor_options">アトリビュート構築オプション/Attribute Constructor Options</a>
<ul>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#attribute_extension">アトリビュートの拡張/Attribute Extension</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#accessor_methods_generation">アクセッサーメソッドの生成/Accessor Methods Generation</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#type_constraints_and_coercions">型制約と型変換/Type Constraints and Coercions</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#constructor_arguments">コンストラクター引数/Constructor Arguments</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#lazy_building_predication_and_cleaning">値の遅延設定と設定状況/Lazy Building, Predication and Cleaning</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#default_values">デフォルト値</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#triggers">トリガー/Triggers</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#delegation_setting">委譲設定/Delegation Setting</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#documentation">文書化/Documentation</a></li>
</ul></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#types">型/Types</a>
<ul>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#type_constraints">型制約/Type Constraints</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#build_in_type_constraints">組み込みの型制約/Build-in Type Constraints</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#parameterized_types">パラメーター化された型/Parameterized Types</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#automatically_created_types">自動生成された型/Automatically Created Types</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#type_unions">型結合/Type Unions</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#to_define_your_own_types">独自の型の定義/To Define Your Own Types</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#type_coercions">型変換/Types Coercions</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#moosex_types"><code>MooseX::Types</code></a></li>
</ul></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#delegation">委譲/Delegation</a>
<ul>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#delegation_to_an_object">オブジェクトへの委譲/Delegation to an Object</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#method_currying">メソッドのカリー化/Method Currying</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#delegation_to_common_perl_data_structures">Perlの通常データ構造体への委譲/Delegation to Common Perl Data Structures</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#helper_methods_from_native_traits">ネイティブトレートによるヘルパーメソッド/Helper Methods from Native Traits</a></li>
</ul></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#construction_and_destruction_of_instances">インスタンスの生成と破棄/Construction and Destruction of Instances</a>
<ul>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#hooks_into_constructor">コンストラクターのフック/Hooks into Constructor</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#hooks_into_destructor">デストラクターのフック/Hooks into Destructor</a></li>
</ul></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#other_tidbits">その他の内容の触り/Other Tidbits</a>
<ul>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#measures_against_namespace_pollution">名前空間の汚染への対策/Measures against Namespace Pollution</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#meta_object_protocol_and_class_mop">メタオブジェクトプロトコルとClass::MOP/Meta Object Protocol and Class::MOP</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#speed_up_by_immutabilizing_metaclasses">メタクラスの不変化による高速化/Speed Up by Immutabilizing Metaclasses</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#mouse"><code>Mouse</code></a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#moosex_expansion_modules"><code>MooseX</code>拡張モジュール/<code>MooseX</code> Expansion Modules</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#oose"><code>oose</code></a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#timing_to_consuming_interfaces">インターフェースの消費タイミング/Timing to Consuming Interfaces</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#measures_against_method_conflict">メソッド衝突対策/Measures against Method Conflict</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#measures_against_testing">テスト対策/Measures against Testing</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#to_moose_or_not_to_moose">Mooseを使うか否か/To Moose or not to Moose</a></li>
</ul></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#see_also">情報源など/See Also</a>
<ul>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#manuals_for_moose">Mooseマニュアル/Manuals for Moose</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#sources_about_moose">Moose関連のその他の情報源/Sources about Moose</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#the_fastest_ways_for_mastering_basic_perl_grammer">Perl関連の基礎文法最速マスター/The Fastest Ways for Mastering Basic Perl Grammar</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#collection_of_the_fastest_ways_for_mastering_a_programming_language">基礎文法最速マスターのまとめ/Collection of the Fastest Ways for Mastering a Programming Language</a></li>
<li><a href="http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html#errata">正誤一覧/Errata</a></li>
</ul></li>
</ul>
]]>
    </content>
</entry>

<entry>
    <title>2009年の回顧と展望</title>
    <link rel="alternate" type="text/html" href="http://blog.eorzea.asia/2009/12/post_89.html" />
    <id>tag:blog.eorzea.asia,2009://1.89</id>

    <published>2009-12-31T12:52:47Z</published>
    <updated>2009-12-31T15:32:09Z</updated>

    <summary>まったく、時の経つのは早いもので、2009年の年の瀬も押し迫ってきました。夏休み...</summary>
    <author>
        <name>Gardejo</name>
        
    </author>
    
        <category term="雑記" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="perl" label="Perl" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.eorzea.asia/">
        <![CDATA[<p>まったく、時の経つのは早いもので、2009年の年の瀬も押し迫ってきました。夏休みの宿題を9月に入ってから終えるという悪癖があった私のことですから、今年を総括する記事をこんな時刻に書き始めるのも無理からぬ事です。</p>

<p>しかし、新学期の開始日と時間割を突き合わせ、例えば中学校では</p>

<ul>
<li>理科Iは月・火・金に授業がある</li>
<li>新学期は9月1日水曜日に始まる</li>
<li>故に理科Iの宿題は9月2日木曜日中に片付ければよい</li>
</ul>

<p>という嫌らしい打算で生きて来た私にとっては、むしろこのくらいが普通の生き様とも言えます。</p>

<p>ともあれ、今年2009年を一言で表現するのであれば、ただひたすら「感謝」の一年だった、ということになります。</p>
]]>
        <![CDATA[<h2>Perlの催事へ参加</h2>

<p>今年は</p>

<ul>
<li><a href="http://yokohama.pm.org/2009/04/yokohamapm-4-2.html">Yokohama.pm #4</a></li>
<li><a href="http://conferences.yapcasia.org/ya2009/">YAPC::Asia 2009</a></li>
<li><a href="http://shibuya.pm.org/blosxom/techtalks/200911.html">Shibuya.pm Tech Talks #12</a></li>
</ul>

<p>などの催事に参加させていただきました。</p>

<p>参加報告が尻切れだったり、そもそも書けていなかったりします（ごめんなさい！）が、とても多くのことを学び、そしてそれ以上に私の意識を大きく揺さぶられることとなりました。その甲斐もあって、いちPerlファンから、いちPerl戦士にクラスチェンジした感があります。</p>

<p>当たり前のようですがどんなソフトウェアも、それを作り上げた「中の人」がいます。そしてその人の顔が見えると、そのソフトウェアへの愛着が増します。そしてその中の人が語る場は、そのソフトウェアの顔を知らしめるものともなります。</p>

<p>掛け替えのない体験をさせてくださった、催事関係者の皆様に感謝です。</p>

<p>なお、Yokohama.pmでは体調不良もありました。やはり体が資本のこの業界、自分の体を大切にしないといけないなと反省しているところです。</p>

<h2>CPANにコントリビュート</h2>

<p><a href="http://www.cpan.org/">CPAN</a> authorsの<a href="http://search.cpan.org/~moriya/">仲間入りを果たしました</a>。今年は</p>

<ul>
<li><a href="http://search.cpan.org/perldoc?MooseX::Types::Locale::Language"><code>MooseX::Types::Locale::Language</code></a></li>
<li><a href="http://search.cpan.org/perldoc?MooseX::Types::Locale::Country"><code>MooseX::Types::Locale::Country</code></a></li>
<li><a href="http://search.cpan.org/perldoc?DBICx::Modeler::Generator"><code>DBICx::Modeler::Generator</code></a></li>
</ul>

<p>の3本をリリースしたことになります。</p>

<p>YAPC::Asia 2009のLightning Talksで、<a href="http://d.hatena.ne.jp/charsbar/">charsbarさん(石垣さん)</a>のTop Tens of 2008/2009の講演を拝聴して、CPAN authorsの多さや、YAPC::Asia 2008以降に初登場した人の数の多さに驚愕したことが切っ掛けだったのかも知れません。夕暮れの仄暗い会場で、我こそはCPAN authorだとして手を挙げた人の、それはもう多かったこと。今でも思い出せます。</p>

<p>そして、CPANに上げてみようとして始めて、CPANを含めたPerlの思想や文化への理解を（おぼろげながらにでも）深められたような気がします。ソフトウェアICとも称されるCPANモジュールは、モジュールのユーザーからすればそれこそ「水や空気」のように当たり前のようにそこにあるものとして便利に使って来ました。しかし、自分がCPAN authorsの末席を汚すようになって始めて、「<a href="http://slashdot.jp/~taro-nishino/journal/475752">何故、私はPerlを続けるのか</a>」にあるような</p>

<blockquote>
  <p>ライブラリの存在は更に容易にライブラリを書かせる。サイクルがそれ自身に餌を与える。すなわち、我々は多くのライブラリを持っている、それが別のライブラリを簡単に書かせ、更に多くなって、別のライブラリを書くことが更に簡単になる</p>
</blockquote>

<p>という基盤があってこそ、CPANモジュールユーザーやCPAN authorsが恩恵を享受出来るのだということを肌で理解出来たような気がします。</p>

<p>CPANという仕組みそれ自体や、多くの前提モジュールの作者の方々に感謝です。</p>

<p>本当は<a href="http://www.cpan.org/">Text::UTX::Simple</a>がCPANデビュー作となるはずでしたが、これは<a href="http://github.com/gardejo/p5-text-utx">Text::UTX</a>として2010年1月中にリリースする予定です。私にしては珍しく期限を切っているのは、<a href="http://www.aamt.info/english/journal.htm">AAMT Journal</a>への寄稿の締め切りがある所為です。相変わらず綱渡りの人生ですね......。</p>

<h2>Blogの引っ越し</h2>

<p>これまでは、サイドバーの「やや真面目なサイト」に掲げている「<a href="http://ttt.ermitejo.com/">エスペラント語日本語翻訳Ermitejo</a>」の開発日誌としてブログを書いていました。一方、（一応）このブログのドメイン名が語っているように、来年サービスイン予定のMMORPGであるFF14用のウェブアプリケーションの開発日誌として<a href="http://blog.eorzea.asia/2009/06/post_2.html">2009年6月末に開始した</a>はずのこのEorzea Loungeですが、気付いたらその他の事についての記述が多くなっていました。</p>

<p>「その他」といっても主にはPerl勉強日誌的なものですが、上述の<a href="http://blog.eorzea.asia/2009/09/post_61.html">YAPC::Asia 2009の報告</a>や、<a href="http://blog.eorzea.asia/2009/08/post_57.html">LLTVの報告</a>などは多くの方にご覧いただいたようで、会場の熱気や催事の素晴らしさを少しでもお伝え出来たのならば嬉しいです。</p>

<p>WordPressよりもMovable Typeの方が性に合っていただとか、Permalinkをいちいち考えるのが面倒臭かった（このブログはエントリーIDがPermalinkになっています）だとか、諸々の理由がありますが、ともかく何となくこちらのブログを更新することになったようです。</p>

<p>各ウェブアプリケーションに紐付く話題とは別に、その他のこと全般を書くブログをこしらえた方が良いかとも思いましたが、取り敢えずもう後の祭りなのでしばらくこのままで運用していこうと思います。</p>

<p>分不相応にも多くの方にブックマークしていただけた記事もあったようで、記事の題材である催事関係者の方々や、読んでくださった方々に感謝です。</p>

<h2>Mooseを使い始めました</h2>

<p><a href="http://search.cpan.org/perldoc?Moose"><code>Moose</code></a>/<a href="http://search.cpan.org/perldoc?Mouse"><code>Mouse</code></a>を使い始めて、Moose信者になりました。事情があって公開は出来ないのですが、証券関係のWindows向けの2万行強のアプリケーションを会社勤めの傍ら1ヶ月程で<code>Mouse</code>で書ききったことが、一つの転機となりました。</p>

<p>基本的に私は頭の回転が遅いので、何事も使ってみて始めて分かるという面倒臭い性格をしていますが、OOの利点が使ってみなければ分かりにくいことと同様で、まず使ってみて正解だったと思います。今ではもう、ごく限られた場合を除いては、Perl OOでMoose/Mouseを利用しないことは考えられません。</p>

<p>Perlのモジュール等を使い始めて、それについてググったりすると、自分が1年や2年ほど周回遅れをしていることがよく分かります。しかし、いわゆるアーリーアダプターなPerl Hackerの方々がブログで書かれた内容がちんぷんかんぷんだった時代と比べれば、時間を経たとしても「あぁ、これはこういうことを言っているのか」と分かるようになったというのは、とても嬉しい物があります。</p>

<p><a href="http://blog.eorzea.asia/2009/09/post_65.html">Moose入門研修の素晴らしさ</a>にほだされて<a href="http://blog.eorzea.asia/2009/10/post_70.html">スライドの日本語訳</a>を書き始めましたので、未訳部分の補完などを含め、定期的に保守していきたいです。</p>

<p><code>Moose</code>/<code>Mouse</code>のメンテナーやコントリビューターの皆様や、研修関係者の皆様に感謝です。</p>

<h2>gitの利用とGitHubの利用</h2>

<p>上記のWindows向けアプリケーションまではSubversionを使っていたのですが、色々と思うところがあって、VCSをgitに移行しました。その一番の理由は、GitHubでなんだか楽しそうなことをしているなぁ、というものでした。ということで、<a href="http://github.com/gardejo">GitHubのアカウント</a>を取っていくつかのモジュールを公開し始めました。</p>

<p>gitやGitHubをまだ十全に活用出来てはいませんが、<a href="http://search.cpan.org/perldoc?DBICx::Modeler"><code>DBICx::Modeler</code></a>というCPANモジュールへテストを含めて<a href="http://github.com/gardejo/dbicx-modeler/commit/5dadb20b3bf1ac36cd05c605bf860d3086d4408f">数行のパッチ</a>をお送りすることが出来たりと、その可能性に気付かされました。</p>

<p>GitHub運営者の方々や、GitHubで惜しげもなくご自分のソフトウェアの開発過程を公開してくださる方々に感謝です。</p>

<h2>JPerl Advent Calendar 2009に寄稿</h2>

<p>上記の<code>Moose</code>と<code>DBICx::Modeler</code>に関連して、FF14向けウェブアプリケーションの開発に際して「<a href="http://blog.eorzea.asia/2009/10/post_76.html">ORMスキーマとドメインモデルを統合する方法・分離する方法</a>]という記事を書きました。また、これに関連して、<a href="http://search.cpan.org/perldoc?DBICx::Modeler::Generator"><code>DBICx::Modeler::Generator</code></a>というモジュールをCPANに上げました。</p>

<p>元々オレオレモジュールとして細々と書いていたものでしたが、Shibuya.pm Tech Talks #12でtokuhiromさん(松野さん)が<a href="http://perl-users.jp/articles/advent-calendar/2009/">JPerl Advent Calendar 2009</a>の<a href="http://perl-users.jp/articles/advent-calendar/2009/hacker/">hacker track</a>の執筆者が不足していると仰るのを伺って一念発起し、勢いでCPANizeしつつ、空気を読まず<a href="http://perl-users.jp/articles/advent-calendar/2009/hacker/22.html">DBICx::Modeler::Generatorでスキーマクラス群とモデルクラス群を一発生成しよう</a>という記事を書かせていただきました。hacker trackも無事完走して、とてもほっとしています。</p>

<p>発起人の<a href="http://d.hatena.ne.jp/tokuhirom/">tokuhiromさん(松野さん)</a>をはじめ、関係者の皆様に感謝です。</p>

<p><a href="http://blog.yappo.jp/">yappoさん(大沢さん)</a>にお願いして<a href="http://coderepos.org/">CodeRepos</a>のcommit権をいただいたので、GitHubだけでなくCodeReposでも何か公開していきたいと思います。</p>

<h2>2010年の抱負</h2>

<p>2010年は</p>

<ul>
<li>CPANモジュールText::UTXの公開</li>
<li>FF14向けウェブアプリケーション「<a href="http://eorzea.asia/amikeco/">Amikeco</a>」のサービスイン</li>
<li><a href="http://ttt.ermitejo.com/">エスペラント日本語翻訳システム</a>の開発進展、およびGitHubかCodeReposでの公開</li>
<li>聞く側としての参加だけでなく話す側としての催事への参画</li>
</ul>

<p>などを目標にしたいと思います。来年もまた感謝のし通しの一年となりそうです。</p>

<p>それでは、良いお年を(Feliĉan jaron)!</p>
]]>
    </content>
</entry>

<entry>
    <title>地球時間と仮想世界の時間を相互変換する日付時刻クラス</title>
    <link rel="alternate" type="text/html" href="http://blog.eorzea.asia/2009/12/post_88.html" />
    <id>tag:blog.eorzea.asia,2009://1.88</id>

    <published>2009-12-24T15:39:03Z</published>
    <updated>2009-12-25T16:53:52Z</updated>

    <summary>アセトアルデヒドの勢いで変な物を書いたような気がします。書きかけですけれども。 ...</summary>
    <author>
        <name>Gardejo</name>
        
    </author>
    
        <category term="開発日誌" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="finalfantasyxiv" label="Final Fantasy XIV" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="moosemouse" label="Moose/Mouse" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.eorzea.asia/">
        <![CDATA[<p>アセトアルデヒドの勢いで変な物を書いたような気がします。書きかけですけれども。</p>

<p><a href="http://github.com/gardejo/p5-games-datetime"><code>Games::DateTime</code> - A simple date and time object on any games</a></p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="screenshot_of_p5-games-datetime.png" src="http://blog.eorzea.asia/2009/12/26/screenshot_of_p5-games-datetime.png" width="580" height="388" class="mt-image-none" style="" /></span></p>

<p>たまには脇道に逸れて、ff14.nameおよびff14.asia向けの部品的なモジュールを書くというのも、気分転換に良いかも知れません。何に対しての気分転換かというと、独り身の帰宅路で涙にむせぶ件といったところでしょうか。</p>

<p>上掲のスクリーンショットのような「時計」であればFlashやJavaScriptでもよく見掛けるのですが、「ローカルタイムな地球現在時→仮想世界の現在時」以外に</p>

<ul>
<li>仮想世界の日時→地球の日時方向への変換</li>
<li>ローカルタイム以外のタイムゾーンへの対応</li>
<li>地球日時もしくは仮想世界の日時の指定</li>
<li>時間計算（地球および仮想世界の両方）</li>
</ul>

<p>などが出来る「日付時刻クラス」というのは寡聞にして知らないので、書きました。取り敢えずググって要件を見つけられたのはFF11だけでしたが、起点日時の対称が見付かれば、プレースホルダー的に置くだけ置いたEverQuestなどの実装にも対応出来るかも知れません。</p>

<p>ちなみにスクリーンショットの時計はライブラリー本体ではなく<code>examples</code>ディレクトリー以下のおまけである<a href="http://github.com/gardejo/p5-games-datetime/blob/master/examples/lib/Games/DateTime/Clock.pm"><code>Games::DateTime::Clock</code></a>です。ff14.nameやff14.asiaでは、最終的にはこれと<code>Games::DateTime</code>をJavaScriptに移植することになります。</p>

<p>なお、<code>Acme::*</code>以下の名前空間にするかどうかは考え中です。また、テストは酔いが覚めてから書く予定です。などと書いていると肝臓が明日も泣きそうな気がします。</p>

<p>備忘録ですが、<a href="http://search.cpan.org/perldoc?MooseX::AbstractFactory"><code>MooseX::AbstractFactory</code></a>で、ファクトリーメソッドに指定する具象クラス名（の一部）を指定する際にエイリアスを使えるようにしています。ただし<code>HashRef</code>を渡さずにエイリアスクラス名（の一部）を渡す際には、宝箱を開ける為の鍵が当該宝箱の中にあるような状態で、いまいちです。</p>

<p><code>Moose</code>の型制約を遅延設定する<a href="http://github.com/gardejo/p5-games-datetime/blob/master/lib/MooseX/Types/Games/DateTime.pm"><code>MooseX::Types::Games::DateTime</code></a>辺りの小細工（実装クラスに依存して<code>where</code>ブロック内の振る舞いを規定する、など）については、稿を改めようと思います。</p>

<ul>
<li>1日24時間という世界の具象クラスでは<code>hour</code>が<code>0 &lt;= $_ &amp;&amp; $_ &lt; 24</code>の範囲になり、</li>
<li>1日30時間という世界の具象クラスでは<code>hour</code>が<code>0 &lt;= $_ &amp;&amp; $_ &lt; 30</code>の範囲になる</li>
</ul>

<p>という要件があったときに、事前に（静的に）それぞれ別の型制約を作らずに、最大値を具象クラスから引っこ抜いて型制約で使うということです。これもまたいまいちな実装ですけれども。</p>

<p><ins><em>追記</em></ins>: テストを薄く書いてバグを除いたほか、見本の時計はロケールにも対応させました。また、cp932でなくUnicodeなコンソールでの字詰めの問題等々を解消しています。上記スクリーンショットも差し替えています。全角半角の「文字幅」の取り扱い方については、（時間があれば）稿を改めて備忘録を起こす予定です。</p>
]]>
        

    </content>
</entry>

<entry>
    <title>JPerl Advent Calendar 2009 hacker track: 22nd day</title>
    <link rel="alternate" type="text/html" href="http://blog.eorzea.asia/2009/12/post_87.html" />
    <id>tag:blog.eorzea.asia,2009://1.87</id>

    <published>2009-12-22T03:01:31Z</published>
    <updated>2009-12-23T13:34:01Z</updated>

    <summary>JPerl advent calendar 2009 hacker trackの...</summary>
    <author>
        <name>Gardejo</name>
        
    </author>
    
        <category term="雑記" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="dbic" label="DBIC" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="orマッパー" label="O/Rマッパー" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="orochi" label="Orochi" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="Perl" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.eorzea.asia/">
        <![CDATA[<p><a href="http://perl-users.jp/articles/advent-calendar/2009/hacker/">JPerl advent calendar 2009 hacker track</a>の<a href="http://perl-users.jp/articles/advent-calendar/2009/hacker/22.html">22日目を執筆</a>させていただきました。</p>

<p>補足情報を簡単に記します。</p>
]]>
        <![CDATA[<h2><code>DBICx::Modeler::Generator</code>のご紹介</h2>

<p>採り上げたCPANモジュールは、拙作<a href="http://search.cpan.org/perldoc?DBICx::Modeler::Generator"><code>DBICx::Modeler::Generator</code></a>です。</p>

<ul>
<li><a href="http://search.cpan.org/perldoc?DBIx::Class::Schema::Loader"><code>DBIx::Class::Schema::Loader</code></a>による<a href="http://search.cpan.org/perldoc?DBIx::Class"><code>DBIx::Class</code></a>スキーマクラス群の生成</li>
<li><code>DBIx::Class</code>スキーマと<a href="http://search.cpan.org/perldoc?Moose"><code>Moose</code></a>とを仲立ちする<a href="http://search.cpan.org/perldoc?DBICx::Modeler"><code>DBICx::Modeler</code></a>モデルクラス群の生成</li>
</ul>

<p>をラップする（だけ）のヘルパーモジュールです。元々先月末くらいから自分用に作っていたのですが、本稿の執筆を想定して先日CPANizeしたものです。若干、手段の自己目的化のきらいがありますが......。</p>

<p>ただ、このモジュールの紹介というよりは、むしろPoEAAでいうところのDomain Modelパターン讃歌のような趣になりました。以前の記事「<a href="http://blog.eorzea.asia/2009/10/post_76.html">ORMスキーマとドメインモデルを統合する方法・分離する方法</a>」と<code>DBICx::Modeler::Generator</code>のPODを鍋に入れた感じです。</p>

<p>MySQL Workbench以外のツールは、「<a href="http://blog.eorzea.asia/2009/08/post_54.html">ER図の描画ツールを求めて三千里</a>」などでもご紹介しています。</p>

<h2><code>Orochi</code> + <code>MooseX::Getopt</code> + <code>MooseX::SimpleConfig</code> = 便利</h2>

<p>日曜プログラマーとして補足しておきたい点として、</p>

<ul>
<li>DIフレームワークである<a href="http://search.cpan.org/perldoc?Orochi"><code>Orochi</code></a>および<code>Moose</code>クラスをアノテートする<a href="http://search.cpan.org/perldoc?MooseX::Orochi"><code>MooseX::Orochi</code></a></li>
<li><code>Moose</code>アトリビュートの初期化を<a href="http://search.cpan.org/perldoc?Getopt::Long"><code>Getopt::Long</code></a>式に行う<a href="http://search.cpan.org/perldoc?MooseX::Getopt"><code>MooseX::Getopt</code></a></li>
<li><code>Moose</code>アトリビュートの初期化を設定ファイルから引き込む<a href="http://search.cpan.org/perldoc?MooseX::SimpleConfig"><code>MooseX::SimpleConfig</code></a></li>
</ul>

<p>を合わせて利用すると、</p>

<ul>
<li>中身は<code>Moose</code>クラスやロールを多用して整然と書いておき</li>
<li>ユーザーインターフェースではそれらクラス・ロールに分散する設定値をまとめて指定する</li>
</ul>

<p>ことが出来て便利だ、ということが挙げられます。</p>

<h2>泣き言: casual trackが埋まってしまった......</h2>

<p>本来<a href="http://perl-users.jp/articles/advent-calendar/2009/casual/">casual track</a>向けとして想定していた内容ですが、そちらの投稿者枠はあっという間に埋まってしまいました。その一方、<a href="http://shibuya.pm.org/blosxom/techtalks/200911.html">Shibuya.pm Tech Talks #14</a>に於いてtokuhiromさんがhacker trackの投稿者が足りていないとおっしゃったので、ハッカーでない一般人としてですが、末席を汚した次第です。</p>

<p>野球としては右方向への流し打ちで、プランシー=パウエル神父の箴言としては「次の世代のための道をつくるだけでよい」といったところでしょうか。舗装された道ではなく、砂利道でもなく、せいぜい獣道くらいの出来映えで恐縮ですが。</p>

<h2>執筆者をまだまだ募集中です！</h2>

<p>さて、25日目までにはあと3日間ありますが、<a href="http://atnd.org/events/2275">ATND</a>で宣言のあった限りでは、キュー内の執筆者が空の状態です。自作のCPANモジュールだけでなく、Perl Hacksっぽいことでも書けるそうです。</p>

<p>我こそは、と思う方は、どうかこの道を最後まで繋げてください！</p>
]]>
    </content>
</entry>

<entry>
    <title>FF14ベータテスターへ応募</title>
    <link rel="alternate" type="text/html" href="http://blog.eorzea.asia/2009/12/post_86.html" />
    <id>tag:blog.eorzea.asia,2009://1.86</id>

    <published>2009-12-17T13:35:10Z</published>
    <updated>2009-12-17T14:31:38Z</updated>

    <summary>本サイトはFF14のプレイヤー向けウェブシステムの開発日誌という位置付けですので...</summary>
    <author>
        <name>Gardejo</name>
        
    </author>
    
        <category term="雑記" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="betatest" label="beta test" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="finalfantasyxiv" label="Final Fantasy XIV" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.eorzea.asia/">
        <![CDATA[<p>本サイトはFF14のプレイヤー向けウェブシステムの開発日誌という位置付けですので、FF14の話題にも触れておきます。</p>

<p>遂に<a href="http://jp.finalfantasyxiv.com/newsletter/091217/index.html">FF14のベータテスターの募集が始まりました</a>。2010年の正式サービス開始予定を前に、開発も佳境に入っていることとお見受けします。大変期待の持てる作品であり、末永く愛されることを願ってやみません。</p>

<p>さて、応募に際しては必要事項を色々記入することになりますが、いくつか気掛かりな内容がありました。といっても、馬鹿正直に書いた内容が裏目に出たらどうしよう、という心配事でしかないのですが。</p>
]]>
        <![CDATA[<h2>環境</h2>

<p>物理的資源と人的資源のいずれも、正直に回答しましたが心配の種を播いてもいます。</p>

<h3>CPU</h3>

<p>まず、CPUです。これはまずい。私が主に使っている環境は少々特殊で、何せラジオボタンの選択項目には使用しているCPUが存在しないという有様です。</p>

<p>サーバーおよびワークステーション用CPUの選択肢がないことは理解出来るのですが、これで「うげっ、こいつはもしかしてPentium IIとかで動かしているのか？」などと思われて落とされないか、戦々恐々です（一部誇張あり）。</p>

<h3>OS</h3>

<p>主に使っている環境は未だにWindows XP Professional SP3です。モバイルPCではWindows Vistaの荘重な......と言葉を飾っても仕方がないので正直に書きますと「緩慢な」動作に感銘を受けて、Ubuntuを入れたりしています。</p>

<p>一方で、運営側にとって一番ありがたいのは、やはりWindows 7でのテストでしょう。売り止められてサポート期限も切られているWindows XPなどより、サービス開始を起点として一番長い寿命を見込めるWindows 7の方が、テストの</p>

<p>4年前に構築した自作ワークステーションは、Super πなどではまだまだ会社で使っている最新のPCをも蹴散らす成績を残していますけれども、流石にそろそろマザーボードごと交換しようとも考えていますので、その時にはWindows 7を載せようと思います。</p>

<p>ただし、それはあくまで未来の話。現時点では正直にXPと書くしかないので、「何だかんだ言ってもまだまだサービス開始時点ではXPユーザーが一番多いのではないか」という希望的観測を展開することにしました。</p>

<h3>貢献時間</h3>

<p>テスターとして貢献出来る時間も、少々心配です。平日は21～25時に帰宅するとして、頑張って2時間くらいと計算します。休日は寝溜めをするような非生産的な時間が多いのですが、この生活を見直して4～5時間。しめて「週12時間以上～24時間未満」の枠に収まります。</p>

<p>かつてEverQuestなどで頑張っていた時代（といっても殆どが大学生時代ですが）とはかなり見劣りがするかも知れません。いわゆる廃人などと称されるハードコアプレイヤーの方々と、いわゆるカジュアルプレイヤーの間に位置する、私のようなミドルレンジのプレイヤーが一番多いのではないだろうかと勝手に想像しています。ただ、あくまでテストなので、システム実装的な問題点の確認および報告を行うためには、貢献時間の長さが物を言うことは言うまでもありません。</p>

<p>ということで不安は不安なのですが、設計面やバランス調整など、ミドルレンジのプレイヤーならではの視点で貢献出来る余地があるのではないかとも思いますので、</p>

<h2>意向調査</h2>

<p>「環境調査」に比べて「意向調査」の色合いが強い項目は、心配の種にならない分、熟慮して回答しました。</p>

<h3>訴求点</h3>

<ul>
<li>他のプレイヤーとの交流</li>
<li>強い敵との戦闘</li>
<li>世界観</li>
</ul>

<p>「上位3つまで」という質問でしたが、順番をさらに付けるとしたら上記の通りになります。伝統的EQプレイヤーの回答ですね。他のプレイヤーとの濃厚な交流を旨とし、それをよすがとしてレイドエンカウンターとの交戦を行うという（PvPではなく）PvE重視で、それらを緻密に織りなされた世界観に抱かれて満喫するという案配です。</p>

<h3>FFシリーズに対する情熱</h3>

<p>これは大変答え難い質問ですが、私は100点満点中99点としました。</p>

<p>オフライン作品には初代からお世話になって来ました。大学生・社会人になってからは流石に全作品に手を伸ばせている訳ではありませんが、安心して財布の口を開けられるシリーズだと思っています。</p>

<p>オンライン作品については、世間一般では色々な意見が（オフライン作品以上に）あることと思いますが、その運営品質は比較第一級に位置すると考えます。不正行為への厳正な対処は、「当たり前のことを当たり前にする」ことの難しさも相まって、高く評価したい点です。</p>

<p>しかし、いずれも完全というものはありません。そうした「伸びしろ」が満点への差分ということになります。ということで伸びしろは1点分ということになりましたが、今にして思えばもう少し差分を大きく取った方が良かったかも知れません。「テスターに必要なのは太鼓持ちではなくて、真摯な評価者だ！」と突っぱねられる可能性があるからです。</p>

<p>しかし、上記のような採点根拠を<code>string</code>型で書けない以上、<code>integer</code>型の値でのみ表現する必要があるので、あまり低すぎると「嫌いな人にテストしてもらいたくないね！」と突っぱねられる危険性もあります。</p>

<h2>今後の展望</h2>

<p>大学生時代と違って、業務に於けるテストの重要性は骨の髄まで染みこみました。テスターに選出いただけた暁には、誠心誠意テストに励む所存です。また、FF14プレイヤー向けウェブシステム「<a href="http://eorzea.asia/amikeco/">Amikeco</a>」も、ベータテストに後れを取らないよう、開発にさらに発破を掛ける所存です。</p>

<p>といっても、テスターに選出されたことの表明自体がNDAに抵触する可能性もありますので、未来は何とも言えませんが......。</p>
]]>
    </content>
</entry>

<entry>
    <title>備忘録: Orochiで依存の逆順にinject_classしないこと</title>
    <link rel="alternate" type="text/html" href="http://blog.eorzea.asia/2009/12/post_85.html" />
    <id>tag:blog.eorzea.asia,2009://1.85</id>

    <published>2009-12-07T16:23:08Z</published>
    <updated>2009-12-07T16:33:15Z</updated>

    <summary>PerlのDIコンテナーであるOrochiは、作者である牧さん(lestrrat...</summary>
    <author>
        <name>Gardejo</name>
        
    </author>
    
        <category term="雑記" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="dbic" label="DBIC" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="di" label="DI" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="moosemouse" label="Moose/Mouse" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="orochi" label="Orochi" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="Perl" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.eorzea.asia/">
        <![CDATA[<p>PerlのDIコンテナーである<a href="http://search.cpan.org/perldoc?Orochi"><code>Orochi</code></a>は、作者である牧さん(lestrratさん)ご本人が<a href="http://fukuoka.pm.org/">Fukuoka.pm</a>の<a href="http://fukuoka.pm.org/2009/10/fukuoak-perl-workshop-14.html">Fukuoka Perl Workshop #14</a>の<a href="http://users.endeworks.jp/~daisuke/presentations/fukuoka-pm/fukuoka_perl_workshop14.pdf">スライド</a>のp.46で「循環依存の解決は実装できてない」と書いていらっしゃいます（参考：平田さんの「<a href="http://p-lab.freeflux.net/blog/archive/2009/11/15/post-119.html">Fukuoka Perl Workshop #14に行ってきた</a>」の記事）。</p>

<p>ただし、これは私にとっては特段の制約事項とは感じません。循環依存するようなクラスは、場合にもよりますが、私の場合には大抵クラス設計を誤って陥る泥沼状態であるからです。</p>

<p>とはいえ、クラスが複雑に絡み合う事態は起こり得るので、依存関係には気を付ける必要があります。ただ単に依存がぐるぐる回ってバターにならないようにすることは勿論ですが、依存関係を実際に注入する処理でも気を付ける必要があります。この処理は、dannさんの記事の通り、Java界隈ではwiring（ワイヤリング）という用語が充てられます。</p>

<p>で、そのwiringで気を付けるというのは、具体的には、<code>inject_class</code>の実行順が依存の逆順であってはならない、という点です。当たり前といえば当たり前なのですが、うっかりしていました。</p>

<p>以下はその備忘録と解説です。</p>
]]>
        <![CDATA[<h2>Windowsで通ったテストがUbuntuで通らない</h2>

<h3>インスタンスが入って来ない</h3>

<p>事の発端は、拙作<a href="http://github.com/gardejo/p5-dbicx-modeler-generator"><code>DBICx::Modeler::Generator</code></a>のテストです。なお、このモジュールについては、CPANに上げる価値があるのか、CPANモジュール足り得る品質を満たしているのかをもう少し見極める必要があると考えています。</p>

<p>さて、自宅での専らの開発環境がUnix系（2割）ではなくWindows（8割）であるという、geekのgの字も見えない一般人な私は、Windows環境でテストを終えたつもりになりました。いざUnix系環境でのテストと、石垣さん(charsbarさん)が紹介している、<a href="http://d.hatena.ne.jp/charsbar/20080928/1222570663"><code>chmod</code>がちゃんと動く<code>make dist</code></a>を行おうと勇躍してUbuntuを立ち上げた私は、以下のようなエラーでテストに躓いてしまいました。</p>

<pre><code>Attribute (tree) does not pass the type constraint because:
Validation failed for 'DBICx::Modeler::Generator::TreeLike' failed
with value Orochi::Injection::BindValue=HASH(0x5921b8)
</code></pre>

<p>要は<code>tree</code>アトリビュートでは<code>TreeLike</code>インターフェース(<code>Moose::Role</code>)を満たす値を想定していたのに、蓋を開けてみたらそんなインスタンスじゃなくて<code>Orochi::Injection::BindValue=HASH(0x5921b8)</code>という値が入っていたよ、ということです。</p>

<h3>依存が未解決であるという印</h3>

<p>実はこの問題には以前にもはまったことがあって、依存が未解決の値を使おうとするとこうなります。インスタンスだけでなくて、例えば<code>Str</code>などの型を想定していても同様です。</p>

<p>実際のDIの定義（<code>MooseX::Orochi</code>でエクスポートして使う<code>bind_constructor</code>）と注入処理（ワイヤリング）部では、その<code>tree</code>アトリビュートを規定する<code>/DBICx/Modeler/Generator/Tree</code>レジストリーだけを着目すると確かに問題なさそうに見えます。</p>

<p>例えばこの場合は<a href="http://github.com/gardejo/p5-dbicx-modeler-generator/tree/v0.00"><code>v0.00</code>タグ</a>で、</p>

<dl>
<dt>依存関係をクラスの<code>meta</code>アトリビュートへ設定する箇所</dt>
<dd><a href="http://github.com/gardejo/p5-dbicx-modeler-generator/blob/v0.00/lib/DBICx/Modeler/Generator/Driver/SQLite.pm#L51"><code>DBICx::Modeler::Generator::Driver::SQLite</code>の54行目</a></dd>
<dt>依存を注入する(ワイヤリングする)箇所</dt>
<dd><a href="http://github.com/gardejo/p5-dbicx-modeler-generator/blob/v0.00/lib/DBICx/Modeler/Generator/CLI.pm#L252"><code>DBICx::Modeler::Generator::CLI</code>の252行目</a>や、実際のクラス名群をこしらえている<a href="http://github.com/gardejo/p5-dbicx-modeler-generator/blob/v0.00/lib/DBICx/Modeler/Generator/CLI.pm#L182">182行目付近</a></dd>


</dl>

<p>がこれにあたります。</p>

<p>しかし、注入時の順番にも注意が必要なのです。<a href="http://github.com/gardejo/p5-dbicx-modeler-generator/tree/v0.0001"><code>v0.0001</code>タグ</a>の<a href="http://github.com/gardejo/p5-dbicx-modeler-generator/blob/v0.0001/lib/DBICx/Modeler/Generator/CLI.pm#L310">同310行目</a>に書きました通り、このアプリケーションは7段の依存関係があります。</p>

<ol>
<li><code>DBICx::Modeler::Generator</code></li>
<li><code>DBICx::Modeler::Generator::Schema</code></li>
<li><code>DBICx::Modeler::Generator::Driver</code></li>
<li><code>DBICx::Modeler::Generator::Model</code></li>
<li><code>DBICx::Modeler::Generator::Path</code></li>
<li><code>DBICx::Modeler::Generator::Tree</code></li>
<li><code>DBICx::Modeler::Generator::Class</code></li>
</ol>

<p>無駄にクラスを量産しすぎたきらいがありますが、ともあれ、この順番を覆して（以下のような順番で注入して）しまうと、場合によっては値が未解決のままインスタンスを生成しようとしてしまいます。</p>

<pre><code class="perl">return [
    qw(
        DBICx::Modeler::Generator
        DBICx::Modeler::Generator::Class
        DBICx::Modeler::Generator::Model
        DBICx::Modeler::Generator::Path
        DBICx::Modeler::Generator::Schema
        DBICx::Modeler::Generator::Tree
    ),
    'DBICx::Modeler::Generator::Driver::' . $self->driver,
];</code></pre>

<h3>ちゃんと末端から根本の順に注入する</h3>

<p>ということで、葉から枝へ、幹へ、値へというように末端から順にインスタンスを生成していかなければなりません。</p>

<p><a href="http://github.com/gardejo/p5-dbicx-modeler-generator/blob/v0.0001/lib/DBICx/Modeler/Generator/CLI.pm#L182"><code>v0.0001</code>での同182行目</a>付近では、以下のように真っ当な順番にしました。</p>

<pre><code class="perl">return [
    qw(
        DBICx::Modeler::Generator::Class
        DBICx::Modeler::Generator::Tree
        DBICx::Modeler::Generator::Path
        DBICx::Modeler::Generator::Model
    ),
    'DBICx::Modeler::Generator::Driver::' . $self->driver,
    qw(
        DBICx::Modeler::Generator::Schema
        DBICx::Modeler::Generator
    ),
];</code></pre>

<p>これで、クラス間での依存関係は循環していないのに、依存の逆順でインスタンスを生成しようとしてテストに失敗することがなくなりました。めでたし、めでたし。</p>

<h2>何故Windows環境ではテストに成功したのか</h2>

<h3>クラス生成で生じる差異</h3>

<p>しかし、そもそも全く同じコードなのに、何故Widnows環境とUbuntu環境でテスト結果が異なるのでしょうか。これが<code>DBD::mysql</code>や<code>DBD::SQLite</code>などに密接に関わったテストであればともかく、クラスの生成で差異が出るのは気持ち悪いところです。</p>

<h3>ハッシュ関数の挙動ではなかろうか</h3>

<p>テストが通った後によく考えてみた結果、これは完全に憶測なのですが、(ユーザーによる大文字PなPerlプログラムという意味ではなく、処理系としての小文字pな)<code>perl</code>のハッシュ関数の挙動が異なる所為ではないかと踏んでいます。</p>

<p>というのも、当の<a href="http://github.com/gardejo/p5-dbicx-modeler-generator/blob/v0.0001/lib/DBICx/Modeler/Generator/Driver/SQLite.pm#L44">実装クラス側で<code>bind_constructor</code>関数に渡す<code>arg</code>ハッシュキーに該当する値</a>はハッシュリファレンスになっています。ハッシュであるから、リストと違って順番は無視されます。</p>

<p>その順番は、ハッシュキーをハッシュ関数に通して得られるハッシュ値の順番なので、これは<code>perl</code>のエディションやバージョンによって異なるのはいかにもそれっぽいです。</p>

<p>そして、Windows環境でテストした際には、このハッシュ値の順が「たまたま」循環依存しない順番であったために、<code>lazy_build</code>が奏功して依存の逆順でも動く処理となっていて、問題が生じなかったのではないだろうか......という推測です。つまり、たまたまWindowsだから免れたというのではなく、ハッシュキーの構成によってはWindows環境でも起き得たり、*nix環境では起き得なかったりする、と整理出来ます。</p>

<h2>いずれにせよ注入順は肝になる</h2>

<p>いずれにせよ、たまたま動いたからといってクラスをその名称でソートして<code>inject_class</code>に突っ込んだのは、大いに反省するべきところです。実際、<code>MooseX::Orochi</code>のPODでも、<a href="http://search.cpan.org/~dmaki/Orochi-0.00006/lib/MooseX/Orochi.pm#ANNOTATIONS_WITH_MooseX::Orochi">ANNOTATIONS WITH MooseX::Orochi</a>節にある通り<code>inject_class</code>の順番に気を使っていることが分かります。</p>

<pre><code class="perl">$c->inject_class($_) for qw(
  MyApp::Logger
  MyApp::Schema
  MyApp::Model::Foo
  MyApp
);</code></pre>

<p>私の場合、それに気付いてはいたのですが見逃していたという次第で、ただ単に気付かないよりも問題の根が深く、忸怩たる思いです。</p>

<p>「<a href="http://mt.endeworks.jp/d-6/2008/03/neurotic-perl-hacker.html">神経質（A型）なPerlハッカーあるある</a>」で</p>

<blockquote>
  <p>use Module; 宣言を書く時、全部ABC順にしないとイライラする。</p>
</blockquote>

<p>とまで、ソースが整然であることを求道していた牧さんが、何故敢えてそこでクラスのソートをしなかったのか、PODを読んで自ずと理解することを求められているような気がしました。</p>

<h2>余談: やはりMooseの型は偉大だ</h2>

<p>余談ですが、こうした問題を出来るだけ早期に発見するためにも、<code>isa</code>や<code>does</code>は満遍なく指定しておきたいものです。</p>

<p>確かに、Shawn M Mooreさん(sartakさん)は、性能面に鑑みると型を頻繁には使わないことを<a href="http://blog.eorzea.asia/2009/09/post_65.html">YAPC::Asia特別研修</a>で勧めていらっしゃいました。しかし、私のような技術不足の人間は、本番環境ではともかく、少なくても開発環境で一通りのものが動くまでは、転ばぬ先の杖として、また文書化の一環としても、是非指定しておきたいと思うのです。無論、本番環境で当該部分をコメントアウトする折衷案はあり得ることです。</p>
]]>
    </content>
</entry>

<entry>
    <title>Moose/Mouse用フックメソッドをPod::Coverageの対象から外す方法</title>
    <link rel="alternate" type="text/html" href="http://blog.eorzea.asia/2009/12/post_83.html" />
    <id>tag:blog.eorzea.asia,2009://1.83</id>

    <published>2009-12-03T17:14:00Z</published>
    <updated>2009-12-05T20:11:02Z</updated>

    <summary>Moose/Mouseベースのクラスをテストする際には、本筋とは離れたところで一...</summary>
    <author>
        <name>Gardejo</name>
        
    </author>
    
        <category term="雑記" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="moosemouse" label="Moose/Mouse" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="Perl" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="test" label="test" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.eorzea.asia/">
        <![CDATA[<p><code>Moose</code>/<code>Mouse</code>ベースのクラスをテストする際には、本筋とは離れたところで一工夫が必要になることがあります。</p>

<p>例えば以前の記事「<a href="http://blog.eorzea.asia/2009/08/post_46.html">Arkアプリケーションの開発者テストでTest::Perl::Criticを使う</a>」では、<a href="http://search.cpan.org/perldoc?Test::Perl::Critic"><code>Test::Perl::Critic</code></a>に於いて、<code>use Moose</code>などで<code>use strict</code>構文も代替した場合でも、<a href="http://search.cpan.org/perldoc?Perl::Critic::Policy::TestingAndDebugging::RequireUseStrict"><code>Perl::Critic::Policy::TestingAndDebugging::RequireUseStrict</code></a>に引っ掛からないようにする方策を例示しました。</p>

<p>これに関連して、メソッド（やファンクション）についてPOD内での言及が網羅されているかを検査する<a href="http://search.cpan.org/perldoc?Test::Pod::Coverage"><code>Test::Pod::Coverage</code></a>で、<code>Moose</code>/<code>Mouse</code>用の一部メソッドの記述を省いてしまいたい場合があります。</p>

<p>具体的なメソッドは、例えば</p>

<ul>
<li><code>BUILDARGS()</code></li>
<li><code>BUILD()</code></li>
<li><code>DEMOLISH()</code></li>
</ul>

<p>などのフックポイントです。</p>

<p>私は、PODというものはモジュールの<em>使用者</em>向けの資料であって、内部実装について<em>開発者</em>へ向けて事細かく書くような資料ではないと思っています。場合によりけりですが、基本的にはそうした考えに基づいてPODを書いているつもりです。</p>

<p>そうすると、例えば<code>BUILDARGS()</code>に於いてどのようなパターンで引数の読み替えをするか（例えば<code>Int</code>なスカラー値1つを渡されたら<code>{ epoch =&gt; $value }</code>に読み替えるなど）を書くよりも、素直に<code>new()</code>についての記述を設けた方が良いということになります。</p>

<p>ということで、PODにそれらを書かずに、<a href="http://search.cpan.org/perldoc?Pod::Coverage"><code>Pod::Coverage</code></a>自体の機能を活用することで、「ためにする文書化」（手段の自己目的化）を避けることにしましょう。</p>

<pre><code class="perl">all_pod_coverage_ok(
    {
        also_private => [qw(
            BUILDARGS
            BUILD
            DEMOLISH
        )],
    },
);</code></pre>

<p>具体例としては、拙作<a href="http://github.com/gardejo/p5-dbicx-modeler-generator"><code>DBICx::Modeler::Generator</code></a>の開発者テストである<a href="http://github.com/gardejo/p5-dbicx-modeler-generator/blob/master/xt/pod_coverage.t"><code>xt/pod_coverage.t</code></a>などを挙げておきます。</p>

<p>なお、Kwaliteeを高くすることなどを目的とした「やせ我慢」について以下で補足しておきます。</p>
]]>
        <![CDATA[<h2>嗚呼、やせ我慢</h2>

<h3>Kwalitee対策</h3>

<p>ディストリビューションの品質を測る一指標であるKwaliteeを向上するためには、若干バッドノウハウ気味な工夫を強いられる場合があります。</p>

<p>例えば上記の<code>use strict</code>絡みでは、<code>Module::CPANTS::Analyse</code> 0.85および<code>Test::Kwalitee</code> 1.01の状態では、回避策を見出せませんでした。従って、冗長なようですが<code>use strict</code>（と<code>use warnings</code>）を明示的にコードに書くことで無理矢理都合を付けています。</p>

<h3><code>Devel::Cover</code>対策</h3>

<p><code>Devel::Cover</code> 0.64, <code>Pod::Coverage</code> 0.20, <code>Test::Pod::Coverage</code> 1.08の環境では、本稿で折角対策したはずのメソッド説明の省略が引っ掛かってしまいます。</p>

<p>ただ、これは何とか出来そうな予感がするので、時間のあるときにでも調べてみたいと思います。</p>

<h3>やせ我慢は程々に</h3>

<p>無理にバッドノウハウを重ねても、「ためにする対策」に陥ってしまいかねません。そうすると、無理のあるコードを書いてしまうことになります。</p>

<p>例えば<code>Devel::Cover</code>のPOD網羅率などは、<code>BUILD()</code>の説明を書くことによってドキュメントの焦点がぼやけてしまい、かえってユーザーにとって害をなしてしまうとも考えられませんでしょうか。</p>

<p>牧さん(lestrratさん)も『モダンPerl入門』p.234で</p>

<blockquote>
  <p>そもそも再現不可能な状況もあり得るのでカバレッジ100%という数値にこだわる必要はありません</p>
</blockquote>

<p>と言明しているように、こうした箇所で無理に数値を稼ぐ必要はないはずです。</p>

<p>負担のない範囲で、かつ、将来に亘る保守を妨げない範囲に限って細々と対策することとして、その域を超えるような対策は素直に諦めるのが良いと思います。</p>

<h2>脱・慈善事業</h2>

<p>こうした「ためにする文書化」は、無駄で無益であるばかりでなくて有害ですらあります。仕事以外ではやりたくないですね。仕事でもやりたくないというのが本音ですが、私は建前を前面に押し出している小心者です。しかしながらこのブログの所在は会社に露見しているので、週明け頃に私の席が無くなっている可能性があります。</p>

<p>私も以前はこうした<em>雇用創出</em>的な意味合いすら透けて見える慣行（関連情報：「VBAを使うのはずるい」で有名な「<a href="http://okwave.jp/qa5419623.html">マクロを組んで作業するのは実力ではないですか？</a>」）を打ち破ろうとしたことがあります。開発・運用費の締め付けが厳しいという割に、こうした慈善事業を営むようなお茶目な会社ではいけない、筋肉質な会社にならなければならない、などと。しかし金融ユーザー系システム子会社というものは石橋を叩いても渡らないものなのか、私の説得力の欠乏によるものなのか、多分後者だとは思うのですが、ともかく諦めざるを得ないということがありました。</p>

<p>「ためにする文書化」を避けられる現場では、焦点を絞った文書化を是非試みてください。</p>
]]>
    </content>
</entry>

<entry>
    <title>Perlクラスのアンロード方法(Class::Unload使用版)</title>
    <link rel="alternate" type="text/html" href="http://blog.eorzea.asia/2009/11/post_81.html" />
    <id>tag:blog.eorzea.asia,2009://1.81</id>

    <published>2009-11-28T04:08:55Z</published>
    <updated>2009-11-28T04:29:09Z</updated>

    <summary>Perlでクラス（モジュール）をアンロードする方法として、Class::Unlo...</summary>
    <author>
        <name>Gardejo</name>
        
    </author>
    
        <category term="雑記" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="cpan" label="CPAN" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="Perl" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.eorzea.asia/">
        <![CDATA[<p>Perlでクラス（モジュール）をアンロードする方法として、<a href="http://search.cpan.org/perldoc?Class::Unload"><code>Class::Unload</code></a>を使っています。</p>

<pre><code class="perl">Class::Unload->unload('Some::Unneeded::Class');</code></pre>

<p>当初、<a href="http://d.hatena.ne.jp/perlcodesample/">木本さん(perlcodesampleさん)</a>による「<a href="http://d.hatena.ne.jp/perlcodesample/20091101/1246274997">クラスをアンロードする方法</a>」の記事や、そこで言及されている<a href="http://search.cpan.org/perldoc?Class::MOP::Class"><code>Class::MOP::Class::DESTROY()</code></a>を参考にして、以下のようなアンロードメソッドも書いてみました。その後、用途に適合する<code>Class::Unload</code>モジュールがCPANで公開されていることが分かったので、自分の場合はこれを活用させていただこうと思った次第です。</p>

<p>いつの日か<code>Class::Unload</code>がどうしても使えない場面に立ち会ってしまったら、これを引っ張り出してこようと思います。「<a href="http://slashdot.jp/~taro-nishino/journal/493208">だが、私はCPANを使えない！</a>」の全ての処方箋が通用しないという、あまりぞっとしない場面ですが......。</p>

<pre><code class="perl">sub _unload_class {
    my ($self, $class) = @_;

    my @route_to_class = split '::', $class;

    # unload class in target library which is dump target of generated classes
    # cf. http://d.hatena.ne.jp/perlcodesample/20091101/1246274997
    # below codes stolen from Class::MOP::Class::DESTROY()
    {
        no strict 'refs';

        # delete inheritance information from @ISA
        @{
            $class . '::ISA'
        } = ();

        # delete class symbol from symbol table
        %{
            $class . '::'
        } = ();

        # delete class symbol from upper namespace
        delete ${
            join '::', @route_to_class[0 .. $#route_to_class - 1], q{}
        }{
            $route_to_class[-1] . '::'
        };

        # delete loading information
        delete $INC{
            (join '/', @route_to_class ) . '.pm'
        };
    }

    return;
}</code></pre>

<p>なお、上記はとあるクラスのメソッドとして実装していますが、<code>$self</code>は使っていないので、単なるサブルーチンにも出来ます。</p>

<p>ところで、普通に暮らしているだけではクラスをアンロードしたいと思う場合が殆ど全くありません。アンロードしたいという稀少な事例の一つとして、拙作の<a href="http://github.com/gardejo/p5-dbicx-modeler-generator"><code>DBICx::Modeler::Generator</code></a>でクラスをリロードするという例を掲げておきます（該当箇所は<a href="http://github.com/gardejo/p5-dbicx-modeler-generator/commit/fcf4b0de4e84b94d8f6a908bb23f9192f6a5eec7"><code>fcf4b0de...</code>コミット</a>に於ける<a href="http://github.com/gardejo/p5-dbicx-modeler-generator/blob/fcf4b0de4e84b94d8f6a908bb23f9192f6a5eec7/lib/DBICx/Modeler/Generator/Class.pm#L147"><code>DBICx::Modeler::Generator::Class</code>の147行目</a>です）。</p>

<p>このモジュールについては稿を改めてご紹介するつもりです。</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Perlでtrim(さらに完全版)</title>
    <link rel="alternate" type="text/html" href="http://blog.eorzea.asia/2009/11/post_80.html" />
    <id>tag:blog.eorzea.asia,2009://1.80</id>

    <published>2009-11-25T03:30:37Z</published>
    <updated>2009-11-28T04:06:50Z</updated>

    <summary>「perl で trim(完全版)」や「ハッシュ変数に存在しないキーを指定した場...</summary>
    <author>
        <name>Gardejo</name>
        
    </author>
    
        <category term="雑記" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="perl" label="Perl" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.eorzea.asia/">
        <![CDATA[<p>「<a href="http://yamamotoplog.blog38.fc2.com/blog-entry-2.html">perl で trim(完全版)</a>」や「<a href="http://d.hatena.ne.jp/zetta1985/20091110/1257867584">ハッシュ変数に存在しないキーを指定した場合の値は何？</a>」という記事をはてブで拝見しました。Perlでいかにtrimする（前後の空白を取り除く）か、という命題です。しかし、残念なことに、文字コードによってはこれでもまだ完全ではありません。</p>

<ul>
<li>モダンなPerlでは、プログラム内部では文字列の文字コードをUTF-8で扱い、必要に応じて入力時にデコード/出力時にエンコードする方法が一般的です。</li>
<li>こうした常套句については、コードスニペットをコピペするより、CPANモジュールを出来るだけ使うと好ましいです。理由は「<a href="http://d.hatena.ne.jp/tokuhirom/20090321/1237629165">かなり使えるPerl正規表現のまとめ</a>」の通り。今回の場合、<a href="http://search.cpan.org/perldoc?String::Util"><code>String::Util</code></a>の<code>trim()</code>が使えます。</li>
</ul>

<p>ということで、モダンに<code>trim</code>する場合には、以下のように書けます。</p>

<pre><code class="perl">use strict;
use warnings;

use utf8;

use String::Util qw(trim);
use Test::More;

# half-width space : 半角スペース
is trim(' foo'),  'foo' => 'half prefix';    # 接頭スペース
is trim('bar '),  'bar' => 'half suffix';    # 接尾スペース
is trim(' baz '), 'baz' => 'half circumfix'; # 接周スペース

# full-width space : 全角スペース
is trim('　foo'),   'foo' => 'full prefix';
is trim('bar　'),   'bar' => 'full suffix';
is trim('　baz　'), 'baz' => 'full circumfix';

# 両対応
is trim('　 foo'),    'foo' => 'both prefix';
is trim('bar 　'),    'bar' => 'both suffix';
is trim('　 baz 　'), 'baz' => 'both circumfix';

done_testing();
__END__</code></pre>

<p><code>use utf8</code>しつつUTF-8でテストスクリプトを保存することで、全角スペースも（<code>trim()</code>の中でも使われている正規表現である）<code>\s</code>に該当するようになります。</p>

<p>実際にアプリケーションで使う場合には、<a href="http://search.cpan.org/perldoc?Encode"><code>Encode</code></a>を使って外から来た文字列は<code>decode()</code>して、外に出す文字列は（必要に応じて）<code>encode()</code>することになります。出力はアプリ作者側でどうにでも出来るので、特に指定する必要がない場合にはUTF-8のままで問題ないでしょう。日本の携帯電話向けには、Shift-JISなどと適宜変えることになります。入力側は<a href="http://search.cpan.org/perldoc?Encode::Guess"><code>Encode::Guess</code></a>辺りで日和っておくといい感じです。</p>

<p>勿論、モダンな環境を使えない場合や、CPANモジュールが使えない場合（実際は「<a href="http://slashdot.jp/~taro-nishino/journal/493208">だが、私はCPANを使えない！</a>」の通り、あまりないです）も多々あるわけで、そうした場合にはトラックバック先に挙げられているような手法を使うのが良いと思います。他にも、「<a href="http://d.hatena.ne.jp/chaichanPaPa/20071213/1197549259">PerlでTrimする！</a>」という記事もあります。</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Mooseロールに実装したメソッドをmemoizeする方法</title>
    <link rel="alternate" type="text/html" href="http://blog.eorzea.asia/2009/11/post_79.html" />
    <id>tag:blog.eorzea.asia,2009://1.79</id>

    <published>2009-11-10T16:43:38Z</published>
    <updated>2009-11-12T15:43:19Z</updated>

    <summary>Mooseクラスでのクラス定数は、MooseX::ClassAttributeで...</summary>
    <author>
        <name>Gardejo</name>
        
    </author>
    
        <category term="開発日誌" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="moosemouse" label="Moose/Mouse" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="Perl" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.eorzea.asia/">
        <![CDATA[<p>Mooseクラスでのクラス定数は、<code>MooseX::ClassAttribute</code>で定義する方法もありますが、素直なのはクラスメソッドとして実装してしまうことでしょう。これならば、ロールとの相性も良いです。</p>

<p>しかし、クラス定数（のように使うクラスメソッドの戻り値）が単純な値であればともかく、何かの値を元に計算して導出するような代物だった場合、クラス定数（のように......以下略）を使う度に計算されたのではたまりません。</p>

<p>こうした場合には、<a href="http://search.cpan.org/perldoc?Memoize"><code>Memoize</code></a>によるメモ化(memoization)が定番の処方箋となります。また、（もはやメモ化の文脈での例としては定番である）フィボナッチ数の計算など、クラス定数として使うものでないメソッドについても、同様にメモ化は強力な最適化方法論です。</p>

<p>Mooseクラスでは単純に<code>Memoize</code>モジュールを使えば良いのですが、Mooseロールでは少々込み入った手順で使う必要があることが分かったので、備忘録的に書いておきます。</p>
]]>
        <![CDATA[<h2>Mooseクラスにあるメソッドのメモ化</h2>

<p>まず、Mooseクラスの例です。素直に<code>memoize</code>関数を使えます。</p>

<pre><code class="perl">{
    package Foo;

    use Moose;
    use Memoize;

    use namespace::clean -except => [qw(meta)];

    memoize qw(bar);

    sub bar {
        warn "bar\n";
        return;
    }

    __PACKAGE__->meta->make_immutable;
}
{
    package main;

    my $foo = Foo->new;
    $foo->bar;
    $foo->bar;
}</code></pre>

<p><a href="http://search.cpan.org/perldoc?Attribute::Memoize"><code>Attribute::Memoize</code></a>による<code>Memoize</code>アトリビュートを使うことも可能です。なお、大変こんがらがり易いのですが、<code>Memoize</code>アトリビュートというのはMooseのアトリビュートではなくて、Perlの（サブルーチンや変数に付与する）アトリビュートです。</p>

<pre><code class="perl"># ...

    use Moose;
    use Attribute::Memoize; # またはuse Attribute::Util qw(Memoize);

    use namespace::clean -except => [qw(meta)];

    sub bar : Memoize {
        warn "bar\n";
        return;
    }

# ...</code></pre>

<h2>Mooseロールにあるメソッドのメモ化</h2>

<h3>ロール消費クラスからメソッドが見えない</h3>

<p>ロールでは単純には行きません。以下は<code>Can't locate object method "bar" via package "Foo"</code>という例外を送出します。もう少し正確に定義すると、<code>Foo-&gt;meta-&gt;has_method('bar')</code>は偽になります。ロール内でメモ化したメソッドは、ロールを消費するクラスからは見えない状態にあるのです。</p>

<pre><code class="perl">{
    package FooBase;

    use Moose::Role;
    use Memoize;

    use namespace::clean;

    memoize qw(bar);

    sub bar {
        warn "bar\n";
        return;
    }

    1;
}
{
    package Foo;

    use Moose;

    use namespace::clean -except => [qw(meta)];

    with qw(
        FooBase
    );

    __PACKAGE__->meta->make_immutable;
}
{
    package main;

    my $foo = Foo->new;
    $foo->bar;
    $foo->bar;
}</code></pre>

<h3><code>memoize</code>にサブルーチンリファレンスを設定する</h3>

<p>上記のように嵌ったのでググってみたところ、<code>moose@perl.org</code>メーリングリストで<a href="http://thread.gmane.org/gmane.comp.lang.perl.moose/793/focus=797">Memoizing role methods</a>という、そのものずばりの質疑応答がありました。</p>

<p>有名なMSTことMatt S Troutさんによると、</p>

<ol>
<li><code>Memoize</code>のマニュアルには、<code>memoize</code>関数にはメソッド名だけでなくサブルーチンリファレンスも渡せると書いてある</li>
<li><code>memoize</code>関数の戻り値として、メモ化でラッピングしたサブルーチンリファレンスが返るとも書いてある</li>
<li><code>__PACKAGE__-&gt;meta-&gt;add_method('foo_method' =&gt; memoize(sub { ... }));</code>とすれば、メモ化ラッピングサブルーチンに名前を付けて、消費元のクラス(consumer class)にメソッドを生やせる</li>
<li>もしくは<code>memoize('foo_method')</code>の戻り値であるサブルーチンリファレンスを<a href="http://search.cpan.org/perldoc?Sub::Name"><code>Sub::Name</code></a>の<code>subname</code>に食わせることで、元のメソッド名を乗っ取って、メモ化ラッピングサブルーチン自体が呼ばれるようにすることが出来る</li>
</ol>

<p>ということです。</p>

<p><code>subname</code>の戻り値をさらにグロブリファレンスに入れる理由は、<code>Sub::Name</code>のPODに書いてあります。おまじないだと思って書くことにしましょう。</p>

<h3>現在の私の実装</h3>

<p>上記を踏まえて、私は現在のところ以下のように実装しています。別の話題（別途記事を設ける予定の「実行時まで遅延させてMooseの型を生成・適用する方法」）の実現可能性調査で使った<a href="http://gist.github.com/230058">Gist: #230058</a>から例示します。</p>

<pre><code class="perl"># ...

sub _memoize {
    no strict 'refs';
    foreach my $method (qw(
        _numbers            _names
        _names_to_numbers   _numbers_to_names
        to_number           to_name
        maximum_number      maximum_name
        minimum_number      minimum_name
    )) {
        *{$method} = subname __PACKAGE__ . '::' . $method => memoize($method);
    }
}

__PACKAGE__->_memoize;

# ...</code></pre>

<p>メモ化したい対象を<code>foreach</code>のリストに突っ込むだけで、後はいい感じに動いてくれます。</p>

<h2>Mooseロールにあるメソッドに<code>Memoize</code>アトリビュートを付与する</h2>

<p>これだけでも基本的には満足出来るのですが、メモ化するメソッドの一覧を書くことは、少々面倒です。</p>

<p>希望としては、メソッド側に<code>Memoize</code>アトリビュートを付与しつつ、各メソッドを列挙することなしに名前空間のマジックに連携させることです。</p>

<h3>メソッドに<code>Memoize</code>アトリビュートを付与すること自体は可能</h3>

<p>まず、メソッド側に<code>Memoize</code>アトリビュートを付与すること自体が出来る、という確認です。</p>

<pre><code class="perl"># ...

sub _memoize {
    no strict 'refs';
    foreach my $method_name (qw(
        _numbers            _names
        _names_to_numbers   _numbers_to_names
        to_number           to_name
        maximum_number      maximum_name
        minimum_number      minimum_name
    )) {
        *{$method} = subname __PACKAGE__ . '::' . $method => \&{$method};
    }
}

sub _numbers : Memoize {
    # ...
}

__PACKAGE__->_memoize;

# ...</code></pre>

<p>これで問題なく想定の挙動をしてくれます。しかし、これでは何の解決にもなっていませんね。かえって、各メソッドと<code>_memoize</code>メソッドの両方でメモ化対象を指定することになるだけ、多重保守の愚を犯してしまいます。<a href="http://ja.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY</a>でないということです。</p>

<h3>メソッドに<code>Memoize</code>アトリビュートが付与されているかを調査する</h3>

<p>メソッド側で<code>Memoize</code>アトリビュートを付与しさえすれば、後は何もしなくて良い......ということが理想です。そのためには、<code>_memoize</code>メソッドに於いて全メソッドを見て回って、各々に<code>Memoize</code>アトリビュートが付いているかどうかを確認し、付いていれば<code>subname</code>の流れに乗る、ということが出来れば良いわけです。</p>

<pre><code class="perl"># ...

use attributes qw();            # 流石にgetという名前はインポートしたくない
use List::MoreUtils qw(any);    # でもanyはいいんです（オレオレ二枚舌基準）

# ...

sub _memoize {
    my $clss = shift;

    foreach my $method ($class->meta->get_all_methods) {
        no strict 'refs';
        *{ $method->name } = subname $class . '::' . $method->name
            => $method->body
                if any { $_ eq 'Memoize' } attributes::get($method->body);
    }

}

# ...</code></pre>

<p>ところが、上記の実装は動きません。ロールには<code>meta</code>メソッドがない（ロールは<code>Moose::Object</code>を持っていない）ためです。</p>

<p>それでは、ロールを消費するクラスのメタオブジェクトを見ようとすると、<code>$consumer_class-&gt;meta</code>となるようにロールを消費するクラスの側で<code>__PACKAGE__-&gt;_memoize</code>する方法などが考えられます。</p>

<p>しかしその案も駄目です。クラス側で<code>_memoize</code>を呼んだ時には、既にロールはコンパイルされていますので、ロールで<code>Memoize</code>アトリビュートを付けたメソッドは<code>foreach</code>のリストには入ってきません。</p>

<p>なお、ここまでしれっと書いていますが、そもそも<code>attributes::get</code>は組み込みアトリビュート(<code>locked</code>, <code>method</code>など)以外のアトリビュートが帰ってこないようです。従って、実はメソッドが<code>Memoize</code>アトリビュート付きかどうかを判別する方法が、本日現在の私には分からないというお粗末な事情があります。</p>

<h3>サブルーチン定義時に何とかMemoizeする</h3>

<p>後からメソッドを洗うことを諦め、メソッドを定義した時点でメモ化しつつ<code>subname</code>の仕組みに乗っかる案もありました。</p>

<pre><code class="perl"># ...

*foo = subname __PACKAGE__ . '::foo' => sub : Memoize {
    # foo本来の実装
};

*bar = subname __PACKAGE__ . '::bar' => sub : Memoize {
    # bar本来の実装
};

# ...</code></pre>

<p>しかし、無名サブルーチンへのアトリビュートの適用は出来ない（と理解している）ため、これも動きません。</p>

<p>ここまで来れば別に<code>Attribute::Memoize</code>を使わずとも良いわけで、以下のような形でなら定義出来ます。周り巡って出発地点に戻ったような、少々異様なコードになりました。</p>

<pre><code class="perl"># ...

{
    no warnings 'once';
    *foo = subname __PACKAGE__ . '::foo' => memoize(sub {
        # foo本来の実装
    });

    *bar = subname __PACKAGE__ . '::bar' => memoize(sub {
        # bar本来の実装
    });
}

# ...</code></pre>

<p>だったら素直に以下のようにした方が直感的かも知れません。いずれにせよ微妙ですが......。</p>

<pre><code class="perl"># ...

{
    no warnings 'once';
    *foo = subname __PACKAGE__ . '::foo' => \&foo;
    sub foo : Memoize {
        # foo本来の実装
    }

    *bar = subname __PACKAGE__ . '::bar' => \&bar;
    sub bar : Memoize {
        # bar本来の実装
    }
}

# ...</code></pre>

<h3>まとめ ～ 敗北宣言</h3>

<p>開き直ってロールを消費するクラス側でメモ化してしまう手もありますが、それでもやはりDRYではありません。Perlのアトリビュート周りも、MooseやClass::MOPの奥深い部分も、私は殆ど理解せずにブラックボックス的に使ってしまっているので、もう少し勉強をしてみたいです。</p>

<p>MSTさんも「<code>Memoize</code>のマニュアルをちゃんと読まない人達のために、<code>Moose</code>のドキュメントに追記が必要ですか？」と記しているように、もしかしたらご立腹されているのかも知れません。ごめんなさい、ちゃんとドキュメントを読みます。</p>

<p>機会があったら試行錯誤して雪辱を果たそうと思います。</p>
]]>
    </content>
</entry>

<entry>
    <title>Mooseクラスのコンストラクター引数でハッシュとハッシュリファレンスを同一視する方法</title>
    <link rel="alternate" type="text/html" href="http://blog.eorzea.asia/2009/11/post_78.html" />
    <id>tag:blog.eorzea.asia,2009://1.78</id>

    <published>2009-11-10T16:34:21Z</published>
    <updated>2009-11-11T15:17:03Z</updated>

    <summary>Mooseクラスの生成時に、コンストラクター引数として与えられたハッシュまたはハ...</summary>
    <author>
        <name>Gardejo</name>
        
    </author>
    
        <category term="開発日誌" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="moosemouse" label="Moose/Mouse" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="Perl" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.eorzea.asia/">
        <![CDATA[<p>Mooseクラスの生成時に、コンストラクター引数として与えられたハッシュまたはハッシュリファレンスに着目して処理を行いたい場合があります。</p>

<p>例えば、初期化ハッシュキーを跨いだ検証などが挙げられます。<a href="http://blog.eorzea.asia/2009/10/post_72.html"><code>trigger</code>の使い方についての記事</a>で説明用に作った、<a href="http://gist.github.com/raw/211073/b22f2404fca8398fe328775484978843ac9d233b/era_role.pl">元号と西暦のアトリビュートを持つ昭和クラス</a>で想定してみます。</p>

<p>元号と西暦の両方を指定された場合、その両方のアトリビュートが未指定になります。<code>undef</code>という値が入っているのではなく、<code>has_imperial_era</code>などの<code>predicate</code>メソッドの戻り値が偽であるという意味です。</p>

<p>それでは困るので、コンストラクター引数に指定するのは元号と西暦のどちらか一方のみに制限する......という要件が出て来たこととします。その場合、ハッシュとハッシュリファレンスの両方でキーを見付ける処理を<code>BUILDARGS</code>に書くのではなく、親クラス(最終的な親は<code>Moose::Object</code>)の<code>BUILDARGS</code>を呼ぶようにすると、素直に書けます。</p>

<pre><code class="perl"># ...

around BUILDARGS => sub {
    my $next  = shift;
    my $class = shift;
    # ここでは@_はハッシュかも知れないしハッシュリファレンスかも知れない

    # 親クラス(Moose::Object)のハッシュリファレンス化はBUILDARGSに任せる
    my $init_args = $class->$next(@_);  # ここではハッシュリファレンス

    confess 'Initialization argument must be '
          . 'any one of imperial_era or christian_era'
            if exists $init_args->{imperial_era} 
            && exists $init_args->{christian_era};

    return $init_args;
};

# ...</code></pre>

<p>こんなものは常識なのでしょうけれども、意外とこういう初歩的なところの認識が甘くて、今までは（後述するように）ハッシュリファレンスのみを食べるような偏屈APIを撒き散らしていました。反省反省。</p>

<p>以下は補足情報です。</p>
]]>
        <![CDATA[<h2>メソッドモディファイヤーを使わない場合</h2>

<p>親クラス(<code>Moose::Object</code>)の<code>BUILDARGS</code>を修飾せず、自クラスで<code>BUILDARGS</code>クラスメソッドを定義しても、親クラスの<code>BUILDARGS</code>を呼べば同じ事です。</p>

<pre><code class="perl"># ...

sub BUILDARGS {
    my $class = shift;

    my $init_args = $class->SUPER::BUILDARGS(@_);

    confess 'Initialization argument must be '
          . 'any one of imperial_era or christian_era'
            if exists $init_args->{imperial_era} 
            && exists $init_args->{christian_era};

    return $init_args;
}

# ...</code></pre>

<h2>親の<code>BUILDARGS</code>を使わない場合</h2>

<p>Mooseのコンストラクターは、デフォルトではハッシュリファレンスかハッシュを受け付けます。自分のBUILDARGSクラスメソッド内で、コンストラクター引数がハッシュリファレンスであるかハッシュであるかを判断する処理を書くのは、とても面倒です。</p>

<pre><code class="perl"># ...

sub BUILDARGS {
    my $class = shift;

    # @_がハッシュであるかハッシュリファレンスであるかを判別する処理は、
    # Moose::Object::BUILDARGSと同じことなので面倒
    # ...
}

# ...</code></pre>

<p>自分のクラスではコンストラクター引数にハッシュリファレンスのみを受け付ける（ハッシュは受け付けない）と決めてしまえば、例えば以下のようにも書けるでしょう。</p>

<pre><code class="perl"># ...

sub BUILDARGS {
    my $class = shift;

    if (@_ == 1 && ref $_[0] eq 'HASH') {
        confess 'Initialization argument must be '
              . 'any one of imperial_era or christian_era'
                if exists $_[0]->{imperial_era} 
                && exists $_[0]->{christian_era};
        return $_[0];   # もしくは$class->SUPER::BUILDARGS($_[0]);
    }
    else {
        return $class->SUPER::BUILDARGS(@_);
    }
}

# ...</code></pre>

<p>ただ、ハッシュを敢えて拒否するような理由がない限りは、費やすべき労力はそれほど変わらないので、素直に<code>Moose::Object::BUILDARGS</code>を呼んだ方が良いと考えます。</p>

<h2>余談: ハッシュやハッシュリファレンス以外の引数を使いたい場合</h2>

<p><code>Moose::Manual::Construction</code>では、それ以外の場合（例えばスカラー値など）の対処法が書かれています。今回の要件とは違いますが、後輩への説明用に余談として述べておきます。</p>

<p><code>Person</code>クラスは、米国在住者の背番号（つまりは一意に識別出来る、<code>id</code>）である社会保障番号（<code>ssn</code> : Social Security Number）の文字列を渡すだけでオブジェクトを生成してくれると便利だ、という例です。</p>

<pre><code class="perl"># ...

has 'ssn' => (  # 社会保障番号
    is          => 'rw',
);

# ...

around BUILDARGS => sub {
    my $next  = shift;
    my $class = shift;

    if (@_ == 1 && ! ref $_[0]) {
        return $class->$next(ssn => $_[0]);
    }
    else {
        return $class->$next(@_);
    }
};

# ...</code></pre>

<p>昔のバージョンの<a href="http://search.cpan.org/perldoc?Moose::Manual::Construction"><code>Moose::Manual::Construction</code></a>では、メソッドモディファイヤーで親を修飾するのではなく、自クラスでBUILDARGSクラスメソッドを実装するように書かれていましたが、これも要は同じ事です。</p>

<pre><code class="perl"># ...

sub BUILDARGS {
    my $class = shift;

    if (@_ == 1 && ! ref $_[0]) {
        return {
            ssn => $_[0],
        };
        # 必要に応じて、以下のようにする方が良いかも知れません
        # $class->SUPER::BUILDARGS({ssn => $_[0]});
    }
    else {
        return $class->SUPER::BUILDARGS(@_);
    }
}

# ...</code></pre>

<h2>余談: <code>BUILD</code>か<code>BUILDARGS</code>か</h2>

<p><code>BUILD</code>の引数は、コンストラクター引数にハッシュを渡そうがハッシュリファレンスを渡そうが、一律にハッシュリファレンスとなっています。従って、技術的には以下のように<code>BUILD</code>でバリデーションロジックを設けることも不可能ではありません。</p>

<pre><code class="perl"># ...

sub BUILD {
    my $self = shift;

    confess 'Initialization argument must be '
          . 'any one of imperial_era or christian_era'
            if exists $_[0]->{imperial_era} 
            && exists $_[0]->{christian_era};

    return;
}

# ...</code></pre>

<p>しかし、既にオブジェクトを作ってしまった後に、そのオブジェクトの初期化変数を検証するのは、順序が逆転しています。おかしな値を拒絶するのは出来るだけ早い段階の方が良いので、今回の場合は<code>BUILDARGS</code>でフックしています。</p>

<p>勿論、生成されたオブジェクトのアトリビュートを跨いだ検証などは、素直に<code>BUILD</code>を使えば良いです。</p>

<p>この辺りは、初期化時に行いたい処理によって、<code>BUILDARGS</code>にフックするのか<code>BUILD</code>にフックするのかを決めれば良いでしょう。迷ったら、早めに死ぬように<code>BUILDARGS</code>を選ぶのが無難です（そして、きちんと検証出来ていることをテストで確かめましょう）。</p>
]]>
    </content>
</entry>

</feed>

