読者です 読者をやめる 読者になる 読者になる

CodeIgniterが急激によくなってきた

PHP

CodeIgniterを評価しました。

申し訳ないけど、このブログエントリの著者が学生さんだと知りつつ、きつく批判します。
CodeIgniterの嫌な部分 | Oddwit
某巨大掲示板でも、このブログと同じような議論がありました。
これを批判することが、CodeIgniterの良さを上手く説明する方法であると同時に、誤解を解く方法だったのです。けして悪意はありません。逆に、注目すべき所を教えてもらえて感謝しています。

このブログエントリがGoogleの最初ページに登場した結果、
KohanaフレームワークでPHPTALを利用してみた - せつないぶろぐ
のように影響される人がいました。

同じように考える人は数多くいるようですが、彼らの存在は特定できないので、特定できる人に…。いや、ほんと申し訳ない、でも、言わないと。むしろ、このページを検索結果の最初に表示してしまうGoogleのレーティングに罪があるよ、これは。

ParserがSmartyじゃない

ここでParserと呼んでいるのは、おそらくテンプレート言語処理系のことだと思う。
開発プロセスだ何だと机上の空論を語らない現実主義者たちは、Smartyを指して、「<?=...?>を{...}に置き換えるだけの効果しかないもの」だと言う。テンプレートエンジンのマクロ言語でテンプレートエンジンを実装するなどという馬鹿げたものが好まれる理由が、私にもさっぱり理解できない。(普通はSmartyは嫌われ者で、でも、特定の条件下ではなくてはならないもの、だと思うんだけど。)
開発中なら、最新デスクトップPCのCPUパワーを自分ひとりが独占しているけど、リリース後は、100や1000じゃ済まない数のユーザが、他に複数のサービスを同時に提供しているサーバ(長く業務を続けている顧客の環境ほど、何世代か旧いUnixであることが多い)に集まるというのに。
なので、PHPというテンプレートエンジンをデフォルトの表示系とするのは、全く正しい。コストに犠牲を払ってでもSmartyが必要な場合には、たぶんそのように拡張することは可能。でも、その逆は多分不可能。
コードの字面が自分好みになるからという理由だけで、無条件にCPUを馬鹿食いしていい道理はない。コードの字面で選んでいいなら、そもそもPHP自体を避ける。アプリケーションサーバのメモリに常駐できるテンプレートエンジンで、より高尚なビュー技術を使うのが正しい。PHPを最も上手く使う方法は、「汚かろうと何だろうと、とにかく正しく動けばいい」という妥協を積極的に受け入れることだと思う。

セッションをクッキーに直書きする

PHPのセッションは特定の条件下でしか使えない。間違った状況で選択すると、致命的な問題を引き起こす可能性がある。ところで、PHPがよく使われる案件(公開されたWebサイトや中小企業の業務系Web窓口)では、むしろPHPの(J2EE仕様のサブセットな)セッションが向いていない場合の方が多い。
いっぽう、クライアントサイドセッションはおおむね万能で、とくに不特定多数を相手にするとき、最良の選択となる。セッションデータ肥大化でサーバがクラッシュするよりは、小数のユーザに不具合発生するほうがまだマシだ。PHPより多くのセッション情報を保持しがちなJavaでは、セッションの肥大化で業務システムのクラッシュが起こっている。
これもまた、テンプレートエンジンと同様だ。クッキーを使えばセッションを実装できるが、セッションが最初から強制されていると逃げ道がない。ドメイン特化なサーバサイドセッションの実現は簡単だ。サーバ側のデータベースにユーザ毎の作業用レコードを作り、そのIDをクッキー経由でユーザに提供すればいい。どうしても必要なものにだけ、それをやればいい。
ちなみに、デフォルト設定はクッキー保存だけど、設定を変えれば、SQLでセッションインスタンスを保存することもできる。ローカルファイルに保持するよりはだいぶマシ。
セッションで簡単に自爆できるプログラムが安易に作られてしまわないよう、デフォルトが安全側になっていることは、むしろ好印象。Apache MyFacesもデフォルトでクライアントサイドセッション。Railsも2.0からファイルシステムにセッションを持たないらしい。
そういえば、某巨大掲示板で、「CIはクッキーダメなブラウザで使えないから嫌、セッションが欲しい」という発言を見かけた。はい、これ笑えない人は、絶対に仕事でWebアプリケーション書かないように。

