PHPとかいろいろ演算代入系の演算子のハナシ

PHPの関数定義はこんな変態的な書き方ができる - 頭ん中

に、続いて。アンリーダブルコードで勉強しようというのがあった、そのとある勉強会の発表ネタです。

これは、PHPのMarkdownパーサ の実装を可能な限りそのまま綺麗に変換してJavaScriptに移植しようという js-markdown-extra をやっていたとき、大ハマりして修正に苦労したバグの話から来てます。

演算代入。+= とか *= とかのやつ。関数型の人以外はきっと常用してますね。じゃあ問題。

<?php
$tokens = array("a", "b", "c");
$tokens[0] .= array_shift($tokens);
print_r($tokens);

こうするとどんな結果が出力されるでしょうか。PHPです。

自身の先頭から要素を取り出して、それを先頭要素に文字列追加する。array_shift() では "a" が先頭から取り出されて $tokens == array("b", "c") になります。取り出された値は配列の先頭要素に「文字列として追加」されて配列の先頭要素に代入されます。結果を見ましょう。

$ php test.php
Array
(
    [0] => ba
    [1] => c
)

...って思いますよね。ここまで、いいですか、よくないですか。

ところがPHPは... という話だと思ったら大間違い。もしPHP以外の言語の人なら、間違っているのはあなたのプログラミング能力ですよと。PHPerはこれでOKです。

JavaScriptで書きました。

var tokens = ["a", "b", "c"];
tokens[0] += tokens.shift();
console.log(tokens);

なんとこれ、答えはこう出ます。

$ node test.js
[ 'aa', 'c' ]

え、え、まあ JavaScript は変な言語だからさあ...

そこにPython委員長がやってきた。

tokens = ["a", "b", "c"]
tokens[0] += tokens.pop(0)
print tokens

$ python test.js
['aa', 'c']

やばい!! PHPちゃんが多数決で負けちゃう。助けてRubyちゃん。(嫌なこと言われることもあるけど、最近嫌いじゃないのよね、あの子。)

tokens = ["a", "b", "c"]
tokens[0] += tokens.shift
p tokens

$ ruby test.rb
["aa", "c"]

あああああーーーっ、Ruby子ちゃんまで。PHPちゃんボッチかわいそう。

検証

すんません、ちゃんとやります、はい。ようするに、a += ba = a + b と等価ってのがわかればいいんですよ、きっと。JavaScriptで検証、やってみましょう。

function equal_and_plus()
{
    var tokens = ["a", "b", "c"];
    tokens[0] = tokens[0] + tokens.shift();
    console.log(tokens);
}

function equal_plus_operator()
{
    var tokens = ["a", "b", "c"];
    tokens[0] += tokens.shift();
    console.log(tokens);
}

equal_and_plus();
equal_plus_operator();

[ 'aa', 'c' ]
[ 'aa', 'c' ]

合格ですね。PythonRubyもこれと同じですね。じゃあPHPはいったい...

<?php
function equal_and_plus()
{
    $tokens = array("a", "b", "c");
    $tokens[0] = $tokens[0] . array_shift($tokens);
    ptint_r($tokens);
}

function equal_plus_operator()
{
    $tokens = array("a", "b", "c");
    $tokens[0] .= array_shift($tokens);
    ptint_r($tokens);
}

equal_and_plus();
equal_plus_operator();

Array
(
    [0] => aa
    [1] => c
)
Array
(
    [0] => ba
    [1] => c
)

違う演算じゃんかこれ

そのとおり、PHPの場合は「加算と代入」は「加算代入」と等価ではなかったのです。ちょっと最初に動かす前に想像した結果に戻ってみてください。「取り出して」→(右辺の変数が変化して)→「代入」って考えましたよね。PHPはそのとおり動きました。

でも他の言語では実際には、「加算代入は加算と代入である」という等価関係を死守します。その結果、最初に評価されるのは tokens[0] = tokens[0] + shift(tokens) 左辺の第1項 tokens[0] つまり "a" です。それに、shift で先頭要素を取り出して詰めた戻り値の "a" が足されます。そして、["b", "c"] という2要素の配列となったものの最初の要素 "b""aa" が代入されます。

たしかにPHPは、言語としての美しさの点では劣りました。が、そもそも「加算と代入」は「加算代入」と等価であるという言語仕様は、すべての処理系で保証されるのでしょうか。「加算代入」という等価変換できない別の演算があるのだと考えればどうでしょう? そう考えるとPHPは、人間らしい自然な思考に合わせて、「加算と代入」が「加算代入」と等価ではない処理系を選んでいるとも言えます。

まあ、こういうことですね。

<?php
function eval_right_then_set_to_left()
{
    $tokens = array("a", "b", "c");

    // 右辺の値
    $right = array_shift($tokens);

    // 左辺に入る値を算出
    $left = $tokens[0] . $right;

    // 代入のところ
    $tokens[0] = $left;

    ptint_r($tokens);
}

そもそも、二者が等価でなければならない理由ってあるんでしょうか。C言語と違うから? 違う言語は違う処理系を持っていて当然ですね。Cはコンパイラにとってコンパクトな仕様だったから等価にしただけかも。ルールが少ないほうが文法の学習コストが低い? 言語の文法なんて他の学習の総コストに比べたら低いですよね。マニュアルに「同じじゃないよ」と書いてあればそう学べばいいんですよ。

PHP: 代入演算子 - Manual

$a = 3; $a += 5; // $a を 8 にセットします。$a = $a + 5; と同じです。

ギャフン

