あと味

たくさん情報を食べて、たくさん発信すると、あとになって味わい深い。

MTDDC 2013の感想文

感想文書くの遅くなりましたが、先日、MTDDC 2013に参加しました。

LTについて

Data APIをさわるキッカケを作りたいなと思って、さわる前にLT応募したんですけど、実際にさわってみるのはギリギリになってしまって、焦ってたんですが、5分だったのでなんとかなりました。

とりあえず、できることを確認して、サンプルアプリ作ってみて、ファーストインプレッションをまとめた感じです。

下記にLTのスライドを置いておきました。

LT用に作ったサンプルアプリケーション

Movable Type Data APIは、結構ポテンシャルが高いなと思っていて、スライドにも書きましたが、MTの管理画面を作るだけじゃなくて、JSONを使ったフロントエンドアプリが普通に作りやすくなりますねってことを紹介するために、ToDoアプリケーションを作りました。

とは言え、作ったというと大げさで、下記の記事にあるチュートリアルそのままで、CoffeeScript + Data APIで少し書き直しただけです。

作ったサンプルは下記に置いておきました。

Data APIはURLの設計キレイだし、JSON/REST APIなので、Backbone.jsとの親和性がとても高いと思いました。バックエンドはMTをセットアップしただけで利用できるので、Backbone.jsでフロントエンドのアプリを書くだけで済みます。アプリのプロトタイプ作るのに活用するのもいいなと思いました。

後、フロントエンドの人達も活用しやすいと思います。フロントエンド技術だけでも、Data APIを使って、Webアプリを作れるとおもいますし、DBのデータの管理アプリケーションにMTが使えます。

MT6について

やはりData APIに注目が集まっているようです。

自分もData APIは、MTの静的ファイル出力やMTML、Perlなど、MTのアイデンティティになる要素を一切排除できる仕組みなので、かなり大胆な機能追加だなと思いました。

今後Data APIがどのような使い方をされていくのか楽しみではあります。

あと、長谷川恭久さんを中心にMTがどのようにリデザインされていくのかも注目です。

新しいMTはSimple, Smart, Speedyがキーワードとのことですが、今のMTは残念ながらどのキーワードもしっくりとマッチしていないように思うので、これからそのキーワード通りに変化していくことを期待しています。

MTがStyleDoccoに対応したっぽい

developブランチのcommitログ見てたら下記のコミットを見かけた。

StyleDocco 形式のStyleGuideを整備したようで、StyleDoccoを使ってスタイルガイドが出力できるようになってた。これによって既存のスタイル探すのにソース見て調べなくても良くなりそう。developブランチの話なので確定ではありませんが。

出力結果

f:id:jdg:20130729235752p:plain

あと、話は変わりますが、MTDDCにてLTをすることになったので、今週は頑張ってスライド作ります。

Perlのデータ構造を意識しつつ、常にmt:loopタグを使う話

案件で試したわけではなく、かと言って試せる機会もないので、あくまで一つの提案です。

mt:loopタグの良い文書がGithubのmovabletype/Documentation Wikiにあります。

特筆すべき箇所が、以下のように書かれた説明です。

Movable Typeの再構築の処理を行う場合、データベースへのアクセスが多くなります。

例えばブログ記事のタイトル一覧をページ内で複数個所で利用するケースの場合、 タグを何箇所にも書くと、その個数分データベースへアクセスしに行く事になり再構築時にオーバーヘッドが多くなります。

そこで、一旦データを配列やハッシュに格納し、ループを各所でまわす事でデータベースへのアクセスを減らす事が可能となります。

データを配列やハッシュに格納すれば、あらゆるコンテナタグと呼ばれる類のタグは、mt:loopの共通のインターフェイスによって利用でき、非常にわかりやすくなると感じました。

mt:loopのインターフェイスを利用することで、もれなく、__first__, __last__, __odd__, __even__, __index__, __counter__などの特殊変数が利用できるのも大きいです。

極端に言えば、mt:entriesやmt:pages等は、「mt:loopに渡すためのデータの構築のみに使うようにする」みたいな話です。

