Perl Hackers Hub

第35回 Perlによる内部DSLの作り方(2)

この記事を読むのに必要な時間:およそ 1.5 分
前回の(1)はこちらから。

Mojoliciousから見る内部DSLの利点と欠点

まず,Mojoliciousのルーティング定義を通してPerlの内部DSLの一例を紹介し,DSLを使わなかった場合との比較を行います。

Mojoliciousは人気のあるPerlのWebアプリケーションフレームワークです注1)。ルーティング定義の方法として,

  • routesオブジェクトにルーティングを定義していくオブジェクト指向的なやり方
  • RubyのSinatraに端を発した簡潔な内部DSLで定義するやり方

の2種類をサポートしています。それぞれの方法で定義したものが以下です。

オブジェクト指向版

{
  package MyApp;
  use Mojo::Base 'Mojolicious';
  sub startup {
    my $self = shift;
    my $routes = $self->routes;
    $routes->get('/')->to('example#index');
    $routes->post('/count')->to('example#count');
  }
}
{
  package MyApp::Controller::Example;
  use Mojo::Base 'Mojolicious::Controller';
  sub index {
    my $self = shift;
    $self->render(text => "Hello, World!");
  }
  sub count {
    my $self = shift;
    my $count = $self->session('count') || 0;
    $self->session(count => ++$count);
    $self->render(text => "Posted $count");
  }
}

require Mojolicious::Commands;
Mojolicious::Commands->start_app('MyApp');

DSL版

use Mojolicious::Lite;

get '/' => sub {
  my $self = shift;
  $self->render(text => "Hello, World!");
};
post '/count' => sub {
  my $self = shift;
  my $count = $self->session('count');
  $self->session(count => ++$count);
  $self->render(text => "Posted $count");
};

app->start;

まずオブジェクト指向版を見てみます。ルーティングを定義しているのはルートオブジェクト$routesgetpostメソッドを実行しているところです。これで,

  • /にGETリクエストが来たらMyApp::Controller::Exampleのindexメソッドを実行する
  • /countにPOSTリクエストが来たらMyApp::Controller::Exampleのcountメソッドを実行する

というルーティングが定義されます。

次にDSL版のほうを見ています。おそらくこちらのほうは,Mojoliciousを触ったことがない人にもどのようにルーティングされるかがわかるのではないでしょうか。すなわちgetpostサブルーチンによって,

  • /にGETリクエストが来たら後続のサブルーチンリファレンスを実行する
  • /countにPOSTリクエストが来たら後続のサブルーチンリファレンスを実行する

と定義しています。

注1)
Mojoliciousについて詳しくは,本連載第33回MojoliciousでかんたんWebアプリケーション開発をご覧ください。

DSL版の利点

さて,この2つの比較でDSLの利点が見えます。DSLを使ったほうが明らかに簡潔です。誰にとってもわかりやすいですし,開発者はルーティングに集中してプログラムが書けます。そして,これは筆者の主観も入りますが,DSL版のほうがクールに感じます。このクールさだけでもDSL版を書く動機になると思います。

DSL版の欠点

一方でDSL版の欠点はあるでしょうか。

第一に,やはりその学習コストが挙げられます。筆者が初めてDSL版でルーティングを書いたとき,get"/" => sub { my $self = shift; ... };$selfに何が渡されているのかわかりませんでした。またルーティングとは少し離れますが,Mojolicious::Liteにはほかにもhelper,pluginなどのDSLのキーワードが用意されています。これらがあること自体,知るのに時間がかかりました。

すなわち,DSLを書くにはまずそのDSLの世界観を知る必要があるということです。その世界観を共有できて初めて,DSLを有効に使えます。

第二に,重複するコードを集約できないことが挙げられます。ある程度ルーティング定義が多くなったときを考えてみてください。この場合,DSL版では1つのスクリプトにかなりの量のコードが書かれます。その中には重複しているコードも出てくるでしょう。それに対してオブジェクト指向版では,処理の実体はコントローラのメソッドにあり,コントローラクラスを複数用意すれば見通し良くコードを書いていくことができます。そして重複コードの集約はオブジェクト指向の視点から対処できるでしょう。

以上,Mojoliciousのルーティング定義をオブジェクト指向とDSLの両方で行い,その比較を行いました。DSLには利点も欠点もありますので,適材適所で使うことが重要です。

<続きの(3)はこちら。>

著者プロフィール

鍛治匠一(かじしょういち)

1984年神奈川県生まれ。ヤフー株式会社所属。

広告配信システムの開発,運用をしている。

いつも,すきあらばPerlで開発しようと画策している。

GitHub:https://github.com/skaji

コメント

コメントの記入