こ...こんなことが宝石系の言語の人に知れたら、またはてブが炎上するに違いない。こりゃ門外不出だぜ。なんかアレみたいな話だな。

と思ったんですが、試しに普段あまり使わないPerlでもやってみました。

# 加算して代入
@tokens = ("a", "b", "c");
$tokens[0] = $tokens[0] . shift(@tokens);
print join(',', @tokens) . "\n";

# 加算代入演算子
@tokens = ("a", "b", "c");
$tokens[0] .= shift(@tokens);
print join(',', @tokens) . "\n";

とりゃー

aa,c
b,c

なんと、誰も期待しなかった結果を返す言語は実はPerlでした。

これ、結果の解釈いろいろ深いですね。なんかこんな感じ? せっかく入れた "aa" を最後に消しちゃう。んーよくわかんない。

@tokens = ("a", "b", "c");
$tokens[0] .= $tokens[0];  # shiftからの戻り値のみ
shift(@tokens);  # shiftの実行そのもの
print join(',', @tokens) . "\n";

(よしこれで白い宝石の方からのマサカリは飛んで来ないぞ...と思うんだけど、もし、Perlではこう書くのが普通だよというのがあったら教えてください)

(ブクマコメントで @tokens[0] がスライスになってると教えてもらいました。やってもうた。$ に修正して結果が同になることを確認しました。)

というわけで、これって怖い人に「PHPなんてものを使うことがそもそも...」とか言われる系の話じゃなくて、

見た目がまったく同じなのに言語処理系によって非互換性なところはあるので、どの言語を使うにしても、直感で人によって解釈が分かれるようなコードになるおそれがある場合は、他人が読んでもわかるよう、自分の頭の中にある理解の順を正しく表現したコードにしましょう、

というのが大事ですねという話でした。

これって、純粋関数型で再代入を禁止するべきとかそういう極端な話じゃなくて、プログラマーの素朴な人間力ってだけだと思います。処理系が違えば言語仕様は違って当たり前なのに、自分の好きなアレと違うからダメな言語と言ってしまうのは良くないよね、とか、字面が読みやすいかどうかではなく、こういうのを分けて書かないとアンリーダブルで大変なことになるんだという学びとか。

あ、フィクションじゃないですよ。ホントにあったんですよこれ。

https://github.com/tanakahisateru/js-markdown-extra/commit/1a0b98b32cf1a94b2e87efd960190f5c47243f46#L0L1161

そうそう PHP といえば

こちらもよろしくお願いします!

なぜ『PHPエンジニア養成読本』はAmazon部門ランキングでトップを取るのか

PHPエンジニア養成読本 〔現場で役立つイマドキ開発ノウハウ満載! 〕 (Software Design plus)

PHPエンジニア養成読本 〔現場で役立つイマドキ開発ノウハウ満載! 〕 (Software Design plus)

PHPエンジニア養成読本

なぜ『PHPエンジニア養成読本』はAmazon部門ランキングでトップを取るのか

またしても釣りっぽいタイトルをつけてしまいました。ご無沙汰しております。

PHPMatsuri 2013の参加レポートも書かずに何をやっていたのかというと、実は本の執筆に参加させて頂いており、ちょうどその頃忙しすぎて忘れていました。こんな本です。

PHPエンジニア養成読本 〔現場で役立つイマドキ開発ノウハウ満載! 〕 (Software Design plus)

PHPエンジニア養成読本 〔現場で役立つイマドキ開発ノウハウ満載! 〕 (Software Design plus)

その名も「PHPエンジニア養成読本」。担当させてもらったのは、注目のフレームワークPHPUnit、Gitといった内容です。詳しい内容は先に書かれているエントリご覧ください。

ようやく書影が定まり、こんな感じで本日(2013/8/27 ...あ、日付変わってるか)より告知スタートしています。で...

告知されるやいなや、なんとみるみるうちにAmazonのWeb開発書籍ランキングでトップに躍り出ました。

f:id:tanakahisateru:20130828005725p:plain

なんということでしょう。まだ予約しかできない段階だし「ナカ見」とかもないんですよ。

そしてさらに、書籍全体ランキングで『連続テレビ小説あまちゃん Part2 (NHKドラマ・ガイド)』と競うとかもう。

f:id:tanakahisateru:20130828005808p:plain

まあ、これは瞬間最大風速的なデータなのかもしれませんが、それでも、表紙や章立てしかわからないのにすぐに購入予約してくださる方がこんなに多いのって、すごくないですか。ありがとうございますありがとうございます。

ちょっと執筆参加したというのは抜きにして、本当に、なぜこの本がこんなに上がるんだろうということに思いを馳せてみました。

いまPHPの世界には、すごく大きな変化が訪れています。でも、その変化がずっと連続していて、これまでなかなか一冊の本にまとめられるタイミングがなかった状況が続いていたんじゃないかと思います。

PHPで仕事をしている人は数多くおられると思います。みなさん、毎日忙しく働いているいっぽうで、Twitterやブログであれこれと新しい技術の名前が流れてきたり、あんな勉強会に行ったこんな勉強会に行ったと羨ましい話を聞いたり。本当は全部試したいけれど、とてもじゃないがそんな時間はないという方が大多数なんじゃないでしょうか。

最近はアジャイルな空気が出てきて、J2EEの大型開発案件よりも、PHPを使った小さなツールを素早く作るような仕事が増えて、JavaプログラマPHP流入も多いと聞きます。Javaの人からすれば、「Mavenはないのか」「コーディング規約どうなってる」「PHPでいうJUnitとかEclipseとかはどんな感じなのか」というもやもやも多いでしょう。

