継続的Webサービス改善ガイド

第2章 開発環境の改善~技術的負債の返済と,レガシーコードの仕様化テスト

この記事を読むのに必要な時間:およそ 6.5 分

技術的負債と開発環境の改善

本章では,サービスの成長とともに大きくなる「技術的負債」に着目し,筆者が勤務するpaperboy&co.(以下,ペパボ)で取り組んでいる開発環境の技術的負債を返済していく具体的な方法について紹介します。

技術的負債とは

技術的負債は,英語でTechnical Deptと呼ばれます。技術的負債の「概念」が最初に登場したのはWikiの開発者として知られるWard Cunninghamが1992年に発表したThe WyCash Portfolio Management Systemという報文の中です。そこから年を経ること17年後の2009年に,アジャイルソフトウェア開発宣言などで知られるMartin Fowlerによって技術的負債という名前が付けられました。

Webサービス開発での技術的負債の例

技術的負債は,サービスを構成するソースコードそのものであるアプリケーション層と,それらのアプリケーションを動かしているハードウェア層それぞれに存在します。本章では前者のアプリケーション層の技術的負債を対象とします。ハードウェア層の技術的負債の例や改善方法については,第4章(2/20公開)を参照してください。

さて,アプリケーション層における技術的負債にはどのようなものがあるでしょうか。筆者が思い浮かべるものを以下に列挙します。

  • 障害対応のためにテストを書かずにその場しのぎで入れたコード
  • 「TODO: あとで直す」というコメント付きのコード
  • とりあえず動けばいいと言われたので設計などを推敲せずに書いたコード
  • 検索して出てきたコード断片をコピー&ペーストしたコード
  • 脆弱性が公開されているバージョンのライブラリを使用しているコード

上記以外にも,エンジニアとして日々コードを書いたり読んだりしていると,⁠このコードはなんとなく良くないような気がする……」という直感に遭遇することがあるはずです。まさにそのときこそが技術的負債を生んでいる瞬間なのです。

技術的負債はサービスの負債

筆者はこの「技術的負債」という表現が実に絶妙なものであると考えています。たとえば障害が発生した瞬間では「きれいだけど作るのに時間がかかるコード」よりも「汚いけどすぐ動くコード」のほうが機会損失の度合いが低いと言えます。しかし,不具合改修後の3年,5年というスパンで考えた場合,後者のコードは「汚い」という可読性の負債だけではなく,次のような利子を積み上げてきます。

  • どう見ても必要ない処理のように見えるが,消してよいのかわからない
  • どう見ても非効率なやり方をしているが,直してよいのかわからない
  • 担当者が変わったときにその都度,何のために必要だったのか聞かなければわからない

しかし,負債のすべてが悪ではないことも理解する必要があります。たとえば障害発生時にはちゃんと網羅的なテストを書いてからリリースすることよりも,障害の収束を優先することが多いはずです。これは今現在において,未来への負債を生じさせることよりも障害による機会損失のほうが大きいという判断が働くためです。

さて,このように技術的負債の利子がどんどんたまり続けると,どのようなことが起きるのでしょうか? 技術的負債は生み出された瞬間はプログラマのレベルの問題であることが多いですが,利子がたまり続けることでサービスの負債となります。

技術的負債が爆発するとき

技術的負債は動いているコードの裏側にひっそりとたまり続けるものです。この動いているコードというのが問題を見つけにくくしていると筆者は考えます。動かないコードであれば動かすためのモチベーションは自然と沸いてきますが,動いているコードについてはなかなか手を付けようというモチベーションは沸きません。

そのような状況で技術的負債がたまり続けるとどのような状況を引き起こしてしまうのでしょうか。筆者が経験したものをいくつか紹介します。

リリースサイクルの長期化

技術的負債が蓄積すると,システムの複雑性が増します。システムの複雑性が増すと,機能を追加しようと思ってもコードのどこを変更してよいかわかりにくくなり,コードを変更した際に自分が意図しなかった振る舞いまでをも変更させてしまう,つまり不具合を生み出してしまうということがしばしば発生します。

これは結果として,リリースまでにかかる時間を増やしてしまうことを意味します。さらに不具合を迅速に修正するために推敲されていない設計を採用してしまいがちになり,さらなる技術的負債を増やしてしまうという,悪循環に陥ります。

システム障害の発生や長期化

リリースサイクルが長期化しても,担当者を増やしたり,リリース期間を延長することで何とか毎日を過ごすことは可能です。しかし技術的負債がたまり続けると,前述した不具合を,開発時点ではなくユーザに対してリリースしたあとに発生させてしまったり,セキュリティ上の致命的な欠陥などを引き起こしてしまうことがあります。

技術的負債は障害発生時にも影響を及ぼします。リリースサイクルの長期化と同じ理由により,障害の根本的な原因を見つけようにもシステムが複雑化してしまっているために時間がかかってしまいます。障害発生中はサービスから得られる利益も停止してしまうことを考えると,障害復旧の時間が増えてしまうことは望ましい状況ではありません。

継続的な現場改善

技術的負債がたまり続けることで,サービスにとって良くない影響を及ぼすことがわかりました。では,ビジネス要求を解決し,社会状況の変化に対応しながら技術的負債を減らしていくために,私たちは何ができるのでしょうか?

