あと味

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

CSS Niteベスト・セッション2012でベスト・LTをいただきました && 本年もよろしくお願いします

CSS Niteベスト・セッション2012でベスト・LTをいただきました。

CSS Niteベスト・セッション2012

インストラクタをしていた時期が長かったので、人前で話すことは得意な方ですが*1、インストラクションとプレゼンテーションは共通部分も多いとは言え、異なるものなので、プレゼンテーションも上手にできたという事実は、個人的にはとても嬉しい事実でした。

何かを話す時、いつも良いパフォーマンスが出るわけではなく、ベスト・LTをいただいたトークでは、会場に知り合いが多く、かつ、2回目だったということもあり、緊張しすぎず、緩すぎず、反省も活きて、良いパフォーマンスが出たのかもしれません。

今後も「あいつは、口だけは達者やなー」と言われないように、実際のスキルや技術力を向上させていきたいと思います。

昨年は最後になって、いろいろ良いニュースが舞い込む年でした。本年もあと味をよろしくお願いいたします。

*1:福井弁ですけど...

Movable TypeのextlibディレクトリのCPANモジュールカタログ

Movable Type Advent Calender 2012の5日目です。

Movable Typeのプラグイン開発は、ダイナミック・パブリッシング対応のためにPHPを書くのを除いて、主にPerlのプログラムを書くことになります。

Perlのプログラムは、標準のモジュールだけで開発できることは少なく、様々なCPANモジュールを組み合わせて書いていくことが多いです。

プラグインの開発をする際、プラグインにCPANモジュールを同梱することもできますが、すでに同機能を実現できるモジュールが標準で用意されているのであれば、そちらをまずは使った方が、依存モジュール等でややこしくなくて済むので、まず、MT_HOME/extlibディレクトリの中にあるモジュールをいろいろと調べることがあります。

この機会に自分の備忘録も兼ねて、デフォルトのextlibディレクトリにある、CPANモジュールのカタログを作ってみました。

調査したバージョン

Movable Type 5.2(MTOS)

モジュールカタログ(アルファベット順)

以下、モジュールをアルファベット順に並べています。MT本体で利用されていない単なる依存モジュールかつ、個人的に使わなさそうなものは独断と偏見で省く可能性があります。ご了承下さい。

A

Algorithm::Diff
2つのファイル、リストの差違を求める関数を含んだモジュール。

MT本体では利用されていませんが、HTML::Diffの依存モジュールです。他に使えることもありそう。

Apache::*
mod_perl絡み。

MT5以降では、mod_perlをサポートしていないようなので、今後使わないのかもしれない。プラグイン開発には必要ないのかな。

Archive::Extract
圧縮ファイルの展開をする時に使うモジュール。

MT本体では使われていないようですが、Archive::ZipやArchive::ExtractのPODを見ると、解凍だけなら、こちらを使った方がメモリ消費量を節約できるっぽいです。(unzip等のコマンドが利用できる前提)

Attribute::Params::Validate
Params::Validateを属性を使って利用するモジュール。

特に使われているところは無さそうだけど。

AutoLoader.pm
AUTOLOADで呼ばれるメソッドをファイルに書きだしておけるモジュール。

Image::Sizeで使われてる。

C

CGI::*
言わずと知れたモジュールですね。

MT::Appで使われています。直接使うことは無さそう。

Cache::*
キャッシュのインターフェイス。

Data::ObjectDriverのサンプル・コードに出てくる程度。標準のextlibには入っていない、推奨モジュールのCache::Fileとか、Cache::Memcachedの方が有用そう。

Class::Accessor::*
アクセサの定義を簡単にするためのモジュール。

MT内でも使われているし、クラス作る時に有用。

Class::Data::Inheritable
アクセサの定義を簡単にするためのモジュール。Class::Accessorとの違いは、インスタンス変数へのアクセサか、クラス変数へのアクセサかです。

Data::ObjectDriver::Driver::BaseCacheでは、両方をClass::Accessor::FastとClass::Data::Inheritableとを使い分けています。

Class::Inspector
クラスについていろいろ検査するモジュール。

SOAP::Liteの依存モジュールのようです。とあるクラスをロード済みかどうか調べるのに使ってました。

Class::ErrorHandler
クラスのエラーメソッドを簡単に定義するためのモジュール。

URL::Fetchの依存モジュールのようです。

Class::Trigger
クラスにトリガーを設定するためのモジュール。