また、新しい技術はいつも英語で発信されます。「エンジニアたるもの英語のひとつも読めなければ」と言うのは簡単ですが、現実には、読もうと思って開いたページの英語は読めても、英語で書かれた情報の海にアンテナを張ることができる日本人は、かなり限られると思います。

これまで、入門者を対象にしたPHPの本は繰り返し出版されてきました。また、ひとつのフレームワークに特化して深く内容を掘り下げる本もいくつか出版されています。しかし、 パーフェクトPHP 以降、すでに入門を終えていてもっと成長したいのに、と感じているエンジニアに、PHPの文化を広く俯瞰できるような内容の本が提供されて来なかったんじゃないでしょうか。

それは、ライブラリやサービスの新バージョンがそれぞれ非同期にかつ継続的にリリースされ続け、一冊の本として書けるほど安定していなかったからではないかと思います。

そんな状況で、「ムック本だから執筆時点のスナップショットでいい」と割りきって紙にしてしまおうという方針が、もやもやしていたPHPerのハートを直撃したんじゃないかと思います。読者としては、こんなコンセプトの本は他にない、だから選ぶ余地なく予約しよう、ってことなのかなと。

執筆のキックオフ・ミーティング前後で「他の本で取り上げられていなかったことをやろう」と話していたのが結果につながったのなら幸いです。

ムック本なので個々の記事のボリュームには限度があるけれど、英語だったり散発的に聞きかじったりしているあれやこれの最初のアンテナとして、たしかにすごくリーズナブルな一冊かも、と、執筆していなかったら自分も予約していただろうと思いました。

この本はこんな方にお勧めです:

  • 以前からPHPを使った開発をしているけれど、よりモダンなPHPを目指したい設計者
  • PHPのバージョンを上げたはいいけど、それでどんな機能が使えるのか自覚していなかった人
  • フレームワークやライブラリなど、話題の技術の最初の一歩でどれをやったらいいか迷っている人
  • 本当にPHPを使い込んでいる人が技術のどの部分に注目するのか、気になる人
  • どこから試していいのか、どれぐらいお金がかかるのかわからず、クラウドに手を出せなかった人
  • モダンPHPに関係するキーワードが拾えていなくて一気に仕入れたい人

実際は使われていたり機能が良かったりするのに、これまでほとんど紙媒体に掲載されることがなかったキーワードをじゃんじゃん載せているのは本当です。これはすごくオススメポイント。

あと、共同執筆のムック本では珍しいと思うんですが、執筆者の多くが直接顔を合わせ、互いに内容をレビューし合って書かれていて、書籍としての一貫性や各章の関連性がわりと強い感じです。なので個人的には、いろんなことを知れる本であると同時に、一冊の本としてPHPで起こっている一本の大きな潮流を表現できていたらなぁと願っています。

最後になりますが、こんな素晴らしいプロジェクトに誘ってくださって、関係者の皆様本当にありがとうございます。この二ヶ月はとても貴重な体験でした。

p.s.

PHPカンファレンス東京へ行かれる方は、Amazonの予約で1冊、PHPカンファレンス会場でもう1冊買うのをオススメします。発売日が9/13なので、9/14日のカンファレンスの時点で入手できていない可能性があります。2冊も買うのかと思うかもしれませんが、1冊は自宅用で、もう1冊は布教用です。職場で回覧して「導入しましょう!!」ってやるためのやつです。なので会社名で領収書を切っておきましょう。

PHPカンファレンス関西2013 #phpkansai を終えて

3回目となる PHPカンファレンス関西2013、今回はスタッフとして参加してきました。

PHPカンファレンス関西2013まとめ - Togetter

去年のテーマは「好きやねんPHP」でしたが、今年はなんと「PHPの未来を関西から」です。大きく出ましたね。どんな未来を発信したのでしょうか。

というわけで僕としては、現在の水準と比べて何が「未来」っぽいと感じたかを書きたいと思います。(他のネタは他のスタッフがやってくれると思うので。ブログを書くまでが勉強会ですしね。)

多言語パネルディスカッション

ものすごい過去の話から始めます。

それは、PHPユーザーは他の言語から学んでいるのか、という点。

PHPユーザーが他の言語ユーザーよりも弱いのは、そこなのではないか。

404 Blog Not Found:「PHPなめんな」と「(Perl|Python|Ruby)をなめんな」の違い

セッション中に出たヒゲのおじさんのこの発言が、2013を読み解くうえで非常にポイントになると思っています。

PHP5.3から始まるあの貪欲な他の言語の特徴の取り込みは、もはや語るまでもないですね。クロージャ、トレイト、ジェネレーター。たぶんこのままいけば、再代入禁止変数の宣言だとか、参照等価関数のメモ化なんかも、文法に入ってくるんじゃないでしょうか。個人的には、ショートアレイシンタックスのような、ショートクロージャシンタックスが来てほしいです。脱線しました m_ _m とにかく、PHP開発者はもう学んでいますというのは明白です。

じゃあユーザはどうか。

セッション内容は、PHPコミュニティ以外から、言語ごとに有名なエンジニアを招待してその言語の文化を知ろうという企画です。僕はPHP代表として、話長すぎるおっさん をやらせてもらいました。Pythonとか誠実な言語はいいよ、とか、関数型も知っておこうね、とか、自分の言語PHPが相対的にどういうポジションで活きるのか(これ大事)、とか、そのあたりが伝わってたらいいなあと願っています。

