hrysd心を折られる
チンカスプログラマーことhrysdがバイトで来てくれることになったので一緒に大門に出社。
初出社前に既にバグを一個潰してコミットしているという荒業を見せたhrysdだが、3000行を超えるcontrollerに早くも心を折られる。
俺「actionのメソッドが5行を超えたら危険印、なんていうrailsのぬるま湯に使ってたんだよ!これがサバンナだ。」
Github Organization契約
出社後早速、社長にGithub Organization Bronzeプランを契約してもらう。技術的なことはわからないというが、リスクを背負って立てなおそうという気持ちが伝わって来ました。
9月30日の直近の締め切りに間に合わないのでsvn + redmineからの移行は10月にお預けだ。
svnがよくわかってない
まずはsvnでもトップにぶち撒けられてるというのは辛いのでtrunkディレクトリを作ってそこにsvn mv。しかし、svn updateの使い方がわかってない外部パートナー様からヘルプの問い合わせ。svn updateしてからsvn ciすればいいだけだと思うんだが・・・。
新たな外部パートナー様を求めて打ち合わせ2件
社長が検索で見つけた2社様と打ち合わせ。技術的に良い会社かどうか判断して欲しいとのこと。githubアカウントの提出をお願いしたら(担当者がプライベートで作ってるコードでも構わないので)2社とも無いとのことで会う前からちょっとガックシ。
1社様はunittestを書いたことがあるということで無くは無いといった感じ。(パートナー様を選ぶ最低限のポイントとしてはgitが使えること、自動テストが書けることの2点と伝えてあります。できればプライベートでコード書いてる人が良い)もう一社様はテストが書ける人を探してると言ったら、エクセルのテスト仕様書を見せられた。phpunitやselenium, jenkinsなんて名前も聞いたこと無い様子だったのでちょっと一緒にやってくのは厳しそうでした。(社長には良い感じの人に見えたと言っていたのが印象的でした。やはりプログラマーが見るべきだと改めて感じた。)
レガシー改善の王道、テストの整備
ステージング環境をさくらVPSで用意。jenkinsでのsimpletest, phpunit + selenium rcでのCI、capistranoでの継続的デリバリーの環境が整った。後はテストを増やすだけだ。
レガシー改善の方針
何はなくとも自動テストだ。テストが無いと、バグもデグレも治った保証が無いし、怖くてリファクタリングできない。
最低限のテストを完備し、その庇護の元、デグレに怯えないバグ修正やリファクタリングを行なっていく。それにはバグを再現するためのテストデータの整備が欠かせない。要はmigrationの仕組みが無いと、多くのバグがそのタイミングでたまたま発生しただけで再現しないため放置されるのだ。(CakePHP1.3でのmigration pluginの導入はまだうまく行ってない)
CakePHP1.3からCakePHP2.xへの移行はもうファイル名やフォルダの命名規則、コア関数などが変わりすぎていてほぼ無理だと判断した。
かと言って中長期的な施策ばかりで直近のデッドラインを無視するわけには行かないので、同時にhrysdにお願いしてヤバイ順に泥臭いバグ修正を並行して行なってもらった。午後は僕も参戦した。
バグと格闘してわかってきたマズイ部分
CakePHPのユーザー認証コンポーネントを使ってない。before_filter的な機能を使ってないので全Controllerの全メソッドの先頭にユーザー認証処理が書いてある。
ユーザーの権限管理にCakePHPのACLを使っていない独自実装の為に膨大な行数が直書き+コピペされている。
検索条件、ページ間のデータ受け渡し(本来POSTされるべきもの)、様々な構造化されたデータのやり取りは全てSessionを通して行われているので各controller、method間の入出力が非常に分かり辛い。完全にGUIアプリのようなステートフルな実装になっているので単体でのテストが非常にやり辛い。バグの再現も難しい。
foreachで処理できるところを(ループをインライン展開しているのか?)全て手で書下しているのでただ代入するだけのような同じ処理が延々と何十行と続く。
$pg, $md, $mk, $sw, $sidなど何を表しているのかわからない変数が大量にあり、推理に時間がかかる。($mdがmodeの略だとわかった時にはガッツポーズをした)
validationはサーバーサイド(model)には一切無く、javascriptだけで行われている。これではデータの整合性を保つのは難しい。
技術的負債が増える理由1
バグを減らす一番の方法はコードの行数を減らすことだ。コード行数を減らすというと、共通処理を関数にくくり出すなどをまずイメージしがちだが、真っ先に考えるべきは、既存のライブラリやフレームワークが備える機能をなるべく使うということだ。
十分テストされたライブラリはその場で作ったスクラッチコードより品質が高い。多くの目に触れているものは不具合の解消も進んでいるだろう。
作ろうとしている機能が、既にあるライブラリで解決可能かどうか、フレームワーク標準の機能にそういったものが無いか、吟味するのはとても重要だ。(フィットするものが無ければその時初めて作ればいい)
そういった調査をせず、闇雲にオレオレコードを量産するとバグ発生率が増加する。
技術的負債が増える理由2
技術的負債が非エンジニアにとって見えづらいのは、組み合わせ爆発の恐ろしさを理解していないことにあると感じました。
日常生活では仕事が増えるといっても精々2倍になったとか3倍になったで大騒ぎ。ソフトウェアの分野では浅慮によって手間が2乗、3乗という風にグラフにしたら垂直に上昇していくようなことが簡単に起きる。
階乗とは違うけどわかり易い例でいうと、何かのmodelに対してcommentを付けたいという要求があったとする、railsノリで言えば、acts_as_commentableみたいな作りにしてcommentテーブルは共通、commentablesみたいなテーブルを作って、コメントを付けたい対象が増えても組み合わせは1×Nのまま爆発的な増大はしない。
ところが、ベタに作ると、post_comments、page_comments、picture_commentsといった風にドンドン増えていく。
色んなモノにtagを付けたいという要求があったらまたpost_tags、page_tags、picture_tagsとその分だけテーブルが増える。
comment, tagの部分もcategory, review, ratingと増えていくとN×Mで爆発的にテーブルは増えていく。
そういったちゃんと抽象化せず、場当たり的実装を重ねた結果、DB定義書のエクセルシート数が3桁に迫り、そんなドキュメントを人間の手でメンテナンスするのは事実上不可能になり破綻する。破綻したドキュメントは軽んじられ、作成者は疲労し、メンバー全員のモチベーションは地に落ちる。
いくら気合で頑張るといっても1日は定時8時間の3倍の24時間しかないのだ。物理的に3倍以上の作業量をこなすことは出来ない。組み合わせ爆発で3倍なんて簡単に超えてしまう。
いかに組み合わせ爆発を起こさないような作りにするか。それが肝心なのだ。
非エンジニアの方(経営者など)はこの動画をみて是非とも組み合わせ爆発の恐ろしさを感じて欲しい。
レガシー改善仲間募集
僕が参加しているプロジェクトでは短期でも一緒にレガシー改善に正面から取り組んでくださるプログラマーさんを募集しています。フリーランス・開発会社様、アルバイト、どんな形でも結構ですのでご連絡いただけるとありがたいです。詳細はこちら
phpプログラマーの募集 - komagata
関連:レガシーPHP改善日記シリーズ