mt:entriesを例に考えます。

mt:entriesは、通常、以下のように使うでしょう。

<mt:entries>
title: <mt:entrytitle>
text: <mt:entrytext>
more: <mt:entrymore>
</mt:entries>

これをPerlのデータ構造で表すと以下のような形で考えるのが自然ですね。

my $entries = [
  {
    title => 'title1',
    text => 'text1',
    more => 'more1',
  },
  {
    title => 'title2',
    text => 'text2',
    more => 'more2',
  },
  {
    title => 'title3',
    text => 'text3',
    more => 'more3',
  },
];

これをそのままmt:loopで使えば、かなり楽にmt:loopを活用できそうです。mt:varでアクセスできる値は、実際にはPerlのデータ構造ですからね。

結果、以下のようにテンプレートを書くことで、先ほどのデータ構造を自然に作れることを確認しました。無名ハッシュリファレンスをどうやって表現するかが悩ましいところでしたが、割とスムーズにできました。

<mt:entries>
  <mt:sethashvar name="entry">
    <mt:entrytitle setvar="title">
    <mt:entrybody setvar="text">
    <mt:entrymore setvar="more">
  </mt:sethashvar>
  <mt:var name="push(entries)" value="$entry">
</mt:entries>

以下のようにmt:loopで利用します。

<mt:loop var="entries">
  <mt:if name="__first__">
    <div class="entries">
  </mt:if>
      <article class="entry<mt:if name='__first__'> first</mt:if><mt:if name='__even__'> even</mt:if><mt:if name='__last__'> last</mt:if>">
        <h1><mt:var name="title"></h1>
        <div class="entry-text">
          <mt:var name="text">
        </div>
  <mt:if name="more">
        <div class="entry-more">
          <mt:var name="more">
        </div>
  </mt:if>
      </article>
  <mt:if name="__last__">
    </div>
  </mt:if>
</mt:loop>

これであらゆるコンテナタグを、常にmt:loopで回せそうな気がして参りました。試してませんが、元のデータ構造がもう少し複雑でも、mt:loopのネストでうまくデータにアクセスできるように思います。

個人的には、上記のmt:ifの分岐すらお腹いっぱい感があるので、もう少しテンプレートを簡潔に書けるインターフェイスを作りたいなーと思ってはいます。

まとめ

共通のインターフェイスを使えて、DBアクセスも減らせるので、メリットが大きい気がしています。やたらめったらグローバルに変数を定義しているわけでもないので、お行儀も良いです。また、基本的に<mt:if name="foo">...</mt:if><mt:var name="foo">しか使わないので、シンプルにもなります。落とし穴あるかもしれませんが...。

おまけ

データ構造を逐一調べるために、下記のような単純なMTタグを定義して、あちこちにmt:dumpを散りばめながら動作を確認しました。

tags:
  function:
    Dump: >
      sub {
        use Data::Dumper;
        Dumper shift->stash('vars');
      }

config.yamlのみでプラグインのプロトタイプをサクッと作れるのは良いですね。

追記

コメント欄で同僚さんにコメントいただいたのですが、コレが自然に動くようになったのは、MT 5.2から だそうです。どおりで、今までサンプル見なかったわけだ。あと、「落とし穴あるかもしれませんが」の回答として、ダイナミックパブリッシングで挙動が異なるケースがあるそうです。ありそうですね...。

春のJAWS-UG 三都物語 2013でMTに関するLTしました

AWSを使ったこと、ほぼなかったんですけど、これをキッカケにして、今後は活用するようになりそうです。

発表内容をシェアするとともに、ちょっと考えることを書きます。5分という短い時間でしたが、伝えたいことは伝えられたんじゃないかと思います。

思ったこと

Wordpress界隈に比べて、MT界隈のAWSのノウハウは、ウェブを見る限りではまだ少ないように思います。

特に、Movable Typeは静的ファイル出力が前提のソフトウェアなので、S3やCloudFrontがもっと活用されるようになるといいなと思いますし、自分は今後活用しようと思います。