そこで逆に驚いたことがあります。たいへん失礼な言い方になるのですが、Java/JVM言語の人もLLの人もみんな、PHPについてあまり学んでいなかったという事実です。僕が知る限りでは、PHP以外の言語を使えるPHPerは案外多くて、逆に、最適なPHPを書ける非PHPユーザは少なかった。自分が正しくモダンPerlを書けと言われて手が止まる、みたいなものかも(新大阪コワーキングに教えてもらいに行こう)。

というわけで、もし怖い人に「他の言語から学んでいるのか」と聞かれたら「そちらはPHPから学んでおられますか」と返せるんじゃないかなと思いました。というのは冗談で、PHPは、もう実用言語としての地位を持っているしその根拠も説明したし、なんだから、これからは、他の言語のユーザに、PHPの変な仕様は、他の言語の言葉を使ってPHPなりの正しさを誠実に説明して、賢い人にもっと正しく学んでもらえる言語としてアピールして行ってもいいんじゃないかな、というのが、自分の中でだけですが、感じた未来です。

裏座談会で、Javaで作っていたものがPHPにシフトしてるんじゃないかという仮説も出ましたし、ってこれはお金の話ですね。まったく大阪はw

Debugging and Profiling PHP

というわけでみんな学びましたよ。英語から。

同時通訳なし、全部英語のセッションです。通訳は遅れてTwitterで流れてくるだけなので、画面で起こっていることは英語のリスニングでなんとかしないといけません。これがなんと、大ホールのほうで行われるんですよ。英語が当たり前なんだという衝撃、集中して聞いたら情報量ゼロじゃない、なにか聞きだせる、ということを、なるべく多くの人が感じてくれたら幸いです。

本当なら、セッションの後に教えてもらおうとがんばって英語で Graham に話しかける、なんて人が現れてもよかったのですが、彼が仕事忙しそうで早く上がってしまったのが残念です。楽天って土日に仕事割り込んで来るぐらい大変なのかな。

Chef + Vagrantで作るこれからの開発環境とクラウド

他の言語? ChefもVagrantも設定ファイルをRubyで書くんですよね。学ばざるをえないんじゃないですかね。 (ごめんなさい実は聴けてませんでした)

Ginq

裏の目玉商品がこれです。「未来を関西から」にもっとも合っているのが、実はGinqだったんじゃないかと思っています。実は発表者の @akanehara 氏は僕のもと同僚で、「PHPだけだとわからなかったHTTPがJavaPythonで理解できた」と言っていたタイプの人間です。カンファレンスのプログラムがまだ決まってなかった頃、僕もまだそのときスタッフじゃなかったんですが、いいから騙されたと思って、ってノリでお互いに薦めて、メインセッションに入れてもらいましたという経緯で行われたセッションです。

LINQインスパイア系ライブラリGinqの紹介

GinqのアイデアはC#のLINQから来ています。GinqのGの由来はまだリリースされていないPHP5.5のGeneratorです。GeneratorはPythonに由来する機能です。達成したことがすごいですよ。途中の一時変数がなくなります。データをすぐに操作せずにまず「操作するということを合成」するのです。合成された操作を使って、最後に入力を出力に直結するので、array_mapとarray_filterに必要な中間バッファが必要なくなります。-> このメソッドチェインで新たな操作コンテキストを次々と生成(コンテキストオブジェクトはイミュータブルで状態を持たない)しつつ、同じ演算の再評価をしない参照等価な関数の遅延評価の世界を作っています。モナドっぽいアプローチでHaskellの基本機能を実現し、それをC#の世界から借りてきたクエリ言語でパッケージ。...もう他の言語から学びすぎですね。

PHPのLINQっぽいライブラリはこれまでにも存在したけど、データを直接操作せず、データを操作する概念を合成してからの遅延評価をやり、必要に応じてメモ化をできるというのは、おそらく世界初です。なぜこれまで存在しなかったかというと、ジェネレーターがなかったから。

array_mapは一時バッファを使わざるをえないものの、元のデータがどうせarrayで来るからという理由で、僕もまあいいやと妥協していました。これまでのPHPは、あらかじめSQLで十分に絞り込んだせいぜい50件程度のデータをHTMLにできれば良かった。スタンドアローンのLAMP構成でもっとも使われてきた。

ところが、NoSQLによるSQLボトルネックのブレイクスルーや、クラウドによる分散コンピューティングという時代にきて、未来のPHPは従来のPHPではいられないようになってきていると僕は思います。100万件のデータをストリーミングで取ってきて、事前に加工してからHadoopに投げて出力をフォーマット、絞り込んでストリーミング出力、なんてことをバッファメモリでやっていたら足りないですよ。僕なんか、10000人の会員データをCSVに吐くだけでメモリ足りなくて困ったなんてこともありました。

そこで、バッファを持たないイテレーターをもっとカジュアルに作れるようにと、次はジェネレーターが登場となったんだと思いますが、本当に残念なことに、そのジェネレーターが活きるデータ操作ライブラリが同時にリリースされるわけじゃなさそうです。せっかくジェネレーターを使っても、array_mapや既存のLINQ類似ライブラリでは、結局巨大なarrayが必要になってしまう。で、いろんな言語から影響を受けたGinqは、バッファを持たないストリーミングができる。ね、PHPの未来はこういう形になる、という種が、関西から発信できるチャンスじゃないですか。

話長すぎるおじさん、ちょっと熱くなりすぎました。

ただ、ChefとVagrantの話との裏番組だったので、聴講者が少なかったのが悔やまれます。まあ、逆に言えば、そこであえてGinqを聞くことを選んだ人にまず伝わったというのはあるかもです。

