技術的負債の生態

@t_wadaさんが翻訳されていた技術的負債の記事をあらためて読んでみたら非常に面白かった。技術的負債の本来の意味が説明されているので、まだ読んだことがない人は一読をおすすめする。

その翻訳記事を読みながら、Jasper(僕が開発しているGitHub用のIssueリーダー)のv1.0で技術的負債を返済したことを思い出した。そこで、その翻訳記事を参考にして技術的負債の生態について自分なりに考えてみることにした。すると面白い生態がいくつか見えてきた。例えば「生態③: むしろ技術的負債が生まれることそれ自体はポジティブである」などである。今日はそのことについて書いてみようと思う。

ちなみに今回は技術的負債への対処までは解明することができなかった。いつか続きを書けたらいいなと思う。

技術的負債が生まれる背景

まずはJasperで経験した技術的負債を紹介する。負債の内容自体はそんなに重要ではないのでさらっと見てもらえれば十分だ。

負債 内容
ポーリングキュー Issue取得のポーリングキューはもともと単純なFIFOだったが、優先度付きFIFOが必要になった
Streamのデータ構造 複数種類のStreamが異なるデータ構造を持っていたが、統一的なデータ構造が必要になった
Main/Rendererの通信 ElectronはMain/Rendererの通信に便利なモジュールを提供しているが、それを使うとパフォーマンスの問題が発生するため、別の仕組みを使うことになった
Reactコンポーネント Reactコンポーネントを小さくわける・なるべく状態を持たないなどの書き換えをすることになった
モジュールの依存関係 モジュールの依存関係を整理して、UI層からデータ層に向かうシンプルな単方向依存にすることになった

これらの技術的負債はJasper v1.0で返済したのだが、結構たいへんだった。最初から技術的負債を生まなければどれほど良いか。

そもそもこれらの技術的負債はどうして生まれたのだろうか?僕が開発スピードを優先してコードの質を落としていたのだろうか?

いや、そうではない。少なくとも僕はその時その時に自分が書ける最善のコードを書いていたつもりだ。では本当の原因は?それは僕がJasperの開発過程で様々なことを学習して新たな理解を得たが、その理解をコードに反映していなかったから技術的負債が生まれてしまったのである。

例えば先程の「ポーリングキュー」はIssueリーダーというドメインについて学習して新たな理解を得たから生まれた負債だ。また「Main/Rendererの通信」はElectronアプリについて学習して新たな理解を得たから生まれた負債だ。

本来ならこれらの理解をすぐにコードに反映すべきだったが、それをしなかった。しなかったというか、自分の理解とコードにギャップがあることをはっきりと認識できていなかったのだろう。それが徐々に大きくなっていき、コードに手を入れるのが大変になっていったのだ。

では今後、技術的負債を生み出さないようにするにはどうしたら良いのだろうか?実は本質的には技術的負債を生み出さないようにすることはできない

なぜなら技術的負債は先ほど書いたように、学習の結果うまれるものだからだ。例えば今このとき自身が考える必要十分で最善のコードを書いたとする。しかし開発を進めていくとビジネスドメインやプログラミング全般について学習し、新たな理解を得る。この新たな理解と目の前のコードにはギャップが生じている。結果としてそのギャップが技術的負債になるわけだ。人は最初から完璧な理解をもって完璧なコードを書けるわけではない。

むしろ技術的負債は学習して新たな理解を得られた結果生まれるものなので、生まれること自体はポジティブである。例えば「インデントが無いコードを書いていたが、コードフォーマットについて学習して新たな理解を得た結果、以前のコードが技術的負債となった」というような場合だって、前進しているんだから素晴らしい。どんな場合も「今この時、自分が考える必要十分で最善なコードを全力で書いた人」が責められる理由は一つもない。

※ただしここでは話を単純にするために「学習しない・意図的に雑なコードを書く」というのは考慮していない。それは別次元の話である。

生態①: 「対象についての理解」と「目の前のコード」のギャップが技術的負債

生態②: 技術的負債が生まれないようにするのは本質的に不可能

生態③: むしろ技術的負債が生まれることそれ自体はポジティブである

2つの技術的負債

とはいえ技術的負債があることで開発スピードや保守に影響を及ぼすのは事実である。ではどうすればよいのか?返済できる日がくるまでじっと耐えるしかないのだろうか?

まず技術的負債を発生原因が異なる「ビジネスドメインの技術的負債」と「プログラミングの技術的負債」に分けて考えてみる*1

ビジネスドメインの技術的負債
「ビジネスドメインの技術的負債」とはビジネスドメインを学習し新たな理解を得ることで生まれる負債だ。

