継続的Webサービス改善ガイド 第2章
継続的Webサービス改善ガイド
第2章 開発環境の改善~技術的負債の返済と,レガシーコードの仕様化テスト
http://gihyo.jp/dev/feature/01/webservice-guide/0002
【概要】
webサービスの成長とともに大きくなる「技術的負債」を返済するために、
筆者が所属する会社で取り組んでいる方法について紹介されている。
以下、1ページ目、および2ページ目前半の内容要約を記載する。
■技術的負債
アプリケーション層とハードウェア層、それぞれに存在するが、
ここではアプリケーション層の技術的負債を対象とする。
具体的には、
・障害対応のためにテストを書かずにその場しのぎで入れたコード
・「TODO: あとで直す」といったコメント付きのコード
・とりあえず動くことを目的とした適当な設計のコード
・コピペコード
・脆弱性が存在するライブラリを使用しているコード
など。
もちろん、障害発生時は「奇麗なコードを時間をかけて書く」よりも
「汚くてもとりあえず動くコード」を書くことが求められるが、
その「汚いコード」を放っておくと、
・システムの複雑性が増すことによるリリースサイクルの長期化
・システム障害の発生や長期化
などの問題に繋がってしまう。
そしてこの「汚いコード」は、エラーで処理が止まるわけではないので、
改善に着手されにくい。
■継続的な現場改善
技術的負債の蓄積 ▶︎ サービスの負債
では、技術的負債を抑えるためには何が出来るか?
・毎日の作業の一環に組み込む
毎朝30分間、技術的負債の返済を行うための時間を確保する。
ここでテストが無いコードにテストを書いたり、リファクタリングを行う。
・CIの導入
Jenkins, Travis CI, Coveralls, Gemnasiumなどのツール、サービスを用いて、
自動的にテストの実行、失敗の検知といった作業を自動化する。
・コードレビュー
チーム内コミュニケーションを促し、結果としてコードの品質向上や
不具合の検出が期待できる。
全てのコードは、書いた本人以外によるコードレビューを通すべき。
GitHub(無償でもEnterpriseでも)のpull requestを用いたレビューにて、
書いた本人が気づかない点に気づけるしくみを作っている。
■開発環境の改善
技術的負債の返済には、環境に問題がある場合もある。
例えば、
・本番環境で動いているコードの中に、バージョン管理されていないものがある
・テスト環境、ステージング環境が存在しない
・開発を行う環境が物理サーバ、仮想サーバ上にしか存在せず、
開発者個人のマシンで確認できない
といった場合は、技術的負債を返すためのコード変更が行いにくいと言える。
バージョン管理
サービスを運用していると、
・サーバ上でコードや設定ファイルを直接編集して対応
・メンテナンススクリプトをサーバ上で作成して実行
といったことが発生する。
これらもすべてバージョン管理システムに保存する必要がある。
Railsのようにデータベースのマイグレーションスクリプトがフレームワークに
内包されていれば、意識せずに上記バージョン管理が行われている。
そうでない場合は、少なくともデータベースに発行するSQLは
すべてバージョン管理しておくべき。
開発環境の仮想化
サーバ設定作業の自動化 ▶︎ Puppet, Chef
本番環境を気軽・高速に開発環境として再現できることは重要。
■レガシーコードの継続的な改善
『レガシーコード改善ガイド』による言葉の定義
テストがないコードはレガシーコード
1時間前に書いたコードもレガシーコード?
▶︎ テストが無いとリファクタリングできないので遅かれ早かれそうなる。
レガシーコードを改善するためには?
▶︎ 仕様化テストがオススメ
既にあるプロダクトコードの挙動が仕様であるとして書くテスト。
リリース済みのサービスは、仕様の変更は慎重に行う必要がある。
【感想】
開発の現場では「動いているコードは触るな」という言葉が度々叫ばれる。
例えそれが汚いコードであっても、デグレを恐れて改修しないことは多々ある。
一方で、TDD実践者として有名な@t_wada氏が言うように、
「動いているコードだからと言って触らなければ、そのコードは死んでしまう」
というのは、まさにこの技術的負債のことだろう。
つまり、改修する/しないの決定は状況に応じて判断する必要がある。
直近を平和に収めるためには「動いているコードは触らない」
例えば「3ヶ月後にサービスの終了が決まっている」といった場合であれば、
敢えて危険を冒す必要はないだろう。
未来の安寧を求めるならば「積極的リファクタリング」
企業の基幹システムで長期間の使用が予測される場合であれば、
技術的負債を抱えたまま運用をすることは考えたくない。
リファクタリングしやすい環境づくりは急務と言える。
もちろんこれらの作業には多大な工数がかかり、
顧客から見たらコストの増大に他ならないが、
最終的なコストを考えると事前に手をうっておいた方が良いことも多いだろう。
※個人的には最終的なコストが例え安く収まらないとしても、
※必要経費としてこれらの導入は行うべきだと考える。
最後に、テストコードについて少しだけ言及する。
テストコードは、ただ書けば良いというものではないと思っている。
現場で「使えないテストコード」を見かける事が多いが、
これらは二重メンテになるため邪魔な存在でしかないからだ。
使えないテストコード
・メンテされていなくて動かない
・データ依存で、データが少し変わると動かない
・クラスを呼ぶだけ(1パターンしかない)
※もちろん呼ぶだけでテスト出来るクラスもあるのでそれは例外とする
使えるテストコード
・可読性が高くメンテしやすい
・再利用性が高い(データが変わっても動く)
・パターンが網羅されている
かく言う自分も、気づけば使えないテストコードを書いていることがある。
実践はなかなか難しい。