PhpStorm

なんと今回、JetBRAINSの日本代理店のサムライズム様がスポンサーとして直々にIDEのデモを見せに来てくださいました。

有料だしまだマイナーなIDEじゃん、と、思いきや、なんと登壇した発表者の大多数がPhpStormをすでに使っているか、またはEclipseを使いつつもPhpStormを絶賛しているではありませんか。LTを含む発表の使用IDE、自分が記憶しているだけで、SublimeText x 1, Coda x 1, Eclipse x 2, PhpStorm x 6 です。多言語ディスカッションでの普及率は、Perlはしょうがないとして、ほとんどの人がすでにJetBRAINSにお金を払っていました。(IntelliJ IDEA, WebStorm なんかもあります。IDEAのScalaプラグイン最強です)

Ginq の @akanehara 氏なんて、すでに使ってるのにじゃんけんプレゼント大会で優勝してパーソナルライセンスもらって「やったーこれで法人ライセンスとパーソナルライセンスの2本持ちだー」なんてもう、仕込みネタかとw (本当に偶然)

JetBRAINSの @yusuke さんが「PhpStormを使ったらPHPでも思った以上に型安全に書けるんだな」という感想を、このカンファレンスで逆に持ち帰ってもらえたことが、すごく良かった気がします。僕も、PhpStormを使うことで、PHPC#Scalaになったような感覚に陥ることがあります。

でも Eclipse でも PhpStorm みたいなリファクタリング機能が欲しいのになかなか出ないから自分で作る、と、実際に作っている @iteman さんすごいです。EclipseはIDE界のFirefoxとして、欠かせない存在なのです。

で、まあ、どのツールが流行るかという話よりも、僕は、Vim/Emacsで書ける人がわざわざIDEを使おうとし始めているということが、MS製品やJavaにおけるIDEとは違う意味で、PHPの未来に繋がっているように感じるのです。「関心を分離するってどういうこと?」のセッションで、分離された関心の記述箇所が遠ざかるのを、IDEで解析してコードをリンクさせるみたいな話がありました。大事なのはそこだと思うのです。

むかし、IDEがないとプログラムが書けないのは軟弱者、エディタをカスタマイズすれば記述速度は同等になるぜ、という論調がありました。たしかに、Visual StudioにしてもEclipseにしても、いきなりサービスが良すぎて、エディタで書けない人でも開発できちゃう、という空気はありました。が、いまPHPで起ころうとしているIDEブームはむしろ、エディタでも十分に速く書ける種類の人から始まっている気がします。そういう人たちがわざわざお金を払ってIDEを使おうとしていることに、そして、それを生で見られるカンファレンスに、深い意味がある気がします。

初心者がテキストエディタで入門し、上級者になるにつれIDEを駆使した設計へ、という構図。これ、新しくないですか。未来っぽいんじゃないですか。PyCharmでもRubyMineでも同じ構造はあると思うんですが、それが真っ先に起こるのは、PHPのユーザコミュニティだと思います。それは、PHPが他の言語より静的解析に向いていることが、大事な足場になっていると僕は思っています。

Pinoco

まあとりあえずシェアしときます。本業はこっちなので。

お蔵入りスライド(ネタ)

もったいないのでネタ披露します。

話長すぎるおじさん、以上、おしまい。

ドラ娘への熱い想いとか、LTを直前で中断してドラ娘と...とかあたりは任せました! ブログ書くまでが勉強会です。

なぜユーザーコミュニティを見に行くのか - PHPカンファレンス関西2013

まもなくPHPカンファレンス関西2013が開催されます。楽しみですね。

カンファレンス開催にむけて、きのうはKLabの内海さんが 満員御礼!PHPカンファレンス関西2013 | K's BlogK's Blog という記事を書いてくれました。今日はこちらで なぜユーザーコミュニティを見に行くのか について書きたいと思います。

なぜITの人は、会社の仕事と直接関係があるわけでもないのに、しょっちゅう技術ネタで集まるのでしょうか。新しいツールの使い方の無料セミナーがあるから? 受託やってますと名刺を配れば営業になるから? ...たしかにそういう要素はあります、が、それだけじゃ説明つかないのです。というのも、参加者の中で目立つのが、「本を読んだら未経験のツールでもすぐに使えるタイプで、今の仕事にはさほど困っている様子でもない人たち」なのですから。

なんで集まるのかについて、やっぱりそうかと思っている僕の答えは、じっさいの人間はどんな会話をしているのか を体験できるってことです。PHPカンファレンス関西に毎年参加してきた僕なので、まあそんな人が言ってるんだから本当だろうと思って読んでください。

たとえば、ITニュースにありがちな記事見出し

「いま話題の〇〇技術」

え、ホントにそれ話題なの? って思うこと、ありますよね。

逆に、すごく仕事で使っているやりかたも、これ実はただの社内ブームなんじゃないの? 外でも通用するの? という不安もあります。

ちょっとPHPとは違う話になりますが、いま話題の Amazon Web Service (AWS)。話題のw。これアカウントを作ると、提供される全サービスの管理コンソールにいちどにアクセスできるようになります。30個ぐらいあるんでしたっけ。正直「どれがどれやねん!?」ってなりますよ。

突然の辞令でクラウド対応やれと言われてやり始めると、たぶんいきなり迷子ですよ。そもそもクラウドで何をどう改善できるのかだって、ITニュースの聞きかじりで具体的には理解してなかったりして。こういうので困るという前提条件が体験できてなかったり。でも会社には「これからはクラウドだから期待しているよキミ」みたいな...