例えば医療機関を対象にしたソフトウェアを開発しているとする。開発するなかで「病院とクリニックではビジネスモデルが違う」「医療クラークや医療事務がいる場合、業務フローが異なる」などを学習して新たな理解を得る。そうすると、それまでのコードと今の理解にギャップが生じて技術的負債となる。Jasperの負債でいうと「ポーリングキュー」や「Streamのデータ構造」についての負債がこれにあたる。

この負債は「学習して得た新たな理解をコードに反映できないので負債を作ってしまう」ことが多いだろう。なぜならビジネスドメインの学習というのはエンジニアに限らずチーム全体で積極的にすごいスピードで行われる。そうすると学習で得た新たな理解をコードに反映するタイミングを逃したり、学習が早すぎて追いつかないなどがあるからだ。なのでビジネスドメインの新たな理解を定期的にコードに反映する機会を作れば負債を最小限に抑えることができる。

プログラミングの技術的負債
「プログラミングの技術的負債」とはその名の通りプログラミングスキル(読みやすいコードスタイル・ソフトウェア設計・データ構造・セキュリティ・使っているフレームワークなど)を学習し新たな理解を得ることで生まれる負債だ。

例えばユーザデータを集計する様々なバッチを開発しているとする。開発する中で冪等性という概念とそれを実現する方法を学習し、新たな理解を得る。そうすると、それまでのコードと今の理解にギャップが生じて技術的負債となる。Jasperの負債でいうと「Main/Rendrerの通信」「Reactコンポーネント」「モジュールの依存関係」についてがこれにあたる。

この負債は「知らないことで負債を作ってしまう」ことが多いだろう。なぜならコードを書くときは身につけたプログラミングスキルの中から適切なものを選んで使っていく(もちろんそれ自体にも難しさはあるが)ので身につけてないものは使えないからだ。なので、必要なときに必要なプログラミングスキルを学習する機会を作れば負債を最小限に抑えることができる。

※ここでも話を単純化するために{ビジネスドメイン, プログラミング}の技術的負債を独立して考えているが、実際は両者は相互に影響しあう。また、新たな理解を正しくコードに反映できるかという問もある。

生態④: 技術的負債には「ビジネスドメインの技術的負債」と「プログラミングの技術的負債」がある

生態⑤: ビジネスドメインの技術的負債は「新たな理解をコードに反映できない」から発生する

生態⑥: プログラミングの技術的負債は「知らない」から発生する

技術的負債を小さく抑える

ここまででわかった技術的負債へのアプローチは次の2点だ。

  • 「ビジネスドメインの新たな理解を定期的にコードに反映する機会」を作る
  • 「必要なときに必要なプログラミングスキルを学習する機会」を作る

しかし本当にそんな機会を作ることができるのだろうか?ビジネスの場では常に最優先のタスクが存在し、不確実性が高いものもたくさんあり、時間と人はいつだって足らない。そんなときに一見ビジネス価値を生まないような機会に時間をさけるだろうか?

その方法は...実を言うと僕にはここまでしか考えられなかった。本当なら生態を完全に解き明かし、技術的負債を最小限に抑える仕組みをズバッと言いたかったのだけど。でも、スクラム開発は技術的負債を小さく抑える参考になるかもしれない

スクラムは開発を通して様々なことを学習し、その学習で得られた理解をプロセスやプロダクトに反映し、現時点で最適な状態を常に保とうとする。そのために様々な機会(プランニング・リファインメント・レビュー・デイリースタンドアップ・レトロスペクティブなど)を仕組みとして備えている。これは先程の技術的負債へのアプローチとかなり共通する考え方である。なので、スクラムに技術的負債へのアプローチをうまく組み込んだ形が作れるかもしれない。

生態⑦: ビジネスドメインの新たな理解を定期的にコードに反映する機会を作って対処

生態⑧: 必要なときに必要なプログラミングスキルを学習する機会を作って対処

生態⑨: これらの対処方法はスクラムと相性が良いかもしれない

というわけで、技術的負債について考えたことを書いてみた。明快な結論は出せなかったが、こうやって考えを残しておけばいつか続きをかける日がくるかもしれない。

最後に一つ注意してほしいのは、今回の話は技術的負債について精緻にも網羅的にも検討されたものではいということだ。例えばベンチャーでドメインの学習がすごいスピード進む場合どうしたら良いのか。すでに大規模なシステムがあり人も入れ替わっていく場合はどうしたら良いのか。などなど、検討していないことはたくさんある。そこはご了承いただきたい。

記: 丸山@h13i32maru

*1:「ビジネスドメインの技術的負債」が本来の意味での技術的負債であり、「プログラミングの技術的負債」そもそも発生させるなという扱いになっている