Perl Hackers Hub

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

前回の(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リクエストが来たら後続のサブルーチンリファレンスを実行する

と定義しています。

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)こちら。>

おすすめ記事

記事・ニュース一覧