また、スライドの中では、管理画面なくてもいいじゃんみたいな話をしていますが、これは極端な話だったかもしれません。しかし、MTはPerlで書かれたソフトウェアなので、コマンドラインツールとの親和性は実際高いと思っています。CPANもあるし。

コードベースでMTを操作すること

ネタに走ってしまって、多分あまり伝わってないので、コードベースでMTを操作するということについては、本エントリでもう少し掘り下げることにします。

MT::Toolクラスのサブクラスを作れば簡単にコマンドラインツールを作ることができます。*1

管理画面経由にせよ、コマンドラインツール経由にせよ、使うのはMTのアーキテクチャです。MTのアーキテクチャは、管理画面に特化しているわけではなく、コードから利用することも可能です。コードから利用するのはWordpressより扱いやすいように思います。Perl製のソフトウェアということもありますが、こういう点がMovable Typeの方が弄っていて楽しいと思う理由なんだと思います。

MTは、ライブラリを直接useして利用できる作りにもなっています。*2

プラグインかtoolsスクリプトかの違いは、MTのオペレーションツールがブラウザかターミナルかの違いだけです。
自分は、コマンドラインツールが好きなので、今後、MTのコマンドラインツールをいろいろ作ることでしょう。コマンドラインツールをしっかり作ってしまえば、どうしても管理画面上から利用したい時には、ブラウザ用のインターフェイスを追加するだけで済むはずです。たぶん。

ついでなので、作りかけで途中になっていた、MTObjectImporterというプラグインをgithubに上げました。YAMLで記事をインポートしたいなと思って作り始めたら、JSONも構造にてるし、EntryとPageも構造似てるしってことになって、ひとつメタなプラグインにしました。

大したことは書いてありませんが、ライブラリをuseして利用できることを意識して作ってあります。こんな感じで、今後もまずはコマンドラインツール、必要に応じてブラウザ用のインターフェイスを用意する、みたいな感じで作ろうと思ってます。テストもしやすいですし。

まとめ

今後、MTらしさを生かしつつAWSを活用したいですね。

*1:perldoc MT::Toolしましょう

*2:githubのmovabletypeのtディレクトリを見よ

俺、今大阪におんねん

ごめんなさい、本当は関西弁まったく使えません。

昨年末から、アルファサード株式会社で働いています。今は主に製品サポートと製品開発を担当しています。

大阪勤務なので、大阪に引越しまして、今や大阪府民です。

これまでも、福井から関西の勉強会に参加することがありましたが、より参加しやすくなりますし、関西圏の方、仲良くしてください。

先日、Movable TypeのextlibディレクトリのCPANモジュールカタログ - あと味という記事の最後の方に、「来年はMovable Typeに本気で取り組みます。」と書いておりましたが、アルファサードPowerCMSというMovable Typeを拡張したCMSを開発している会社なので、嘘偽りなく、今年からはMTに本気で取り組むことになります。

Perlで仕事をしたいと思いつつ、Web制作で関わり弄ってて楽しかったMTと戯れながら、いちひよっこPerlプログラマとして頑張っていきたいと思う所存です。

今後はMTの記事やPerlの記事が増えることと思いますが、個人のライフワークとして、特に関数型言語には興味を持ち続けると思うので、そういう記事も継続的に書いて行きたいと思います。

ちょっとフロントエンドから離れた感はあるのはありますが、未だ興味の対象としては大きな要素なので、今後も勉強していこうと思います。

ということで近況報告でした。

サクッとPSGIなMTOSの開発環境を用意する方法

MTは5.2.2からPSGI対応したということで、今までPSGIアプリケーションをMojoliciousやMENTAで作ることもあった自分としては、かなり嬉しい出来事でした。

Mojoliciousなどは、開発用のPSGIサーバーも同梱されていて、ポータブルだし、サクッと開発環境を用意して、プログラム書き始めることができるのがとても良いですね。

どのCMSApacheの設定から始めて、DB作って、それらの開発環境を外に持っていく時も同じようなことをして云々かんぬんというのに辟易していました。Cartonなどを利用すれば、Perlの実行環境を除いて、アプリケーションディレクトリ配下にアプリケーションが動作するすべての条件を含めることができるのが快適で快適で。