MTのフック・コールバックはこの仕組で実装してるっぽい。

Crypt::DH
DH法のためのモジュール。

Net::OpenID::Association等の依存モジュール。鍵作るのに必要みたい。

D

Data::ObjectDriver::*

ORマッパー。

MTで独自オブジェクト作る時は間接的にお世話になる。

F

File::Copy::Recursive

再帰的にファイルのコピーや移動をするためのモジュール。

MTでは、MT::CMS::Themeでエクスポートする時に使われている。

File::Listing

ファイルやディレクトリの一覧を出したい時などに使うモジュール。

LWP::Protocol::FTPで、ファイルの一覧をHTMLで返す時にファイル一覧ページを作るために使われている。

File::Tmp

TempファイルやTempディレクトリを作りたい時に使うモジュール。

MTでは、ファイルのアップロードで重複したファイル名の場合、上書きする時などに使われる。

H

HTML::Diff

二つのHTMLのdiffを取るモジュール。

MTでは、MT::Revisableで使われてますね。リビジョンの機能を使う時にお世話になってるってことです。

HTML::Form
HTMLのform要素をオブジェクトとしてパースするモジュール。

どこでも使われていなっぽいけど、LWP::UserAgentなんかと組み合わせて使うみたい。

HTML::Template
HTMLのテンプレートエンジン。

かつてのバージョンでは、MTの管理画面はHTML::Templateで書かれていたようで、その名残りだと思われます。MT::Builderには、HTML::Template形式のテンプレートをMTタグに変換するコードが入ってました。

H

HTTP::*
HTTPプロトコル周りのインターフェイス。

依存モジュールが大半で、MTでは、HTTP::RequestとHTTP::Response、HTTP::Dateあたりが実際に使われています。

Heap::Fibonacci
フィボナッチヒープを取り扱うモジュール。

MT内では使われていなくて、Cache::Memoryの依存モジュール。

フィボナッチヒープ自体、何が良いのか一度作ってみないと理解不能な感じなので、よくわかりません。

I

I18N::LangTags::*
RFC3066形式の言語タグを取り扱う関数をエクスポートするモジュール。

Locale::Maketextの依存モジュールで、MT::L10Nでも使われてます。言語タグから言語名を取得するのに使ってるだけかな。

IO::Scalar
スカラ変数をファイルハンドルっぽく扱うためのモジュール。

MTでも依存モジュールでも使ってなさそう。

IO::WrapTie
IO::Handleインターフェイスでtieされたオブジェクトを扱うためのモジュール。

IO:Scalarの依存モジュール。

IPC::Cmd
外部コマンドをPerlから簡単に実行するためのモジュール。

MTでは直接利用していない。Archive::Extractの依存モジュール。tarコマンドやらzipコマンドやらを使う時に利用されている。

Image::Size
画像のサイズを取得するためのモジュール。

MT内でも、MT::Imageや、MT::Asset::Image等、画像サイズの取得が必要な場面で利用されている。

J

JSON::*
PerlでJSONを取り扱うためのモジュール。

MT内でもJSONを取り扱う箇所でいろいろ使われています。

L

LWP::*
PerlのWWWクライアントツール群。

MTでは、主に、LWP::UserAgentが外部サイトへのアクセス等で背面化でいろいろ働いてます。MT->new_uaで、MT用にカスタマイズされたUserAgentが作れるようになっています。

Locale::Maketext
ローカライゼーションのためのフレームワーク

MTのローカライゼーションの基盤です。プラグイン開発で使う、translate関数の元です。

Lucene::QueryParser
全文検索ソフトLuceneののクエリパーサ。

MTでは、MT::App::Search等で使っていて、検索クエリの解析に使ってるみたい。

M

MIME::Charset
MIMEのためのCharset情報を扱うモジュール。

MTでは直接使っていなくて、MIME::EncWordsの依存モジュール。

MIME::EncWords
RFC2047形式でエンコードされた文字を扱うためのモジュール。

MT::Mailでメールのヘッダをエンコードするのに使われている。

Math::BigInt
BigIntを扱うためのモジュール。

MT::Utilのdsa_verifyで、Crypt::DSAがない時に、これを使ってなんとかしている。

Module::Load
モジュールローダー。

Module::Load::Conditonalの依存モジュール。

Module::Load::Conditional
モジュールの情報によってロードするモジュールローダー。

MT内では使われていませんが、Archive::ExtractやIPC::Cmdの依存モジュールで、can_loadメソッドが使われています。