セッションを読み書きするメソッド名が長い

CIのセッションは、HTTP越しの持続的な対話全般を表現したいようだ。PHPのような、特定機能にたまたまアサインした名前ではない。なので、セッションオブジェクトには複数の責務があり、複数の責務がひとつのクッキーというメカニズムを共有する。なので、ユーザデータの取得と格納と、他のクッキーを使った機能とを明示的に区別できることは有難い。フレームワークを拡張してユーザデータではない属性をセッションに加えるさい、アプリケーション実装との名前衝突を心配しなくて済む。

バリデーションがダサい

まずライブラリのメソッドの中身に「$_POST」がハードコーディングされているため、任意の変数をバリデートできない。

バリデーションは「何らかの境界で、正体不明な外部のデータを、内部で使える形式(型)に変換する試み」のこと。けっこう間違っている人が多いけど、主題は「変換」であって、「検査」ではない。検査はベリフィケーションと言う。さて、Webで正体不明なデータとは何か、そいつはポストデータのことだ。自分で作った値や、すでに保持しているデータは正体がわかっているので、それらを比較照合しても、(Webの入出力境界においては)バリデーションとは呼ばない。単に、データ不整合のエラーと解釈するべき。
たしかに、ポストデータのバリデータに含まれるチェックルーチンを再利用したい時はあるが、Webフレームワークのバリデータが持つ責務は、外部からの変数を安全に持ち込むことだ。それは、自分が必要としている検査と同じだろうか?自分のアプリケーションのデータには自分で責任を持つのが、適切な責務分担だと思う。

そして、エラーメッセージを変数で取得するとデフォルトで<p>〜</p>に囲まれて来るという驚きのダサさを発揮してくれる。

ポストデータのバリデーションエラー文字列を任意の文字列でラップできるのは有難い。

<?php if (array_key_exists('hoge', $errors)) { ?>
<span class="error"><?=$errors['hoge'] ?></span>
<?php } ?>

このパターンを

<?=$this->validation->hoge_error ?>

こう書ける。もしラップしたくなければ、空文字列でラップすればいい。

以上。ここで切っておきます。大事なことは言いました。

CIを喜んでいる人はおそらく、あらゆるWeb技術を使い分けることができるスキルを持った、本当の現実主義者だと思う。彼らは、いくら高度とされる技術を持っていようとも、目の前の現実問題を解決するのに妥当な技術を選ぶ。彼らがあえてPHPを選ぶとき、多くの場合、お仕着せの豪華なフレームワークを避ける。なぜって、RoRのようにPHPを書くぐらいなら、最初からRoRを使えばいいんだから。ところでCIはというと、「あらゆるドメイン特化フレームワークが共通して実装しそうなもの、あるいは、実装を忘れそうなもの」をある程度まとめて提供してくれる。余計なものは避けられる。足りないものは作ればいい。生のPHPには足りないものだらけで、たしかにゼロから作ればいいんだけど、もし自分が作るものと同じものがすでに存在し、そのコードの方が枯れているなら、使わせてもらって楽しようって発想。これが職業プログラマの視点。

CIに限らず、他人の方法に自分が違和感を覚えるとき、単に「おかしい」とだけ考えて切り捨てていると真実を見逃す。おかしな仕様だと思えば思うほど、「なぜそうなったか」を考えることは重要。基本的に、批判される側の多くは、批判する側より優秀だということを忘れると恥をかく。おかしな仕様の原因のほとんどは、

  • 作者より自分が二段階以上遅れていて、目的が理解できないため
  • 組織という集合知(えてして個人より知能が劣る)の愚かさが度を越したため

このどちらかだ。