これとなるべく近いことをMTOSでやってみようという試みです。基本的にPSGIで動かす話なので、CGIで動かす場合は、今までどおりメンドイですね。

MTOSを取得する

MTOSはGithubで公開されているので、とても助かります。

$ cd /path/to/yoursite
$ git clone https://github.com/movabletype/movabletype.git mt

これで取得完了です。特定のbranchや特定のtagのファイルが必要な場合は、以下のコマンドも適宜実行しましょう。

$ cd mt
$ git tag -l
$ git checkout -b mt5.2.3 origin/mt5.2.3

とか、

$ git branch -r
$ git checkout -b develop origin/develop

とか。

以降、すべての操作をmtディレクトリの中で行うので、cdコマンドは省略します。

最後にmakeします。

$ make me

シェバンを書き換える

すべての.cgiのシェバンが、/usr/bin/perlになってますが、自分の開発環境で、そのPerl使うことは皆無ですし、CPANモジュールもまったく追加してないので、シェバンはワンライナーで書き換えます。

$ find . -name '*.cgi' -or -name '*.t' -o -name '*.pl' -o -name '*.psgi' | xargs grep -lE '^#!/usr/bin/perl' | xargs perl -p -i -e 's|^#!/usr/bin/perl(\s*(?:-w)?)$|#!/usr/bin/env perl$1|'

DBを作成する

これもSQLiteでできればなー・・・。という感じ。他はすべてアプリケーションのディレクトリに閉じ込めることができますが、ここばかりはどうにもなりませんね。

MySQLの設定 : Movable Type 5 ドキュメント

この辺は、今後、コマンドラインスクリプトで自動化しようと思います。

ディレクトリの配置

こんな感じにするのが良いと思います。

www (プロジェクトのルート)
├─ mt (MTのCGIPath)
├─ mt-static (MTのStaticPath)
└─ public (公開領域)

以下、このディレクトリの配置を前提に、設定ファイルにパスを書いています。

mt-config.cgiを用意する

最小限のmt-config.cgiは以下のような感じになりました。

CGIPath /mt/
StaticWebPath /mt-static
StaticFilePath /path/to/mt-static
ObjectDriver DBI::mysql
Database database
DBUser dbuser
DBPassword dbpassword
DBHost localhost
DefaultLanguage ja

/mt/foo.cgiが、それぞれ別個のPSGIアプリケーションになります。MTの管理画面は、/mt/mt.cgiです。

app.psgiを用意する

mt.psgiというものがあるのですが、書き換えたいのと、plackupでファイル名指定するのが面倒なので、mtディレクトリ配下にapp.psgiを用意します。ちなみに、コレが今回の肝です。

use strict;
use warnings;
 
use lib qw(lib);
 
use MT::PSGI;
use Plack::Builder;
 
builder {
    enable 'DirIndex',
        dir_index => 'index.html';
    enable 'Static',
        path => qr{^/(?:(?!mt/|mt-static/))},
        root => '/path/to/public';
    MT::PSGI->new()->to_app;
};

Plackミドルウェアを2つ使っています。mt.psgiは個別のPSGIアプリケーションを包括した大きなPSGIアプリケーションになっていて、中でMT標準のアプリケーションやら、プラグインで利用するアプリケーションやらをPSGIアプリケーションにして、マウントしてみたいな処理をしています。

外から、mt.psgiを拡張しようとすると、今のところ、Plackミドルウェアしかないのかなーと思っています。

とは言え、既存のPlackミドルウェアの資産が活用できるのは魅力です。
もしかしたら、今後、MTのプラグインだけではなく、mt.psgi用のPlackミドルウェアもいろいろ出てくるのかもしれませんね。

静的ファイルを配信するためだけに、Apacheを設定するのは流石にだるいので、PSGIサーバーさん(plackup)に、そこんとこも頼むことにします。

静的コンテンツを配信するミドルウェアであるPlack::Middleware::Staticと、特定のファイル名をApacheのDirectoryIndexのように設定できるPlack::Middleware::DirIndexを利用しています。