いっぽう、ユーザコミュニティから聞こえてくる事例には、さりげなくEC2とかS3とか(AWSのサービス名)が入ってきます。Amazonの営業さんの説明じゃなくて、個人的な体験なので偏っているかもしれないけど、すごくインパクトあります。その話に出てくる名前と話の内容を吸収しておけば、いちどに全機能表を見せられても、必要なものに7〜8割がた勘が効きます。

僕は、初回のPHPカンファレンス関西で「明日はクリスマスだからEC2を1000台追加しようぜ〜」という運用がすごく印象に残りました。なんでそんな大量のセットアップが1日で終わるのか... そのとき自分がまだ「独自AMIを使ってサーバのクローンを任意台数いちどに作成できる」ことを知らなくて、言ってる台数と語調の軽さのギャップが衝撃でした。そのときまだAWSを使っていなかったので、後日、AWSで初めてEC2を立てようという練習のとき、そこに出てくる「作成する台数」の欄で「あーーーこれかーーーーっ」となりました。

こういう強い体験って、読んでいるだけではなかなか得られないと思うのです。

インターネットのITニュースサイトには、微妙に業界が違うニュースもいちどに流れてきます。毎日の記事が欲しくて、使われているかどうかを無視した新規性が高いだけのニュースもあります。全部読んでたら大変ですよ。Google Readerもなくなるし。

いっぽう、ユーザコミュニティには、自分の仕事と似た、けど直接関係のない人間のサンプルがわんさかいます。彼ら彼女らが本当に「あの話題の技術」を話題にして会話してるんでしょうか。自分と仕事内容や考え方が近い人は、どんなことを意識しているんだろう。

確かめに行きましょう。本屋でもネットでも見つけられないことを。

それと同時に、シェアしに来てください。あなたが知識をシェアするのを求めている、あなたに似た人がいっぱい来ます。みんなの知識を少しづつ合わせて、全員がおみやげとして持ち帰れたら、それがユーザコミュニティが最高に機能している状態だと言えるんじゃないか、なんて思っています。

とくにPHPは、バージョンや世代の違いで、ユーザごとに理解のばらつきが特に激しい技術です。ひどい言語だと言われることもあります。逆に、普通に仕事で使うにはちょっと高度すぎて人材がいないと言われることもあります。何が本当かわかりません。 でもひとつだけ本当のことがあります。PHPという看板を掲げて、これが有意義な活動だと何かの信念をもってボランティアをやる人達が、日本中に何人もいるということ。

あと3回寝たら6/1です。関西PHPユーザ会のブースは会場ロビーにあります。待ってますー。

JetBrainsユーザーグループ in 大阪でPhpStormの発表をしてきました #jbugj

1/30(水) 第二回 JetBrainsユーザーグループ in 大阪 でPhpStormの発表をしてきました。

JetBRAINSという会社の、主に IntelliJ IDEA とそのファミリー製品についてのお話を聞かせてもらいました。僕は、個人的にとある事情でPhpStormを使う機会に恵まれて、しばらく前から機能のいいところをツイートしてたんですが、それを今回の主催者のaa7thさんに見られていたらしいという経緯で、簡単な1セッションを持たせていただきました。

PhpStormはIntelliJ IDEAのサブセットで、IDEの基本ツールに、Web共通の機能とPHP関連だけを残して、デフォルトメニュー構成をPHPに最適化した感じのものです。

PHP IDE :: JetBrains PhpStorm

英語しかないですが、さすが毎日デイタイムで働いているメンテナがいる商用製品で、技術トレンドの追従がものすごく早いです。PHPのバージョンが上がったとき、オープンソースのIDEだと新しい文法への対応遅くて、それが待てなくてエディタを使うという人もいると思いますが、PhpStormはPHP5.3/5.4への対応が、そんじょそこらのエディタのシンタックスハイライトより早かったんじゃないかとさえ思いました。なんと次の安定バージョンには、ComposerとPHPMessのサポートが入るそうです。

今回、IntelliJ IDEAの主要ターゲット言語がJavaということもあったり、なぜかVisualStudioのプラグインの製品のユーザもいたりして、軽量言語シリーズのほうは少数派でした。いつものような濃い目のPHPあるあるネタが通じない場でしたが、なんとか無事めくり芸発表を終えることができました。ありがとうございます。

発表内容については、主催者さんのブログ、nocono のこの記事にすべてまとまっています。

第二回 JetBrainsユーザーグループ in 大阪開催しました #jbugj - ブログ・アンケート記入でIntelliJライセンスプレゼント - nocono

それぞれのセッションで印象に残ったところを。

オープニング・セッション: 渾身の「乙女心をくすぐられちゃいます」まさかの空振りw

製品紹介: コマーシャルライセンスは会社の経費で落とせる、パーソナルライセンスは個人で決済しないといけない、という違いでしかなく、会社にパーソナルを持ち込んで仕事で使ってもいい。仕事に使ってはいけないのはアカデミックライセンス。これは明確な指針だと思いました。

IDEAのデモ: コード補完で自動インポートが動いたとき、MavenXMLが勝手に書き換わって、エディタで開いたらもうJUnitが入っていたのがびっくりでした。あとキーボードショートカットステッカー。

IDEAを使った経験談: IDEに何を期待するかということで、ソースのテンプレートやコード補完などの「書く速さ」に注目してしまいがちだけど、実は作業時間のほとんどはコードを読むことに使われる。「読む速さ」で考えたとき、ナビゲーションまわりの機能が充実しているから嬉しい。禿同ですね。書くだけでいいなら、チューニングしまくったエディタとコピペには勝てませんから。