N

Net::HTTP
HTTPクライアント。

MT内では使われていません。LWP::Protocol::httpやNet::HTTPSの依存モジュール。

Net::HTTPS
HTTPSクライアント。

Net::HTTPと同じく、LWP::Protocol::httpsの依存モジュール。

Net::OAuth
PerlでOAuthを扱うためのモジュール。

もしかしたらコマーシャルパックでは利用するのかもしれませんが、MTOSでは利用してなさそう。

Net::OpenID::*
PerlOpenIDを扱うためのモジュール。

MTでは、MT::Auth::OpenIDで使われています。コメント投稿時にOpenID使う時とか。

P

Parms::Check
関数の引数をチェックするモジュール。

MT内では使われていません。Archive::Extractや、Module::Load::Conditional等で引数チェックに使われています。

Params::Validate
関数の引数をバリデートするためのモジュール。

MT内でも、何かの依存モジュールでもなさそう。

S

SOAP::*
SOAP関連のモジュール群。

MTでは、MT::XMLRPCServer等で使われている。

T

TheSchwartz::*
ジョブキューシステムTheSchwartz関連モジュール。

SixApart製ということもあり、MTのジョブキューシステムはこれで管理されている。

U

UDDI::Lite
UDDIクライアント。

MT内で使われてなさそう。

UNIVERSAL::require
モジュールローダーのひとつ。

Net::OAuthで使われている。

URI::*
URIPerlのインターフェイス。

MT内では、MT::App::Wizard、MT::AtomServer等、URIを分解する時等に利用されている。

W

WWW::RobotRules

MT内では直接使われてません。LWP::RobotUAの依存モジュール。

X

XML::Atom
ATOMのインターフェイス。

MTでも、MT::AtomやMT::AtomServer等、ATOM関連で使われている。

XMl::Elemental
XMLPerlオブジェクトにパースするモジュール。

XMl::Parser::Style::Elementalの依存モジュール。1

XML::Parser::Lite
正規表現ベースのXMLパーサ。

特に使われていない。

XML::NamespaceSupport
XMLのnamespaceのインターフェイス。

XML::SAXやXML::Simpleの依存モジュール。

XML::SAX
SAXパーサ。

MT::Utilで使われていて、MT::BackupRestoreに必要なモジュールになるので、ブログのバックアップと復元機能が使えなくなる。

XML::Simple
簡単に使えるXMLインターフェイス。

MT内では直接使われてないけど、XML扱う時には使えそう。

XML::XPath
XPathに基づくXMLパーサ。

MT内では、MT::AtomServerとMT::Auth::OpenIDで使われている。

XMLRPC::Lite
XMLRPCのPerl実装。

MT内では直接使われていませんが、XMLRPC::Transport::*の依存モジュール。

XMLRPC::Transport::*
XMLRPC::Liteの様々なプロトコルの実装。

mt-xmlrpc.cgiで、XMLRPC::Transport::HTTPが使われている。

Y

YAML::Tiny

YAMLファイルを読んだり書いたりするモジュール。

MTでは、MT::Util::YAML::Tinyという名で再定義されている。

V

version::*

バージョンオブジェクトを扱うためのモジュール。

まとめ

思ったより、必要最小限のモジュールしか使ってないなという印象がありました。やはりいろんな環境で動かそうと思うと、依存多すぎてもいけないってのがあるのかもしれませんね。extlib配下のモジュールのものでも、Perlのバージョンによっては標準モジュールになっているものもたくさんあります。

toolsの中に突如Web::Scraper依存のコードがあったり、コード書く人によって、違うのかもしれませんが。

どこで使われているかよくわからないものもありましたが、今回調べたバージョンで使われていなかったり、MTOSでは使われていないものもあったのかもしれません。

Tips

特定のモジュールが特定のPerlのバージョンの標準モジュールかどうかを調べるには、Module::CoreListが便利です。corelistというコマンドがインストールされるので、それを使えば標準モジュールを調べられます。

$ cpanm install Module::Corelist
$ corelist --help
$ corelist -a Module::Load

また、依存モジュールも含めてローカル領域にCPANモジュールをインストールするには、cpanmコマンドの方が楽でしょう。XS依存の部分はサーバーに単純に上げても使えませんが、*::PPとか書いてあるモジュール探すとか、metacpanでpure perlと検索して探して解決するとかで対処する感じですね。

$ cpanm -h
$ cpanm -L ./extlib Plack