Plack::Middleware::DirIndexの方は、Plack::Middleware::Staticの正規表現をもうちょっと書いたら不要かもしれません。もしくは、インラインでミドルウェアを書くとか。

ちなみに、Plack::Middlewara::DirIndexの存在は、Plackのgithub上にあったIssueで知りました。

MTOSの起動

plackup

以上!

デフォルトでは、ポートが5000番で起動するので、http://localhost:5000/mt/mt.cgiがMTの管理画面、http://localhost:5000/がサイトルートになります。

まとめ

以上で、割とポータブルで、サクッと用意できるMTOSの開発環境が用意できたと思います。用意が楽な上に、今までより速いです。

一応、公式では、plackupの制約上、PSGIサーバーはStarmanの利用が想定されていて、plackupはあくまで開発用と割り切って使いましょう。プラグイン入れた時とかアップグレード後とか何かと再起動必要だし。

初期状態では、CPANモジュールがいろいろ足らないと思いますが、この辺の依存関係を書いたMakefile.PLを用意して、Cartonで管理するのが良いと思います。

公開サーバーにMTを置かないという選択肢があるなら、これだけでも、高機能な静的HTML生成器になるし、汎用的なテキストファイル生成機になりますね。

プログラミングHaskellのfoldr, foldlの説明が秀逸だった件

今年はHaskellを勉強しています。

土日などを利用して、すごいH本を3〜4週間かけて読み終えました。時間かかった分、記憶の密度が低くて、まだ理解度は低いです。

新しい概念を学ぶ時は、同じテーマの本を何冊か読んで、本当に読みたかった本を再度読み直すというのが自分の学習の方法として定着しているので、今は、プログラミングHaskellを読み進めています。

すでに「ふつうのHaskellプログラミング」は読み終えていましたが、改めて読むと、本当に普通のプログラミング本に感じたので、すごいH本がかなり刺激的で、よくできた本なんだと思います。読み直す時が楽しみであります。

本題

さて、「プログラミングHaskell」の話に戻りますが、foldrとfoldlの説明の箇所が秀逸だと思ったので内容を紹介してみます。*1

fold関数は、他の言語でreduceとかinjectとか呼ばれている関数ですね。個人的には、かなり表現力が強い関数なので、一番好きな関数かもしれません。*2

プログラミングHaskellでは、冒頭にこんな紹介があります。

引数にリストを取る関数は、リストに対する再帰を使って、以下のような簡単な様式で定義できることが多い。

f [] = v
f (x:xs) = x f xs

標準ライブラリで提供される高階関数foldr(fold rightの略称)は、この再帰的な様式を抽出する。演算子と値vは引数となる。

なんのこっちゃという感じですが、確かに、fold関数には引数にリストを除いて、に相当する関数と初期値に相当する値vを渡します。

例にある、sum関数とproduct関数のfoldを使わない定義はこんな感じです。

sum []         = 0
sum (x:xs)     = x + sum xs

product []     = 1
product (x:xs) = x * product xs

sum関数とproduct関数のfoldを使った定義はこんな感じです。

sum     = foldr (+) 0
product = foldr (*) 1

確かに、に相当する部分と、値vに相当する部分がそれぞれ引数になっています。しかも、いつの間にか再帰がなくなりましたね。再帰的な様式を抽出するというのは本当みたいです。

Haskellはすべての関数がカリー化されるので、sumもproductもリストに適用すれば、結果が返ってきます。

わかりやすかった説明

で、前提は以上で、次に以下のような説明が続きます。

すなわち関数foldr f vは、空リストを値vに変換する。空でないリストに対しては、「先頭の要素」と「残りのリストに対し自分自身を呼び出した結果」に関数fを適用する。ただ実際には、foldr f vは再帰的に理解するのではなく、単にcons演算子を関数fに置き換え、末尾の空リストを値vに置き換えると理解する方がいいだろう。

という説明の後に具体例がこのようにきます。

1:(2:(3:[]))

これは、以下のように変換される。

1+(2+(3+0))