WebStorm: ごめんなさい自分の発表の後でスライドの調整してて、実はあまり集中して聞けてなかったです。Sassで色の値をセットした変数まで、エディタにその色を出してくれるとこは見てました。IDEAの売りのひとつは、けっこう大真面目に「CSSの色」ですね。

なお、こちらがイベントの開催中もっともRTされた重要なツイートとなります。

なんか見るたびに上に上がってきてもう毎回も目に入りました。結局懇親会でやっぱり「イデア」言っちゃうし、もう「マクド」と同じイントネーションで関西弁では「いであ」でOKってことで落ち着きました。「いであいかへん?」→「ええで」

似た話で細かいですが、PHPStormではなくPhpStormです。"hp"は小文字。WordpressでもWord_Pressでもなく、WordPressですよというアレと同じ感じですみません。まったくPHP系の人はうるさいですね、言語仕様には関数名の大文字小文字の区別ないくせに。すみません。

前日〜当日の朝あたり、スライドを作るためにPhpStormを触っていると、出るわ出るわのPinoco(拙作PHPフレームワーク)の問題点。自分typoしすぎやで。というわけでこんなことに。

f:id:tanakahisateru:20130201201727p:plain

一番棒が長い右端のが、イベント当日のpushですね。いやもう、リリース後の落ち着きが嘘のように立ち上がっていますね。PhpStormで触るってだけでまじで捗りすぎだから、ほんともうオープンソースライセンス版は危ないですよ。

というのも、実は僕はその日が納期の案件を抱えてて、わりと前倒しで完了してたつもりだったのですが、発表の直前にひとつ急ぎの作業が発生していました。後でもいいGitHubの黒猫とお戯れていたせいですね。で、急ぎだったので、ちょうど開いてたオープンソースライセンス版のPhpStormを使って、こっそり仕事済ませてました。git commit しただけで、FTPとgit pushを一気にやってくれるんだもの。まじ仕事が早いんだもの。

というわけで、これでもし商用版のライセンスがもらえたら、ライセンス条件違反をチャラにできて嬉しいなぁ。というのはネタで、まあエディタで追い付かなくなる仕事が来る前に、普通にパーソナルライセンス買います。はい。

Pinocoでシンプルに正しく(&ぶっちゃけで)DIを理解する

Pinocoだって実はすごいんだぞ、Pimpleになんて負けないもん、というわけで、

PHPメンターズ -> Pimpleでシンプルに正しくDIを理解する

をPinocoで理解してみようというネタをやります。先にこれを見ておいてください。

あ、「Pinocoってなんやねん、あっちょんぶりけかよ」って思った人すみません。Pinocoは拙作のマイクロフレームワークです。いわゆるオレオレの一種ですが、オレオレにしてはかなりよくできたほうだと思います。RESTなAPIを作る他のと比べて、どっちかといえばWebサイトを作るほうが強い感じのヤツ。

https://github.com/tanakahisateru/pinoco

で、DIですよ。依存性注入ですよ。楽しんご的なアレじゃないですよ。オブジェクト指向ですよ。
Pinocoの第一印象はみんな「プレーンPHPっぽいね」で、それはそれで狙い通りなんだけど、いかんせん、そのせいで「この子、やればデキる子...」というのがわかってもらえないかわいそうな所があります。まあ作者がドキュメントを書かずにソース読んで一人で使ってるからダメなんですけどね。

以前、Pinocoで遅延評価がおいしいという話を、Pinoco0.4はクロージャですごくなる - なんたらノート 第二期 に書いています。Pinoco_Vars を PHP5.3 で使うと、遅延評価でいろいろやるとき超クールとかそんな話です。しかもこれがランタイム依存なしで、単独で使えるクラスだからこれだけ使ってもいいよ、とかそのあたりに言及しました。今回、これ前提でいくので、事前に読んでおくとわかりやすいですよ。

じゃ、やりましょう。

まず、PHPメンターズのお題を引用:

アプリケーションからニュースレターを送信する機能を実装しているとします。ニュースレターを送信するという責務を持つニュースレタークラスと、具体的にメールシステムを使ってメッセージの送信を行う責務を持つメール送信インフラクラスの2つに着目しましょう。

あくまで説明用のサンプルモデルなので、細かい設計の是非は論じません。ニュースレターオブジェクトの送信メソッドを呼び出すと、メール送信インフラを使ってニュースレターが送信されることとします。

というわけで、こっちでも全く同じことをやりましょう。メールを送るためのインフラになるクラスを作りますね。

おまけで、同じインターフェースの別のメーラー実装も書きました。

じゃあつぎ、こいつらをPimpleではなくPinocoで依存性として管理するにはどうするか。

だいたい似たようなもんですね。

Pinoco_VarsはDIコンテナのために設計されたわけではなく、汎用的なオブジェクトとして使うためにあります。なので、ただの代入はインスタンスへのプロパティアクセスになっちゃいます。遅延評価されるプロパティ専用のメソッドを使うあたりが、ちょっと見た目、DI専用に作られたPimpleより愚直な感じですが、まあ問題ない範囲ですよ。

さて、ここからがDIを理解しましょうという話になります。ここまでは、あくまで「DIコンテナの使い方」の話。

PHPメンターズ版と違って、まず先に答えをいうと、次のコードはDIがうまくできなくなるダメな設計です。