cpanmのインストール等、Perlの環境構築については、あと味の[Perlの環境構築 - あと味などを参考にしていただければと思います。

最後に

来年はMovable Typeに本気で取り組みます。

Perlのリストのおもしろいところ

PerlのリストはPerlらしいというか、結構おもしろいなーと思うことがあります。

Perlのリストの面白いところを紹介してみます。

cons, append

Perlでconsとかappendするいい方法何かなーとか考えてた時に、リストの標準機能でできることに気づきました。

my @one_to_three  = (1, 2, 3);

# cons
my @zero_to_three = (0, @one_to_three);

# append
my @one_to_four = (@one_to_three, 4);

concat

同じような方法でconcat相当もできます。

my @one_to_three  = (1, 2, 3);
my @four_five_six = (4, 5, 6);

# concat
my @one_to_six = (@one_to_three, @four_five_six);

ハッシュ版cons, append, concat

Perlでハッシュを定義する時は、以下のように定義します。

my %foo_bar = (foo => 1, bar => 2);

これはいろんな書籍に書いてあることですが、以下の別記法です。

my %foo_bar = ('foo', 1, 'bar', 2);

ハッシュはkeyとvalueが対になったハッシュをリストコンテキストで評価すれば、ハッシュになるわけですね。

この特徴を利用すれば、ハッシュ版のcons, append, concatも可能になります。

my %foo_bar = (foo => 1, bar => 2);
my %baz_qux = (baz => 3, qux => 4);

# ハッシュ版cons
my %hoge_foo_bar = ('hoge' => 0, %foo_bar);

# ハッシュ版append
my %foo_bar_hoge = (%foo_bar, hoge => 3);

# ハッシュ版concat
my %foo_bar_baz_qux = (%foo_bar, %baz_qux);

面白いですね。

car(head), cdr(tail)

関数型言語でよくあるcar(head), cdr(tail)などもリストの標準の機能でOKです。これくらいのことをするのに、イチイチ関数なんていらんかったんです。

my ($car, @cdr) = (1, 2, 3, 4);

多値っぽいもの

多値っぽいものもできます。

my $zero = 0;
my $one  = 1;
my $two  = 2;

# リストの各要素に10足したリストを返す関数
sub map_add_10 {
  map { $_ + 10 } @_;
}

my ($ten, $eleven, $twelve) = map_add_10($zero, $one, $two);

便利ですね。

分配束縛っぽいもの

引数を分解するのも簡単です。超単純なheadとtailを関数にしてみましょう。(先ほどいらんかったんですって言ったとこですが...)

sub head {
  my ($x, @xs) = @_;
  $x;
}

sub tail {
  my ($x, @xs) = @_;
  @xs;
}

my $head = head(1, 2, 3);
my @tail = tail(1, 2, 3);

補足

面白いんですけど、リストは1次元しか表現できないので、2次元以上はこのワザは使えません。

ちなみに最近まで、同一視していたんですけど、配列とリストはPerlでは別物という扱いだそうです。

参考: リストと配列(Array)はPerlでは別物 - Togetter

まとめ

Perlのリストおもしろいですね。*1

*1:ただ、Perl関数プログラミングするのは、個人的には微妙な感じしてます

簡易的なuniqメソッド(文字列限定)を書いたので、underscore.jsのuniqメソッドとベンチマーク取ってみました

グリモンを書いてて、uniqメソッドを自前で作ろうと思ったのですが、少し面白い方法を見つけたので、jsPerfでベンチマークしてみました。文字列専用ですが。

自前のuniqメソッド

オブジェクトを構築する際に、キーはひとつのオブジェクトに対してユニークになるので、適当な値を突っ込んでオブジェクトを構築し、最後にキーだけ取り出す感じです。reduceを使えば、4行程度で書けます。

underscore.jsのuniqとの比較ベンチマーク

underscore.jsのuniqメソッドと比較しました。第2引数の最適化オプションの有り無しでも比較しています。

こんな感じになります。

string-uniq · jsPerf

まとめ

文字列限定ですが、underscore.jsのuniqメソッドで、最適化オプションなしの状態より速い場合が多いようです。

ただ、Google Chromeでは、underscore.jsの最適化オプションがfalseでも、今回作ったuniqメソッドよりも速いので、実用的かどうかは微妙なところです。

Object.keysメソッドが遅いのかな?それとも、バイナリサーチが得意なのかな?よくわかりません。

追記

@hokaccha さんとのやり取り。

悔しいですけど、for速いですね。

MovableTypeのモジュールのPODのViewerプラグイン作った

MovableTypeを触っていると、MTのモジュールのPODを見る機会が多くなります。MTタグの使い方とかも該当モジュールのPOD見れば解決することもあるので、とりあえずアイデアレベルですが、昨日作ってみたのでエントリー起こしました。

MTPodViewerという名前を付けました。

20121004112532

デモサイト

MTPodViewer

インストール

リポジトリにあるplugins/MTPodViewerをサイトのpluginsにコピーします。加えて、リポジトリにあるmt-static/plugins/MTPodViewermt-static/pluginsにコピーします。

依存モジュールはextlibに同梱したつもりですが、動かなかったらごめんなさい。cpanコマンドかcpanmコマンドでインストールしてください。依存モジュールは、plugins/MTPodViewer/Makefile.PLに書いてあります。

プラグイン設定

システムのプラグインに進むと1箇所だけ設定があります。

ログイン必須にするかしないかの選択です。Yesならログイン必須、Noならログイン不要です。

検索方法

たとえば、MTのディレクトリで、perldocする場合、以下のような感じになると思います。

$ perldoc lib/MT/App.pm

MTPodViewerでは、以下の様なキーワードで検索することになります。

app

MT::Template::Tags::Entryを検索したい場合は、

template-tags-entry

と検索します。

MTというプレフィクスは省略して、「/」や「::」の区切り文字を「-」にして、全部小文字にしているということです。

bootstrapのtypeaheadがある程度面倒見てくれるので、これで充分な気がしてます。

感想

最初はCSSとか自分で書いてたんですけど、途中からbootstrapに変更しました。bootstrap-typeaheadのスタイル作るの面倒だったので...。というか基本的にbootstrapは何かと楽でマジ助かります。

見出しのフォントはHelvetica、本文のフォントはGoogle Web Fontsにある、OpenSansにしました。すごく読みやすいですね、このフォント。

速度的にはちょっと微妙なので、モジュール一覧をキャッシュしておくなりした方がいいと思いますが、また気が向いたら対応します。

リンクの部分とかは、Pod::Simple::XHTMLの吐き出すソースをちょっとカスタマイズしたらうまくできるのかもしれませんが、ページ内リンクと別モジュールへのリンクがうまく場合分けできなさそうなので、リンクをすべて外すって対応を取っています。

MTアプリケーションはMTをWAFと思えば、普通に使えますね。クライアントワークだったら、依存モジュールの解決もそんなに面倒じゃないですし、最近は、MTアプリケーション作る機会もあって、いろんなCPANモジュールと組み合わせて使ってます。

あと、英語のドキュメント書けない。深刻。

kanazawa.rbで「Mojoliciousと愉快なPerl」という話をしてきました

つい先程の話。kanazawa.rbで「Mojoliciousと愉快なPerl」という話をしてきました。

Perlの記事を書いたことはあるけど、Perlについての発表をするのは初めてだったので、いつも以上に緊張した感じです。というか、ようやくプログラムの話ができるようになったという感じでしょうか。

スライド

スライドは以下に置いておきました。

話の内容

スライドにはキーワードだけ書いて、口頭での説明とデモがメインだったので、スライドだけ読んでもちょっと物足りないかもしれません。

発表でも話しましたが、かつてはRubyPerlから学ぶことが多かったけれど、今はPerlRubyから学ぶことが多いです。

Rubyの勉強会に参加するのも初めてでしたが、多分、Perlの人がRubyの勉強会に参加するのは、少し先の未来を覗き見することにもなるのかなと思います。

今回はSinatra vs Mojolicious vs Expressみたいな構図でしたが、それぞれパクリ愛に溢れていて、どれも素晴らしいものだと思いました。

ですが、発表の準備をするにあたり、Mojoliciousをいろいろ調べ直してみると、やっぱりMojoliciousが好きです。ひいきなしで、自分はSinatraよりも、Expressよりも、Mojoliciousが好きだなぁと。

Mojoliciousは、標準モジュール以外、すべて自前で用意しているし、どのCPANモジュールを使えばいいかわからないという人でも、とりあえず、Mojoliciousの用意しているモジュールやツールを使えば、Perlで簡単なWebアプリケーションを書くことができるでしょう。

今回の発表では、デモも交えて説明したのですが、Perl使うならperldocをたくさん使いましょうねっていう話をしました。

Rubyのドキュメントの文化とかはよく知りませんが、Perlはドキュメントがちゃんと整っているし、ちゃんと書かないといけない印象で、しかもperldocってツールが最高に使いやすいです。

PODという発明、良いプログラマは良い物書きでもあるという教えが、この文化を生んだのかなと思います。

まとめと反省

Rubyの勉強会に参加することで、Rubyの人になる可能性もありますが、もはや、Perlのキモかわいさに慣れてしまって、なかなか難しいような気もしています。*1

去年のYAPC::Asia TOKYO2011に参加して、感想記事を書いた中で、来年のYAPC::Asiaまでに、CPAN Authorになりたいとか、次回のYAPCではLTに出たいとか書いていましたが、結局この目標は未達になってしまいました。。。*2

自分を慰めるとすれば、Perlの勉強会ではないにせよ、Perlの発表をすることができたのと、Perlでツールを作って公開するということはできたという点でギリギリ赤点でしょうか。もっと精進します。

最後に

次回はkanazawa.rbの本編?である、beer会にも参加したいです。

kanazawa.rbの皆さん、今日はありがとうございました。

@wtnabeさん、ご招待ありがとうございました。

*1:個人的には、Rubyに転向するより、Clojureに転向する可能性の方が高い

*2:YAPC::Asia 2012に参加することすらできずorz...

margin-top派かmargin-bottom派で言えば、margin-top派です

世の中にはmargin-top派とmargin-bottom派がいるとかいないとか。

自分はmargin-top派です。

margin-left派とmargin-right派がいるならば、margin-left派です。

試しにmargin-bottom派になってみようかなと頑張ってみたんですけど、やはり慣れもあり、margin-topの方がしっくりきたのでエントリーを起こすことにしました。

margin-top派な理由

margin-top派になったのには理由はなくて、なんとなくmargin-top派になった気がするのですが、margin-bottom派に移るのが少し面倒な理由はあります。

その理由は:first-child擬似クラスの存在です。

例1

例えば、以下の様なHTMLがあったとします。各section.contentの間には30pxの余白が欲しかったとします。

<section class="content">
  <h1>title1</h1>
  <p>section2</p>
</section>
<section class="content">
  <h1>title2</h1>
  <p>section2</p>
</section>
<section class="content">
  <h1>title3</h1>
  <p>section3</p>
</section>

この場合、:first-childを利用すると、margin-topで楽にレイアウトできます。

section.content {
  margin-top: 30px;
}
section.content:first-child {
  margin-top: 0;
}

margin-topで、30pxの余白を取ります。そうすると各section.contentの間には、30pxの余白が確保できます。しかし、このままだと、先頭のsection.contentには余計な30pxの余白が入ってしまいますので、:first-child擬似クラスを利用して、先頭の余白を0にすることで、各section.contentの間に30pxの余白を作るということが実現できます。

例2

横並びでも同じです。リストが横並びで、各リスト項目の間に20pxの余白を取りたい場合です。

<ul>
  <li>item1</li>
  <li>item2</li>
  <li>item3</li>
</ul>

CSSはこんな感じになります。

ul {
  margin: 0;
  padding: 0;
}
ul li {
  list-style-type: none;
  display: inline;
  margin-left: 20px;
}
ul li:first-child {
  margin-left: 0;
}

こんな感じです。

このケースでは、:first-childを使わなくても、以下のようにすればOKですね。

ul {
  margin: 0 0 0 -20px;
  padding: 0;
}
ul li {
  list-style-type: none;
  display: inline;
  margin-left: 20px;
}

それ、:last-childでできるよ

そうなんですけど、IE7から対応しているのと、IE9から対応しているのとでは、大きな違いがありますし、IE8とか捨てれる状況でないので、:last-childを実務で使える状況はあまりありません。

まとめ

margin-top派、かつ、margin-left派です。その理由は:first-child擬似クラスを利用して、余白を調整する機会が多いからです。

IE6に対応しないといけない案件の場合は、:first-childの代わりに、.firstを付けることがありますが、要素を後ろに追加する機会の方が多い気がするので、.lastと付けた要素より、.firstと付けた要素の方が、後々、影響を受けないことが多い気がします。なんとなくですけど。

数年後、:last-childがどんな案件でも使えるようになったら、margin-bottom派に移行するかもしれません。現状は、margin-topの方が利点があると思っているので、margin-top派です。

もし、margin-top派だと面倒な事例があれば、ツッコミいただけると嬉しいです。