こういう説明、今まで見たことなくて、すごくわかりやすい説明だと思いました。
すべての関数を中置記法で使えるHaskellだからこそわかりやすいのかもしれませんが、他の言語でその機能の採用率が低めってだけと考えれば良いだけですし。

まとめるとfoldrのフォーマットは以下のような感じですね。

foldr f v [...]

で、次からは例です。

例: リストの値を合計する
foldr (+) 0 [1,2,3]

関数f = (+)
値v = 0

before:

1:(2:(3:[]))

cons演算子を関数fに置き換え、末尾の空リストを値vに置き換えてみる。

after:

1+(2+(3+0))
例: リストで最も大きい数値を求める
foldr max 0 [1,2,3]

関数f = max
値v = 0

before:

1:(2:(3:[]))

cons演算子を関数fに置き換え、末尾の空リストを値vに置き換えてみる。

after:

1`max`(2`max`(3`max`0))
例: リストの最初の要素を求める
getLeft :: a -> b -> a
getLeft a _ = a
foldr getLeft 0 [1,2,3]

関数f = getLeft
値v = 0

この例の場合、値vは即捨てるので、なんでもいいですが。

before:

1:(2:(3:[]))

cons演算子を関数fに置き換え、末尾の空リストを値vに置き換えてみる。

after:

1`getLeft`(2`getLeft`(3`getLeft`0))
例: リストの要素数を求める
succRight :: Enum a => a -> a -> a
succRight _ n = succ n
foldr succRight 0 [1,2,3]

関数f = succRight
値v = 0

before:

1:(2:(3:[]))

cons演算子を関数fに置き換え、末尾の空リストを値vに置き換えてみる。

after:

1`succRight`(2`succRight`(3`succRight`0))
例: リストを逆順にする
snoc :: a -> [a] -> [a]
snoc x xs = xs ++ [x]
foldr snoc [] [1,2,3]

関数f = snoc
値v = []

before:

1:(2:(3:[]))

cons演算子を関数fに置き換え、末尾の空リストを値vに置き換えてみる。

after:

1`snoc`(2`snoc`(3`snoc`[]))
例: リストの偶数の要素の合計値を求める
addEven :: Int -> Int -> Int
addEven n m  = if even n then m + n else m
foldr addEven 0 [1,2,3,4]

関数f = addEven
値v = 0

before:

1:(2:(3:(4:[])))

cons演算子を関数fに置き換え、末尾の空リストを値vに置き換えてみる。

after:

1`addEven`(2`addEven`(3`addEven`(4`addEven`0)))

foldr, foldlの要約

foldrの要約として以下の定義が掲載されていました。

foldr () v [x0, x1, ..., xn] = x0 (x1 (...(xn v)...))

で、foldrはが左結合であることが前提の関数で、foldlはが右結合であることが前提の関数だと。
foldlの定義も以下のように書かれています。

foldl () v [x0, x1, ..., xn] = (...((v x0) x1)...) xn

foldrかfoldlかでは、個人的には圧倒的にfoldlの方がわかりやすいので、foldl相当(reduceかreduceRightだったらreduce)ばかり使っていましたが、どちらでも実装できる場合は、より効率の良い方を選びましょうという話でした。
例えば、すごいH本には、(++)は(:)に比べると遅いので、リストを使って、リストを構築するようなケースでは、foldrを使う方が良いと書いてありました。後、無限リスト扱う時とか。consは右結合ですもんね。

まとめ

今までに比べてfold(r|l)関数の処理が頭の中で可視化されるようになった気がします。
あと、foldrに渡す関数は、定義がどれだけ複雑だったとしても、とどのつまり左被演算子が要素で右被演算子が累積値になる二項演算子的な関数で、foldlに渡す関数も、定義がどれだけ複雑だったとしても、とどのつまり、左被演算子が累積値で右被演算子が要素になる二項演算子的な関数なんだねって理解もできました。
今後は、リストを使った再帰を書くような時は、foldr, foldlに書き換えることもまず検討しようと思います。

*1:すごいH本の説明もわかりやすかったですよ

*2:PerlのList::Utilにあるreduceは好きになれませんが...