ここまでは、何も問題ないように思えます。コンテナで管理してるのは、まだあくまで、メール送信をするインフラのほうで、アプリケーション固有の機能は独自に new して使っています。NewsletterTransfer::send() の中で完結して動くようにベタに書いた、という段階ですね。これでも一応、単体テストは通るだろうからTDDしてもいいでしょう。

これだけのコードをカタカタと書いてる時間があれば、みなさんそろそろ、

「ニュースレター送信はメール送信インフラに依存してるじゃん」

という本質に気付くと思います。イエース、そのとおり。

「じゃあさ、NewsletterTransferのほうもDIコンテナに入れようぜ」... カタカタカタ

おやおやおや〜、慌ててそんなことしていいのかな〜?

「あ、そうだ、SendmailMailer を EchoMailer にすり替えたほうがテストしやすいじゃん、オレ頭いい〜。えーと、スタブって言うんだけっけ? こういうの。」... カタカタカタ

はい、ここ、「依存性」の「注入」じゃないですね。こういう編集作業をした時点で、依存性を手動でセットしているということになります。

単にDIコンテナと呼ばれるものを使うってことがDIなんじゃない。みたいなことを、「(ご)」←こんな感じのアイコンの偉い人が、PHPカンファレンスで言ってました。せっかく入れ替え差し替えでうまくできるオブジェクト指向なのに、その差し替えをロジック中に残したら意味ないですね。

で、このまま慌ててリファクタせずに作業を進めるとどうなるでしょうか?


「ステージングに入りまーす。本番モードようそろ〜」

_人人人人人人人人人人人人人人人人人_
> 突然の NewsletterTransfer 修正 <
 ̄^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^ ̄

「ごめんなさい、モジュールのコードをフリーズしたというのは嘘でした」

一同「エー」


はいこれが依存性を注入しなかった代償です。
おっと、さらに焦った文系PG上がりのプロマネからこんな案が...

...こんなとこ辞めてやるフラグへまた一歩ですね。あるあるすぎますね。いったどれだけの、そして何年の間、 ->testmailer が偽り続けるのだろうか...


ちゃんとDIしましょう。まず、依存関係に対して、正直に正しくクラスを設計します。

大きな問題の1つは、NewsletterTransferクラスをパッと見て、具体的にどのクラスに依存しているのか、関連を持っているのか分からなくなっていることです。

というわけで、関係をちゃんとすると、

$container が $mailer になり、assert が消えてタイプヒントだけになりました。

NewsletterTransfer が本当に依存しているものだけ、DIコンテナから取り出して、個々に与えましょう。コンテナまるごと与えて好きにしろというのは、間違いだったのです。こうすることで、どのメール送信インフラを使うかを切り替える権限は、オブジェクトの設計から、DIの設定の方に逃がすことができました。

こういう部分部分のまとまりの良さを、OOP用語で凝集度といいます。一般的に、凝集度が高いほうが、テストも保守もレビューもしやすいです。

こうしちゃうと、たしかに、外から依存性を注入しないといけないので、すぐには動かせないかもしれません。でも、個々の部品から全体へのアクセス権を奪うことで、各実装が好き勝手できないようになります。どのモジュールが何に依存するのかという関係が、いつの間にか誰にも知られずに変わってる、なんて、ちょっとしたホラーですよね。現場ではよくありますが。

それにほら、システムのコンテナを渡してしまうのは、みんな大嫌いな、あのグローバル変数と同じことですよね。いつでもなんでもグローバル変数という、あのプログラムセンスを許せないなら、それと同じ意味のことをやっちゃダメ。

なぜグローバル変数がダメなのかは、いつどこで書き換えられるかわからない、ということ以外に、仕様を変えたいのに誰が使っているかわからない、というのも問題でしょ。スコープが閉じてなくて広すぎ、っていう問題。


以上、Pinocoでちゃんと動いてますよという証明のために、リポジトリ作りました。

https://github.com/tanakahisateru/pinoco-as-di-sample

ComposerがあるとPinocoを入れるのに便利ですが、なくてもエラーメッセージでだいたいわかります。PHPUnit

phpunit --bootstrap bootstrap.php test/NewsletterTransferTest.php

してみるといいと思いますよ。phpunit.xml が面倒で書いていません、ごめんなさい。

FirefoxでUser-Agentを変えるとき必須の拡張

FirefoxにはUser-Agentを切り替える拡張がいっぱいありますね。本体の開発ツールに「レスポンシブビュー」なんてあるので、あとは拡張でUA切り替えを使えば、かなりいい線でスマートフォンの真似ができそうです。

でも...

けっこう多くのUA切り替え拡張で、サーバに送信するときのUAは変更できても、いざJavaScriptでnavigator.userAgentを取ると、まだFirefoxのまんまだったりします。

そこでこの拡張もいっしょに!

User-Agent JS Fixer

https://addons.mozilla.org/ja/firefox/addon/user-agent-js-fixer/

サーバに送信したUAの値を取り、レスポンスを受けたとき、それをそのまま、navigator.userAgentにセットしてくれます。で、JavaScriptから見てもUAがちゃんと切り替わってくれます。

サーバ側でUAを使ってレスポンスのビュー切り替える以外にも、最近では、サーバではレスポンシブなページで済ませ、JSを使ってデバイス判別をしたりする場合が増えてきました。それがなかなか、全ブラウザ共通でいけるので、キャッシュが効いて良い感じだったりするんですね。そういうとき、JSから見たUAが送信したものと違ってると困る。

というわけで、クロスデバイスなサイトを作る人には、この拡張必須だなと思いました。