どうも、えいやです。
今回もお鉢が、というかぬいぐるみが回ってきたので、ブログを書きます。
今回は、技術的負債の計測と返済についてです。こんな方向で適当にやってるというだけの話とポエムなので、真面目に話を聞きたい人は、品質管理の専門家に相談してください。
なお、今回もJavaで開発を行っている想定での話です。あと、最後はやっぱり暗い気持ちで締めることになるので、誰か手伝いに来てください。
SonarQubeの紹介
僕がメインでメンテナンスしているサービスでは、CIに組み込んだSonarQubeを用いて静的解析ツールや動的テスト結果の解析ツールを実行し、CodeSmellなどのメトリクスを集計、可視化しています。
技術的負債とは、それらのメトリクスの個々の理由うちコード修正が必要なものについて、修正に要する日数を算定し、コストとして積み上げたものです。
SonarQubeについての詳しい内容は、公式のサイトを見てください。多様なプログラミング言語について指標を出せますが、解析ツールが洗練されているJavaについての指標がもっともきちんと提示できるようです。
Astamuse.comの場合
弊社の主要なサービスでは、Astamuse.com、AstaID.comについて取得しています。また、それらを構成するライブラリについても、自製のものについては取得しています。
例えば、コードベースが大きいAstamuse.comでは、Java言語で実装されている部分について、現在のメトリクスは以下の数値となっています。
Lines of Code Bugs Vulnerabilities Code Smells Coverage Duplications main-java 42k 49 20 1.4k 30.4% 4.9%
これらの指標に基いて算出された技術的負債は62日となっています。これが多いのか少ないのかは、プロジェクトによって異なると思いますので言及しません。
ここ2年の技術的負債の推移を見てみると以下のようになります。
新機能の追加で負債が増加することもあり、二年前の時点の167日を完済とは行きませんが、メインコードについては負債は減少傾向にあります。
借金で例えると「新規の借り入れ」はありつつも「元本」を返せている感じがしますね。まぁ頑張っている方だと思います。
数値の改善に取り組む
さて、この返済をどう行ってきたのかについてです。
もちろん、基本的には、個別の指摘事項を潰していくことで返済していますが、指摘されたことを機械的にやっていたのでは埒があきません。
以下では一気に改善してみせる方法を取り上げます。といっても、どれも当たり前な改善方法ですが。
抽象設計を行う
まず、負債が大きいコードでは設計がなっていない事が多いです。
コードをみて、オブジェクト指向の基礎にしたがった設計をしっかりと行います。
また、既存のコードが増える度に、抽象化して共通化すべき概念は増えていくはずです。エリック・エヴァンスが好きならそれらの一部はドメインと言い換えても良いでしょう。
手続きとしての共通化ではなく、抽象度の高い設計を行い、コードを共通化しましょう。
抽象設計が正しく行えると、コードの重複が少なくなりますので、わりと劇的に指標が改善します。
とくに、Java8以降では、ラムダ式やdefaultメソッドが使えるので、Java7以前から存在しているコードについては見直せば大きな効果が期待できるでしょう。
テストで使用されているMockの見直し
単体テストが設計時のままの場合、テストの対象となっているクラスと連携する他のクラスでモックを使用しているケースが多いかもしれません。
それらがインスタンス化が出来るなら、インスタンス化してしまいましょう。無理ならスパイを使っても良いでしょう。
単純にカバレッジが改善することもあれば、実際にはどうやったって通ることのない不要なコードが見つかって、それを削除できたりします。
例えば、Nullになり得ないシーンでのNullチェックや、@NonNullアノテーションをつけられるシンボルの発見などです。
ライブラリへの切り出しでよく見せる
指標を改善するだけなら最もよく見せる方法がこれです。
じつは、グラフ中に現れる大きな減少は、メインから別のライブラリへコードを切り出した結果としてメインコードから負債が消えたという部分があります。
むろん、その場合では、ライブラリの負債も合計すれば負債総額は変わらないです。いわば(メインからは)視えない化ですね。
それでも、メインコードの負債が減るのは短期的には良い傾向だと捉えられます。
なぜなら、一般にライブラリへのコードの追加・更新はメインコードへの追加更新よりも頻度が低いからです。このことをまた借金で例えるなら、返済期限が長く、新規の借り入れをあまり必要としない返済方法への乗り換えと捉える事ができます。
また、ライブラリ化によってコードの独立性が高まることで、そのライブラリに関する業務を分離することが出来ます。メンバーが増えたときにその業務を担当させやすくなるでしょう。借金の肩代わりをさせるようなものといえます。
なお、ライブラリ化できる構造に変更すること自体が、設計を正しくし、指標の改善となる傾向があります。
もちろん、機能をライブラリとして切り出すべきかどうか、きちんと考えた上で行う必要がありますので、なんでも分割すればいいというわけではないことには注意しましょう。メイン部分と独立している、改修の頻度が高くない機能が切り出す対象として向いています。
そして、切り出した後のライブラリを知らんぷりしていると、多重債務者状態になって立ち行かなくなることも心に留めておきましょう。
視えない指標にも対抗する。。。けど心構えは必要
上記までは、基本的に視えている技術的負債に対抗する方法です。
技術的に負債には、見えない部分があって、それらについても対抗しておかないと困ったことなります。
陳腐化に対抗する。。。のにも限界はある
さて、視えない部分で大きな部分を占めるのが陳腐化による内在的な負債です。
陳腐化とは、時間経過により使用する基盤技術やライブラリが古くなってしまい、刷新を行わなければならなくなることを指します。もちろんコストがかかります。
いつライブラリや環境が新バージョンをリリースするか、旧バージョンのメンテナンス期限が切れるかなどは、その全てを自動で把握することが難しいため、SonarQubeでも指標として取りにくいケースが多いです。
セキュリティ上の問題が発覚したりなどは、ある日突然に起こる場合もあります。
使用している技術が突如として使用不能になったり、採用した技術の新しいバージョンへの移行が極端に難しいことが判明してしまう様子は、借金に例えるなら、貸し剥がしや貸し渋りといったところでしょうか。
可能な限り最新のライブラリ環境に寄せ続けることでリスクを減らすことは出来ますが、なかなかに難しいことが多いでしょう。
対抗策として考えられるのは、設計段階で腐敗防止層を設けたり、ファサードのような実装が可換なパターンを用いていたりなどですが、それらはライブラリの変更には耐えられても、言語のアップグレードなど基盤技術の変更には耐えられません。
どんなシステムでも、陳腐化の原因については対策は後手に回る以外にないため、「陳腐化速度>メンテナンス速度」が宿命づけられており、いずれ陳腐化による借金が返済不能になると思っています。
何処かでしっかりと諦めて、システムの一からの作り直しをするか、もう止めてしまう覚悟が必要だと思います。
ちなみに、今のAstamuse.comはJava製ですが、かつて黎明期にあったScalaを用いて、同じく初期頃のバージョンのLiftで組まれていた時期があります。乗り換えの理由は、総合的な理由であり、陳腐化のみではなかったかと思います。昔のScalaは、今よりも問題が多かったことは確かです。
前提条件の変更もある。。。流れに乗らざるを得ない
陳腐化と似ているのですが、時代の変化により前提の条件が変更されるということもあります。時間というより、もっと大局的な時代でおきる、いわゆる時代の要請ですね。
条件の変更の例を言えば、CPUの進化や、メモリ容量の向上、クラウドの普及、スマートフォンユーザの増加、HTTPSデフォルトの一般化、などです。
それらを理由に、システムの根本的な作りや、データの取り扱い方、必須とされる機能の要件など、様々なところで変更が強いられます。
つまり、かつての時代の常識が、今の時代の非常識になったため、対応を取らなければならないことですが、Webサービスで言えば、FlashからHTML5への刷新などですね。
こうした内容は、陳腐化と同様にSonarQubeでは指標化出来ないこともありますので、他の方法で気にかけられるようにしておくべきでしょう。たとえばモバイルフレンドリー調査ツールやアクセス解析など、要件ごとの解析ツールなどです。
Astamuse.comでも、こうしたツールを用いて、細かな修正で対応可能な範囲においては、時代の要請にあった改修を続けています。
もちろん、小さな変更では済まないことも多くあります。例として出したFlashの廃止も、手法によってはそのうちの一つとなるでしょう。
Astamuse.comにおいてそのような部分の一つに、コンポーネント化への対応というのがあります。
Astamuse.comの基本的機能は、かつてGoogleの検索ボットが動的ページのインデックスをうまく行えなかった時代に作られています。それゆえ、Astamuse.comは、データを元に静的なHTMLを生成できるCMSのような実装が得意なFWを用いて、サーバサイドでHTMLをレンダリングするシステムとして組まれています。
ですが、ご存知の通り、今ではGoogleのBotは賢く、フロントエンドで描画されるインタラクティブなページも難なく解析し、検索インデックスに加えることが出来ます。
一般に、サーバサイドレンダリングは、サーバサイドへの負荷が高く、クライアントでも重複するHTMLデータを何度もダウンロードをしなければならないため、非効率とされています。
なので、いつとは言えませんがAstamuse.comもそのようなサーバサイドレンダリングからフロントエンドレンダリングに実装を切り替えていくことになるでしょう。
こうした改修は、コストが大きいので、既存のシステムを「諦める」可能性についても考える必要があります。
今のAstamuse.comのコードベース全てを諦めるということはないと思いますが、ミドルウェアやフレームワークの選択を含め今後考えていくことになるでしょう。割りと好き勝手に。
まとめ
- 指標を見えるようにしよう。
- 指標を改善する設計を行おう。
- 一度書いたテストも放っておかずにメンテしよう。
- メインコードから切り出すべき機能を探してライブラリにしておこう。
- 見えない部分にも気を配ろう。
- 諦めるときは諦めよう。
- 諦めたら割りと好き勝手出来ると思う。
P.S で、Java9もう出てるよね
先日、待望のJava9が発表され、モジュール化機能の検証をせざるを得ないなぁと思っているところにその後のJavaのリリース計画も半年ごとに云々とか、、、
新しいことが出来るようになっていくのはとてもいいことなんだけど、抱え込んでるものの大きさにもよるよなぁ。
全くもって、人手が足りません。