「技術的負債」とその扱いについて
技術的負債とは?
プログラムを書くにあたって、避けて通れないのが保守作業です。 今回は「技術的負債」について考えていきたいと思います。
※言語を問わない内容ですが、一部PHPに限定した内容もある点だけご承知おきを
技術的負債(Technical Debt)とは?
ウォード・カニンガムにより、1992年に提唱された概念
The WyCash Portfolio Management System
(原文訳) 最初のコードを出荷することは、借金をしに行くのと同じである。小さな負債は、代価を得て即座に書き直す機会を得るまでの開発を加速する。危険なのは、借金が返済されなかった場合である。品質の良くないコードを使い続けることは、借金の利息としてとらえることができる。技術部門は、欠陥のある実装や、不完全なオブジェクト指向などによる借金を目の前にして、立ち尽くす羽目になる
(参考) 「エンジニアリング組織論への招待 ~不確実性に向き合う思考と組織のリファクタリング」広木 大地 (著) P.249
続いてWikipediaによる定義(厳密だが、ちょっと狭い)
時間がかかるより良いアプローチを使用する代わりに、今すぐ簡単な(限定的な)解決策を選択することで生じる追加の手直しの暗黙のコストを反映したものである
もともとは、課題解決的に生み出された用語で、比較的曖昧に使われていました。
What is Technical Debt? - Definition from Techopedia
- ソフトウェアは、当初の開発から日が経つにつれ、追加開発の工数が増大したり、メンテナンスが困難になったりすることが、しばしば見られた
- しかし、技術に造詣の深くない経営層には理解されがたい現象であったため、適切なリソース(人員・期間)を得ることが難しかった
- 負債(debt)という用語を用いることにより、技術に対する造詣の深くない経営層へのアピールを目指した
技術的負債の例
- 複雑かつ肥大化したコード
- 複雑かつ肥大化したDB(RDBMS)
- レコードが億単位になっていたりすると、手をつけたくてもつけられない
- セキュリティパッチの提供されなくなったOS、ミドルウェア、ライブラリ
- バージョンが乖離するほど、バージョンアップ時のトラブル率も上がるので、余計に手をつけられない
- 陳腐化したフレームワークなど
- 誰も使わなくなって更新が止まったライブラリなど
- 陳腐化したハードウェア
- クラウド時代になってあまり聞かなくなった
技術的負債の弊害
技術的負債があると、どんな悪いことがあるでしょうか?
開発コストの増大
以前にいた現場では、コーディングが「影響調査7割、価値を生み出す作業3割」くらいになっていました
- リグレッションテストなども含めると、技術的負債の返却に充てている工数が大半
- 日々発生する不具合も多く、その改修がことごとくこんな感じの作業になる。技術的負債による自転車操業状態
従事するエンジニアのモチベーション低下
日々このようなコードと対面し続けるのは、エンジニアとして辛い・・
- 悪い見本の山。コードを読んでいてもスキルアップに繋がらない
- モチベーションも上がらず、離職率も高くなりがち
どうやって解決するの?
技術的負債とは何かを見てきましたが、では、どうしたら解決できるでしょうか・・・
どうやって解決するのか?
大きくは3つの方針が考えられます
- 大規模な刷新により、一括での返済を目指す
- 日々のリファクタリングにより、より良いコードに置き換えていく
- 対応しない
大規模な刷新
- 既存コードを捨て、1から全ての仕組みを書き直す
- コストは最大。うまくいけばメリットも莫大。しかし、リスクも大きい
- 大規模な刷新でないと対応できない事項はある
- DB構成の見直し、複雑に分散した機能の統合など
- 運用上の制約が、汚いコードやDB設計に影響を及ぼしている可能性もある
- システムを設計する組織は、そのコミュニケーション構造をそっくりまねた構造の設計を生み出してしまう (コンウェイの法則)
- この場合は、制約をどうにかしないと良いコードにならない
- そもそも良いコードを書く習慣がついていないチームが、新たなコードを書いても同じものを作る可能性もある
- 大規模な刷新は、結局のところ1つの契機にはなるが、全てを解決する魔法の杖ではない
- 昔はハードウェアの定期的な刷新で、大規模な刷新の機会を得られることもあったが、クラウドの時代になりそういう機会も少なくなっている
日々のリファクタリング
- 日々リファクタリングを続けることで、こまめに負債を返済し続ける
- 日々の開発の中で、気づいた点を修正していく
- アマゾンでは1日1000回のデプロイ
- という噂。裏は取ってない(が、それ以上とも言われる)
- もちろん、毎日1000個の機能追加を行っているというわけではなくて、細々とした改善をそれだけ実施しているという話だと思われる
- ただ、「リファクタリングしやすい」コードになっていないと、テスト工数が嵩むことになる
- 例えば、関数がクラスメソッドになっておらず、unit testが書かれていない場合、以前と同じ挙動になっているかの確認が困難である
- この場合、まず「リファクタリングしやすい」コードにリファクタリングするのが最優先となる
対応しない
- 経営の視点から考えると、あり得る選択だとは思う
- 日々、人海戦術で品質の低いコードと戦う
- 離職率は高くなるだろうので、技術者は使い捨て
- 一定の限界を超えたらサービスを打ち切ったり、売却したり...
- 技術者としてはあんまり嬉しくない
- 明示はされていないが、暗黙にこういう経営方針を採っているプロジェクトは見かける
- とはいえ、無借金経営は無理(ある程度の技術的負債はあるもの)なので、あまり悪いところばかりを見てこういう方針だと即断しないように
まとめ
個人的には、日々のリファクタリングが重要だと思っています。大規模な刷新をするにも、日々のリファクタリングができるくらいの「地力」がないと難しいのではないでしょうか。では、「地力」とは?
最後に「地力」とは何かを述べて、この記事を締めくくります
リファクタリングに工数を費やせるための環境
日々の作業にかかる工数が多ければ、その分リファクタリング等に割く時間は減る
- 開発環境整備
- DBマイグレーション
- 自動デプロイ
リファクタリングしやすいコードにする
リファクタリングの結果新たなバグを大量に作り込んだら、周囲の理解を得られない
- クラス化、メソッド化、適切なサイズへの分割
- ファットコントローラ/ファットモデルの回避 (MVCの弱点)
- 自動テスト (phpunit と CIの仕組み)
コーディングガイドライン
墨守する必要はないが、ある程度はあった方が楽。リファクタリングしやすいコードにもつながる
- phpcs(psr2によるコーディング規約チェック)
- phpmdによる静的解析 (癖が強いので使い方は難しい)
ナレッジ共有、共有による深化
自分が良いと思ったものが、必ずしも他人にとっても良いものではない
- コードレビュー
- ペアプログラミング