DevOps組織におけるベロシティの測定値を用いて、技術的負債のコストと位置を決定する。

技術的負債の漫画

技術的負債とは、(Wikipediaより)以下のように定義されています。

時間がかかる良い方法ではなく、今すぐできる簡単な解決策を選択することによって生じる、追加的な手戻りの暗黙のコストです。

多くの人は、この負債がコードの中だけにあると仮定し、サイクロマティックコンプレックスやテストカバレッジを測定したり、リンターを使用して負債の量や存在する場所を決定します。これらの測定はうまくいきますが、どのタイプの負債(複雑さ、テストの欠如、不十分な文書化)が最大の問題を引き起こしているか、どこから始めるのが最善かを明らかにすることはできません。また、例えば、発見が困難なタイプの負債を測定することもできません。

機能の重複
構成要素全体は複製されるが、異なる言語で書かれている。
デバッグ用デザインなし
ロギング、エラーレポート、リリース/デバッグのばらつきが原因で、顧客サイトやQA部門と離れた場所で障害が発生した場合、デバッグは困難です。
スローテストスイート
テストスイートの実行に時間がかかり、結果的に納期が長くなる
...

これらのことから、クリスティでは、テクニカルデットの標準的な定義を少し引き出して、次のように使っています。

時間がかかる良い方法を使わず、今すぐできる簡単な解決策を選んだために生じた追加作業のコスト。

これを把握する方法があるのです。

  1. もし、より頻繁にコミットすることが望ましいと仮定した場合
    (...と言いながら、そうすることを推奨している...)
  2. となると、もっと頻繁にコミットしない理由は
  3. というのも、技術的負債と定義しているからです。
  4. リファクタリング、アーキテクト、その他の方法で改善すれば、可能です。

そこで、技術的負債を次のように測定することができます。

標準偏差α以上のコミットで、通常から標準偏差α離れたファイルを含むコミットに費やされた時間。

つまり、時間がかかるコミットで日常的に登場するファイルを含むコミットで余分な時間がかかった分です。

コミット履歴を把握する

subversionとgitのログを処理して生成するpythonスクリプトを書きました。

  • コミット作成者
  • 作者が最後にコミットしたレポからの業務時間
  • そのコミットに含まれるファイル

そして、これらのコミットを著者ごとに正規化し、このグラフを作成しました。

正規化されたコミット履歴

多少の試行錯誤(がある 紛れもなく しかし、統計学的な知識は実験中に学んだ)。 lambda x: np.log(x) ** 2 を2つの同時のBox-Cox変換として与えると よほど を正規分布に近づけ、これを逆に適用すると、上のグラフのように最適な線が得られます。

コミット履歴の変換

技術的負債

これで、各ファイルのzスコア(正常であるべき母集団がどれだけ「正常」であるかを示す指標)を次のように計算することで、技術的負債を把握することができるようになりました。

def zscore(commits):
"Z-Score per-file for all files in commits"
perpath = collections.defaultdict(list)
for commit in commits:
for path in commit.paths:
perpath[path].append(commit.interval)
return {path : sum(perpath[path]) / math.sqrt(len(perpath[path]))}

つまり、技術的な負債に対して支払っている利息を計算することができるのです。

def debt(commits, deviation=1):
"Total debt for this series of commits"
scores = zscore(commits)
debt = 0
for commit in commits:
for path in commits.paths:
if scores[path] > deviation:
debt += commit.duration -
inverse(0) -
inverse(deviation)
return debt * 100.0 / sum(c.duration for c in commits)

スライディングウィンドウを使用することで、技術的負債の経時的なグラフを作成し、これに寄与しているファイルを見つけることができます。以下は、関心の高いファイルのコミット数の母数を通常と比較して示したものです。

比較すると高金利なファイル

結果

2018年からの技術的負債は20%前後で推移しています。

借入金利息、2018年

さらに重要なことは、これで作業すべきファイルのリストが得られることです(罪のない人々を守るために編集されています)。

Zスコアコミットメントマルチプライヤファイル名
3.181.66 %2.44xアプライアンスDockerfile
0.824.76 %2.14x新製品用ライセンスコード
2.940.98 %2.15xリモートpython REST API

上記のようなケースで、問題点があったことはチーム全員の共通認識でした。診断結果は、以下の通りです。

アプライアンスDockerfile
アプライアンスのサイズが大きすぎたため、必要なパッケージをNexusからネットワーク経由でプルダウンすると、往復で大きな遅延が発生していました。
この対策として、アプライアンスサイズを大幅に縮小しました。
新製品用ライセンスコード
このコードは買い取ったもので、いろいろと問題があった。

  • 32/64ビット、ビッグ/リトルエンディアンアーキテクチャのコンパイルミス
  • 重複しているが、似たような名前の関数、例. CheckLicencecheck_licence
  • 誤解を招く名称(dsUint32_t は、実は単なる int...)

これをクリアするために、このコードを広範囲にリファクタリングし、テストを追加しました。

リモートpython REST API
これは、周期的な複雑さが高く、ドキュメントも少ないが、最も重要なことは、統合テストのターンアラウンドタイムが高いということでした。
これは、各テストで実施される統合テストのステージをいくつか削除することで改善されました。

この方法に対する反論

バージョン管理に入らないものはどうする?

まず最初に...全てはバージョンコントロールされるべきです!簡単です。もちろん、そうでないアクションは常にあります。しかし、それらは現在のコミットとは独立しているか(つまり、大量に実行してもデータに影響を与えない)、現在のコミットに影響を与えるか(その場合は技術的負債となります)のどちらかです。

人によっては、もっと気を遣うこともあるのでは?

個人ではなく、コードやプロセスに関するデータを作成するために、著者ごとに正規化を行っています。

金利は、コードが現在アクティブである場合にのみ支払われるため、金利が下がるということは、現在アクティブなコードがより良いということかもしれません。

これは本当にそのとおりで、間違いなく問題です。技術的負債の多い非活動的なコードは、リスクを表していますが、実際にはまだ物事を妨げていません...。これは二次的な測定基準(複雑さ、カバレッジ、リンティング)が役に立つところです。特に、負債の経験的な測定基準へのリンクが見つかれば、そのようなことが可能になります。...このスペースに注目してください。