技術的負債返済の習慣化としくみ作り

技術的負債を返すために最も手っ取り早い手段は技術的負債の返済を開発プロセス,すなわち毎日の作業に組み入れてしまうことです。たとえば毎朝30分や,毎週金曜の午後は技術的負債の返済を行う時間として確保し,テストがないコードにテストを書いたり,テストがあるコードをリファクタリングするのがよいでしょう。

改善活動を毎日の作業に組み入れると同時に,技術的負債を生み出したり,技術的負債が残ることをできるだけ見逃さないしくみ(プロセス)を作ることも必要です。明日からでも始めることができ,すぐに効果を出すことができる筆者お勧めのしくみを2つ紹介します。

CIの導入

負債を放置しないしくみとして最も簡単に導入できるのがCIContinuous Integration継続的インテグレーション)です。CIは継続的に何らかの処理を実行するプロセスのことを指します。CIで実行する代表的なものとして,テストの実行と,その失敗の検知があります。自分たちでサーバを準備できるのであればJenkinsを用いてCI環境を構築したり,外部のサービスを利用可能な場合はTravis CIを用いることで簡単にCI環境を作ることができます。

近年ではテストの実行だけではなく,テストのカバレッジを継続的に記録するCoverallsや,使用しているライブラリの脆弱性を検知するGemnasiumなどの外部サービスも登場しているので,積極的に導入するとよいでしょう。これらのツールやサービスを活用することで,開発メンバーが意識しなくても負債がたまった瞬間を検知できるようになります。

コードレビュー

CIの導入はツールを活用することによって継続的な改善を支援するしくみでした。それに対してコードレビューは,チーム内のコミュニーケーションを促し,結果としてコードの品質向上や不具合の検出が期待できるしくみです。筆者はすべてのコードを書いた本人以外がコードレビューすべきと考えています。ペパボではすべての新しいコードをGitHubまたはGitHub Enterpriseのpull requestを用いたレビューを行うことで,本人には気づかない設計判断や不具合に気がつけるしくみを作っています。

開発環境の改善

技術的負債を返済しようにも手を出しにくいときがあります,このようなときは多くの場合,開発環境に負債が蓄積しています。たとえば次のような場合,技術的負債の返済は困難な状況にあると考えてよいでしょう。

  • 本番環境で動いているコードの中に,バージョン管理されていないものがある
  • テスト環境,ステージング環境が存在しない
  • 開発を行う環境が物理サーバ,仮想サーバ上にしか存在せず,開発者個人のマシンで確認できない

上記のような場合,技術的負債を返すために必要なコードの変更が極めて行いにくい状況にあります。その結果,技術的負債がたまり続け,さらにコードの変更がしにくくなるという悪循環を生み出します。

このような状況はどこかの時点で返済しようと思っても,いっぺんに返すことは極めて困難です。筆者の経験上,上記の状況を改善するためにはエンジニア数人で作業して数ヵ月から半年かかります。

バージョン管理

開発環境を語るうえでなくてはならないのがバージョン管理です。サービスを運用していると,サーバ上でコードや設定ファイルを直接編集して対応したり,メンテナンススクリプトをサーバ上で作成して実行したりするようなことが発生しがちです。そのようなスクリプトもすべてバージョン管理システムに保存することで,なぜこのような変更を加えたのか,将来再利用するときに加えるべき変更点を議論することが可能になります。

Railsのようにデータベースのマイグレーションスクリプトがフレームワークに内包されている場合は,意識せずに上記のバージョン管理が行われている場合が多いです。そうではないフレームワークを用いている場合は,データベースに対して発行するSQLはすべてバージョン管理の対象とすべきでしょう。

開発環境の仮想化

近年では,開発環境の仮想化がちょっとしたブームになっています。たとえばPuppetやChefを用いてサーバの設定作業(プロビジョニング)を自動化し,VagrantのようなVMVirtual Machineを簡単に作成するツールなどを組み合わせて使うことで,アプリケーションやサービスを開発するうえで必要とされるサーバ群を気軽かつ高速に構築できます注1)⁠ペパボではテクニカルマネージャの宮下剛輔が開発したMaglicaを用いて誰でも仮想サーバを構築することができるため,本番環境と同等の環境をすぐに構築しテストすることが可能となっています。

技術的負債を返済するうえで,この本番環境を気軽かつ高速に開発環境として再現できることが重要であると筆者は考えています。本番環境の変更は気軽に行えるものではありません。そのため,開発者が何かしら実験的なコードを入れたりすることで内部を良くしようと思っても,後回しになりがちです。このときに開発環境を気軽に用意できれば,改善活動をやりやすくなります。ペパボでは改善活動の一歩目として,本番環境や物理サーバでしか動かないようなサービスを積極的に仮想化しています。

注1)
Chef,Vagrantについて詳しくは,WEB+DB PRESS Vol.75の連載「Emerging Web Technology研究室」⁠p.108)をご覧ください。

著者プロフィール

柴田博志(しばたひろし)

(株)paperboy&co.

URL:http://www.hsbt.org/diary
Twitter:@hsbt
Github:hsbt

コメント

コメントの記入