CodeIgniterでパッケージシステムの一角を担当してた時の思い出

昔、あるパッケージシステムの公開Webアプリ部分をスクラッチで作ることになって、サーバーサイドはPHP・フレームワークはCodeIgniterという構成を選んだことがある。いろいろあって感慨深くなったので、そのときの思い出話をなんとなく書く。
誰かがそれなりに真面目に悩んで選んだ姿というのは、これから導入する人のヒントになるのかもしれない。

# そのシステムって何よ

嫌になって放り投げて辞めちゃった会社のシステムだから、バツが悪くて言えない。

俺が辞めた後、日経新聞に広告じゃない記事でシステム名が載った。CodeIgniterを日本国内で最も金に変えたシステムだよ、と冗談を言っても許されるレベルには達していると思う。

# なぜPHP、なぜCodeIgniter

CodeIgniter素晴らしいからとかではない。

## ISPのおまけのクズみたいなレンタルサーバーでもそこそこ動かせるから

このシステムの当時の販売ターゲットは、新興企業か、大手企業の新興部門だった。そして、市場は未成熟だったので総ターゲット数は100にも満たなかった（その代わりに、珍しいくらいのブルーオーシャンだった）。
狭量な技術的正義を振りかざして、いわゆる「ちゃんとした基準のWebサーバー」を運用できる顧客に絞らせるようなコードを書いたら、営業活動の幅をずいぶん狭めてしまう。

金を儲けるためには、上から下までなるべく多くの顧客をひとつのアーキテクチャで対応できるような、軽量で汎用的な基盤が必要だった。下は、mod_phpが使えないようなレンタルサーバーから、上は、管理に手間暇かかってるオンプレミスのWindows Server + IIS。

当時、そういうバカ理想みたいな点取り表を書いて、比較的マルが多かったのがPHPであり、CodeIgniterであったというだけだ。点取り表の項目はだいたいこんな感じだった。

* パッケージやサーバーに同梱して売っても（再頒布しても）問題無いライセンスであること
* mod_phpが使えなくてもそこそこ高速に動くこと
* OSに依存せず、マルチプラットフォームで動作すること
    * 具体的にはPECLへの依存が無く、割とピュアなPHPの世界だけで作られていること（PEARへの依存も無いとなお良い）
    * 具体的にはWindowsで動くこと
    * 具体的にはFreeBSDで動くこと
* 次のDBへのインターフェイスを持っていること
    * MySQL
    * Oracle
    * SQLServer
        * 選定当時、CodeIgniterには標準でmssqlドライバーしか無かったんだけど、参考にしてsqlsrvドライバーを自前で書けるだけの余地があった。
* 願わくば、Webアプリケーションフレームワークではあるが、phpコマンドでの実行も可能な汎用アプリケーションフレームワークでもあること

## 俺がいなくなった後でも単価安い人をかき集めて開発を継続できるから

中小企業だ。人材はごく限られている。
立ち上げ時の担当は俺ひとりだったので、俺さえわかれば何でも良かったんだけど、そこでニッチに走ってしまうとシステムがちょっとでも売れた時に開発チームがスケールできずに死ぬ。
なるべく低廉、なるべく一般的なものと考えると、サーバーサイドについては当時はPHPだったし、丁寧なユーザーガイドが付いていて制約も少ないCodeIgniterが適していた。

# どういうものを作ったか

ある程度リアルタイム性のあるデータを随時グラフに表示させて、閾値を超過したらメールを飛ばしたりするのが当時の主な機能だった。主要なテーブルのレコード数は当時3000万〜5000万くらいが性能目標値で、ささやかなものだけどそれまで自分が担当するシステムの中では最も大きかった。

プアな環境でこういうことをやらせて、万が一その導入先にめちゃくちゃアクセスがあったときにどうなるんだろう、ということを悩んだ。アクセス不能時間が30分あっただけで、顧客の数百万円が吹っ飛ぶ場合も考えられたから。

たとえば、グラフをImageMagickなどでPNG画像とかに書き出すとする。
この画像データはキャッシュできない。リアルタイムのデータだからだ。そういうキャッシュできないデータが、いろいろな切り口で何度も新規に作成される。
アクセスが最も集中するのは、こういう比較的コストの高い部分ということになる。
ISPのおまけじゃ無理な処理方式だね。

いろいろ考えて、サーバーサイドではグラフ画像を作らないことにした。代わりにクライアントサイドの`<canvas>`に表示させる。クライアントに負荷を分散させる格好だ。こうすれば、サーバーサイドはただJSONを出力すれば良いからずいぶんマシになる。
今なら普通の方式なんだけど、当時はようやくHTML5が普及してきた頃なので（IEは9がリリースされた頃）、いくら俺一人で決めて良いと言っても少々の思い切りが必要だった。企業ユースだから、IEは6でまだまだ当然な頃。`<canvas>`未対応ブラウザーでは[FlashCanvas](http://flashcanvas.net/)を併用してしのいだ。

諸々の機能は、既定ではHTMLのviewを持っているけど、コントローラーメソッドの最終引数にcsvとかpdfとか欲しい形式のサフィックスを与えれば、その形式のviewが得られるように作った。CodeIgniterのviewはCakePHPみたいにlayoutありきじゃない素朴な作りだったので、こういう様々な形式での出力に対応するのが簡単な発想でできた。

セキュリティーは、PCIDSS v1を参考にした実装をDXAuthに加えることでそれらしくしていた。

# そのシステムは成功したのか

それをほんとうに見定められる前に、会社を辞めた。
けど、CodeIgniterの利用事例ですよ、と言ってまったく恥ずかしくないだけの導入実績がついたのは間違いないので、それをもって成功と言っても良いのかもしれない。

ソフトウェア的に成功したかと言えば、そんなわけはない。
ここまで書いたことを、PHP始めて1〜2か月の小僧が社内外で相談相手も作れず泣きながらやっていたわけだ。まったく頭がおかしい。今見れば、設計は破綻しているし（MVCを理解していない、典型的なfat controllerのままリリースしてしまって、しかも当時はそれで良いと思っていた）、PHPの言語仕様やHTTPのプロトコル仕様を理解していないからおまじないが多いし、だいたいテストコードも付いていない。

ただ、悩んだからにはそれなりの真理も残っており、それはかけがえのないものなのかもしれない。

# 4年経って再会した

このシステムを最初に導入してくれた最も寛大な企業から、4年後に誘われて入社することになった。まったく人生は読めない。
そこで、導入後4年経ったかつての担当システムの姿を見ることになる。なかなか無い経験だ、かつての渾身の作品を自らの手で全力で貶すことになるというのは。

性能上限の想定値を2〜3倍上回るレコードが登録されていた。
がんばってインデックス設計したつもりのテーブルでは、肝心のところで変なクエリー（自分の書いたクエリー）がインデックスを利用していなくて全然パフォーマンスが出なくなっていた。
長時間のテーブルロックで、Webアクセスが致命的にブロックされていた。
そのテーブルロックは、信頼できると思っていたサーバー業者の無自覚なジョブ設計ミスによるものだった。

それでも、だいたい動いていた。
ちょっと嬉しかったけど、このシステムにはもう幕を下ろさなくてはならない。

何度も直接修正して改善してしまいたくなったけど、今の立場でそれは許されない。
今はユーザーなのだ。

# 今の俺とCodeIgniter

3を使って、ヒアドキュメントでSQLをまるっと書くような意識の低いModelを書いている。
こういうことやっても許容されるのがCodeIgniterの良いところだと思っている。上から下まで、だ。