そろそろ「技術的負債」という言葉を使うのは止めませんか?負債の返済から資産としての管理へ
はじめに
ソフトウェアエンジニアリングにおいてSNS上で技術的負債が定期的に話題にあがることがあり(炎上ともいう)、小飼 弾氏が言及することがありました。最近ではこちら。
負債ではなく資産(何年か前にこれとは別の呟きをみて腑に落ちた)。どうして資産と言及しているかというとソフトウェアは無形固定資産として貸借対照表の左側にあるため。
技術的負債とは
負債という比喩を生んだのはWard Cunningham(ウォード・カニンガム)氏であり、その説明が和田 卓人氏の「【翻訳】技術的負債という概念の生みの親 Ward Cunningham 自身による説明[1]」で翻訳されています。是非ともお時間のあるときに目を通していただきたい。
或る事象に名前が付くとその背後にあるコンテキストが失われてしまうため、原義にあたりコンテキストを理解するのを心掛けるようにしましょう(自戒を込めて)。
負債とは貸借対照表(バランスシート、B/S)の右側であり、英語ではLiabilityで、借金の意味合いが強い場合にはDebtを使うそうです。

貸借対照表。項目は一部のみ
カニンガム氏は『Debt』と言っているので借金の意味合いが強いですね。つまりは技術的借金。技術的借入。
学びを反映(リファクタリング)することで負債を返済していきます。世の中の不確実性に対応しながら持続的なソフトウェアエンジニアリングを実現するためです。
しかし、返済しない場合は利子が増えてさらに借金が増え、ソフトウェアエンジニアリングにおいて悪影響となり開発速度が停滞します。
決して雑なコードを書いても良いということでもありません。
「技術的負債」という言葉の問題点
ここで、技術的負債という言葉の問題点を考えていきたい。
負債(借金)という言葉は返済すれば終わるものという誤解を与えやすい。また、エンジニア側が対応したくても、この技術的負債には明確な返済期限がないため対応しなくて問題ないとビジネス側に判断される恐れがある。
b
そして、返済に対応していたとして、果たしてこの借金を返済し終わることがあるのでしょうか?
答えは「ない」。なぜならカニンガムの『ソフトウェアを世に出し、そこからの学びを反映し続けることで借金を返済していく』と言う通り、ソフトウェアは流動的であり「学びを反映し続ける」必要があるから。先の図では「持続可能な開発」と書きましたが外部的でも内部的でも何かしらの理由で開発が停滞すると借金は膨らんでいきます。
ソフトウェアは学びを反映し続ける必要がある
ソフトウェアはリリースしてからが本番と言えます。法律への対応、ビジネスの判断が変わった、新機能の追加、より良い設計や実装への改善、運用で見つかった問題への対応、プログラミング言語自体やライブラリ、フレームワーク、データベースなどの各種サーバー、ミドルウェア、OS、コンテナエンジンなどのバージョンアップ対応の保守やメンテナンスなどなど、「学びを反映」し続けるコト・モノは無数にある。
長い目で見ればハードウェア(およびソフトウェア)の塊である自動車もだいたい3-5年ほどで「学びを反映」してモデルチェンジされ、スマートフォンはほぼ1年単位でモデルチェンジされる(OSやアプリは都度更新される)。ソフトウェアはこの「学びを反映」する期間がハードウェアに比べて短いだけ。
また、長期に渡ってソフトウェアに「学びを反映」しないということは、ソフトウェアの持つ(ハードウェアに比べて)変更が容易であるという特性を無視するもの。
スケープゴートとされる
他にも意味が希薄化してスケープゴートとして濫用されているように思えます。
リスクを取った結果なのか、ずさんな設計や知識不足からくる結果なのかが区別されず、思考停止のキーワードとしての便利なスケープゴートとして濫用されているように思えます。
例えば、ずさんな設計でコードがごちゃごちゃになっているのは「大きな泥団子」や「スパゲティコード」など他に当てはまる言葉があるので負債と区別し、正面から向き合う必要があります。負債だからと放置せずに正しい言葉と向き合ってより良い設計・コードにしていきたいですね。
他にも、検証もせずにトレンドだからという理由で採用して盛大にミスったのは「選定ミス」と言えます。ミスを認めるのは難しいですが、これも素直に認めていきたい。
あと、プログラミング言語自体やライブラリ、フレームワークなどなどのバージョンアップを放置しているのは「車検切れ」「消費期限切れ」「腐敗」あたりですかね(まだ同意された比喩はなさそう)。これも放置しないように定期的に行っていきましょう。
負債ではなく資産として考える
前述の貸借対照表の図を見ても分かる通り、ソフトウェアは無形固定資産。左側の資産の部であり、償却していくもの。また資産と定義することで前述の「大きな泥団子」や「スパゲティコード」、「選定ミス」、「車検切れ」、「消費期限切れ」、「腐敗」なども不良資産として定義できるかと考えます。
資産は会社に利益をもたらす可能性のあるものである。それが不良な資産で埋め尽くされていると問題であり、資産管理をして優良な資産に変えていきましょう、と。ビジネス側にはこちらのほうが理解が得られやすいのではないでしょうか。
「なんで不良資産を放置するんだ」とお叱りを受ける可能性はありますが、ソフトウェアは会社の資産であるのでビジネス側のソフトウェアエンジニアリングへの理解の促進にもなるのではないか?と前向きに考えたい。
不良資産を生み出すアンチパターン
アンチパターンとして考えられるのは、
・顧客の求めるものを理解していない
・外注
・プロジェクト単位で人を割り当てる
・バージョン管理されていない
・CI(Continuous Integration)/CD(Continuous DeliveryまたはContinuous Deployment)の環境がない
・モジュール間が密結合している
・テストコードが書かれていない
・ライブラリなどをあまり検証せずに導入した
・プログラミング言語自体やライブラリ、フレームワークをバージョンアップを放置している
・技術トレンドの流れを気にしない
などなど。
これらはソフトウェアの価値を発揮できずにビジネスの足を引っ張る不良資産を生む可能性が高いです。もちろん不良資産を放置する戦略を取ることはビジネス上あり得るが、放置期間が長ければ長いほど不良資産は大きくなっていきます。また、いざという時に法律への対応やビジネスの変更に対応するまでにソフトウェアの改修に時間が掛かるようになります。
優良な資産に変える
これはアンチパターンとは逆のことをすれば良い。とはいえ企業の業種や規模、考え方などなど関係しており「言うは易し行うは難し」です。
顧客の求めるものを理解する
例えば社員が掲示板がほしいと要望があっても「なぜ、なんのために必要なのか」を十分にヒアリングすること。情報を一方向で伝搬するためなのか、コミュニケーションの円滑のためなのか、コミュニケーションのためならブログのような投稿することに心理的ハードルが低くなるようにしたほうがいいのか。案件管理の仕組みがほしいと要望でもそもそも案件を管理したいのか、案件に費やすリソースを管理したいのかなどなど。本当にほしいものがなんなのか探究する必要があります。ここを怠ると誰も使わない無駄なものが出来上がり不良資産となるのでそもそも開発しないほうがいいでしょう。
「UMLモデリング入門[2]」と言う書籍がおすすめ。とくに第11章の「総合演習: ユーザー要求のとらえ方)が良い。
あとコミュニケーション能力。新卒の頃に「あなたの話はなぜ「通じない」のか[3]」と「日本語の作文技術[4]」に助けられました。
探究についての私の考えは「顧客と接する際に意識していること[5]」に以前書きましたので参考までに。
外注ではなく内製する
内製にするとIT側とビジネス側との意思疎通が早くなり全体の速度が上がります。情報システム部門は存在するけども要件をまとめるだけで開発は外注していることが多いですが、情報システム部門を単なるオペレーターではなく問題解決の集団としましょう。ビジネス側からの相談から開発、運用、保守まで情報システム部門で行う集団に。
「構築した者が運用する(You build it, you run it.)」の精神を持ちましょう。画家が数多くのデッサンをして絵を描くように、小説家が推敲をなん度も重ねて小説を書き上げるように、漫画家が没になりながらも何度もネームを描いて漫画を完成させるように、エンジニアも実際に自分自身で問題を発見して課題を定義し、ソフトウェアで解決するべき範囲を決め、試行錯誤しながら仮説と検証を反復的に実施し、かつ、開発したソフトウェアをデプロイし運用・保守を行う。
プロジェクトではなくプロダクトに人を割り当てる
プロジェクト単位ではなくプロダクトに人を割り当てると、同じ人(チーム)が担当するため各種変更への追従も早い。これも外注では難しいです。ただしチーム(の考え)が硬直化しないようにする仕組みが必要。考えが硬直化しないように柔軟で自発的に学習する人が望ましい。
バージョン管理する
バージョン管理は必ず行いたいですね。できれば分散型であるGitだと手元のPCで開発しやすいため、喜ばれると思います。Subversionは集中型なので分かりやすいがGitほど軽快ではないので。
大規模でなければGitフローではなくシンプルにGitHubフローでいいと思うが、本番環境とは別のステージング環境がある場合は、mainをベースにするのではなく、stagingブランチをメインにすると良いと思います(次のCI/CD絡みで)。
CI(Continuous Integration)/CD(Continuous DeliveryまたはContinuous Deployment)の環境を構築する
バージョン管理とセット。GitHub ActionsやAWSのCode Pipelineなどどれでも。リリース時のエラーを減らすためにもリリース作業は自動化してあったほうが良いし早めに構築したほうが良いでしょう。DORAのメトリクス(いわゆるFour Keys)も良くなります。
本番環境とは別のステージング環境がある場合は、stagingをベースにfeature/bugfixブランチとして開発し、stagingにマージしてステージング環境に反映、本番環境へはstagingからmainにマージしてバージョンタグを付けて反映するようにする、など。
モジュール間を疎結合にする
モジュール間を疎結合にするには、オブジェクト指向プログラミングでも参照透過性のある計算と、入出力を伴う副作用のあるアクションとをメソッドでなるべく分離しましょう。他にも循環的複雑度[6]やAbc Metric[7]を小さく保つなど。
まずはSOLIDとか難しく考えて悩むよりも、疎結合にすることや分岐を少なくすることを意識するといいでしょう。
計算とアクションについては書籍「Grokking Simplicity[8]」から(残念ながら邦訳はありません…)。
テストコードを書いて自動テストを行う
ユニットテストを充実させるテストピラミッドの考えが良いと思います。ユニットテストは人によって理解が異なりがちですが、参照透過性のある計算に対するテストがユニットテスト、テストダブルが必要となるような入出力を伴う副作用のあるアクションに対するテストが結合テストと考えるようにすればいいのではないか、と考えます。
念のために入出力と言ってもPCで完結するものはテストダブルにはしません。外部のサービスのAPIなどをテストダブルとします。
コードカバレッジやブランチカバレッジも計測しましょう。カバレッジのためのテストはしないほうが良いが、カバレッジが高いとプログラミング言語やライブラリなどなどソフトウェアが直接使う箇所のバージョンアップを安心してできます。
ついでにLinterとFormatterも自動で行うようにしましょう。これはCIまで待たずに手元のPCでもできるしPCのほうが早い。
ライブラリなどはきちんと検証してから導入する
技術は時代のトレンドなどもあり見極めることは正直難しいです。開発するシステムに対して導入したいサービスやライブラリ、または開発や運用時に使用するツール群が業務に合うかはなるべく早めに検証したいところですね。まずは公式ドキュメントをしっかり確認する(意外にも公式ドキュメントを確認しない人が多い)。
サービスは、だいたい何かしらと連携することになるのでAPIを調査すること。
ライブラリやツールを取り入れる目安の判断として、どう適合するかが一つ。適合する方法がイージーなのかシンプルなのか。イージーの場合は取り入れたり使うのはイージーだが密結合していることが多いため、不要になった場合に取り除くのが難しくなる。シンプルの場合は取り入れるのは手間が掛かるが基本的に疎結合となっていて不要になっても取り除きやすい。
特にツール系の操作感はしっかり確かめる。実現したいことはコマンド一つでイージーにできるが、出来上がったものが見通しが悪く複雑なものになるようなツールは要注意。
あとはOSSであればできればある程度ソースコードに目を通す。
イージーかシンプルかの説明はRich Hickey氏の「Simple Made Easy[9]」や廣瀬 健氏の「SimpleとEasyは違う / Simple is not Easy[10]」が参考になるかと。
プログラミング言語自体やライブラリ、フレームワークをバージョンアップを放置しない
上記までの環境が整っていればバージョンアップしやすい。最低でも四半期か半年に一度は棚卸しを定期的にやるしかない。Dependabotで自動化しても良いでしょう。
脆弱性が確認された場合は棚卸しに関わらずになるべく早く適応する。
技術トレンドの流れを捉える
書籍やネットで学習する、勉強会や技術カンファレンスに参加するなど。気合いと根性、継続しての習慣化しかないと思います。ただし、トレンドの流れを捉えてもその技術を採用するかどうかは別です。システムやサービスの規模やタイミングに応じて採用はしっかり見極めましょう。早すぎる採用は諸悪の根源となり得ます(特に将来の運用面で)。
基礎がないままでは見極めることができないため、まずは足場をしっかり固めること。今までにおすすめとしてスライドや書籍をいくつかあげましたが、他にも書籍だけでも一例として問題解決では「ライト、ついてますか[11]」や「いかにして問題をとくか[12]」、ソフトウェアエンジニアリングの哲学や考え方では「人月の神話[13]」や「達人プログラマー[14]」、システム構築では「データ指向アプリケーションデザイン[15]」や「ソフトウェアアーキテクチャの基礎[16]」、他にも保守性の高いコードを書くためには「リーダブルコード[17]」や「リファクタリング[18]」や「レガシーコード改善ガイド[19]」などなど、これらはそれぞれの分野でのごく一部で他にも多くの良書があり、デザインやネットワーク、データベースなどなど他の分野でも多くの良書があります。調べて気になる書籍を読みましょう。参考文献がしっかり記載されている書籍がおすすめです。
おわりに
どこまで内製にするかは企業の業種や規模によると思いますが、できれば内製の体制を整えられると良いと思います。ソフトウェアエンジニアリングにも当然、納期やコスト、デリバリーなどがありますのでそこの兼ね合いも必要。前述までの諸々が実現できていれば反復的に仮説と検証がしやすい環境になっていると思うのでエンジニアが開発に集中できるはず。
採用について
エンジニアとしての専門性は必要なので、採用する場合は最低でも5年ほど経験し、かつ、IPAの応用情報技術者試験に合格しているのが条件かと(育てる場合は根気良くお願いします)。応用情報技術者試験は試験範囲としてコンピュータサイエンスの知識から情報システムの構築に重要なフォールトトレラントの考えなどや、経営戦略・IT戦略なども幅広くカバーしているため。理想としては試験のために勉強するのではなく、5年ほど経験したら試験慣れのために過去問2、3年分くらい解いて合格できるくらいの教育・学習ができればいいかなと思います。ソフトウェアエンジニアの専門性や信頼、待遇の改善のためにも、IT業界が自主的に「これをクリアしないとソフトウェアエンジニアと名乗れない」という風潮にしていくべきのような気もしますが。
不良資産が多いとビジネス側からの要望による新機能の追加や機能の変更、見つかった問題の修正などなどへの対応速度が遅くなります。エンジニアのやる気も削ぎます。ビジネス側との摩擦も大きくなります。そして離職します。長期的に見れば損失でしかありません。
内製とは少し違いますが、フルタイムでの雇用が難しい場合は、週2-3日あたりで、相談から開発、運用の全体に関わるアドバイザー兼エンジニアやITコンサル兼エンジニア、問題解決型エンジニア、顧問エンジニアとして動いてもらえる業務委託契約ができれば良いのではないか、と。
評価について
ソフトウェアエンジニアリングは不確実性との戦いであり、仮説と検証を反復的に繰り返すものであり、ソフトウェアエンジニアは知識集約型のため評価は難しい(重大な問題を一日掛けて調査して検証した結果、変更されるのはたった一文字なんてこともあるので生産性も計測しづらい)。
ビジネス側への定量的な報告にはDORAの指標が参考にできると思います。あとはシステム全体の稼働率。安定に運用していることを評価するようにすること(障害からの復旧はわかりやすいので評価されやすく、安定運用は目に見えないので評価されにくい)。ただし、各種計測値を評価に使わないこと(「キャンベルの法則[20]」またはグッドハードの法則)。誰だって失敗はするのでミスした場合は人を責めるのではなくミスした仕組みを検証する。ヒューマンエラーが発生しやすいような原因の場合は自動化する、など。
ノーコードツールについて
法律が深く関わる財務や労務などは専門的なパッケージやクラウドサービスのほうがいいですが、そういったパッケージやクラウドサービスと企業内のシステムを組み合わせるような連携システムもできれば内製したほうが望ましい。経験上、データ連携系のノーコードツールを導入すると(当然テキストベースのプログラミング言語に比べて自由度が低いために)「がんばって工夫する」ことが多くなって不良資産となりやすいです。そして手がつけられなくなり、数年後に別のノーコードツールへの移植が発生する(発生した)。システムの発想もそのツール内に閉じ込められてしまうため、ツールが対応していないサービスは人が作業をするままの運用となる(そう言うのに限って深夜作業が必要だったりミスも発生しやすい)。また、ツール提供者はNo Codeと謳うが「No Text Programming」なだけであり、「YES Visual Programming」なためプログラミングの知識や素養が必要です。ビジュアルプログラミングについては前述の人月の神話の「第16章 銀の弾などない」にもビジュアルプログラミングについて懐疑的に書いてあります。
最初に楽をすると後で大変になります。エンドユーザーコンピューティングに夢を見過ぎない。
まとめ
ソフトウェアは「返済すればゼロになる負債(借金)」ではなく「メンテナンスし続けなければ不良化していく資産」です。技術的負債ではなく貸借対照表通りに技術的不良資産と考えることで、会社全体でソフトウェアエンジニアリングに取り組むことができるきっかけになるのではないでしょうか。不良資産から優良資産に変えていくにはエンジニア個人ではなく、組織全体で取り組む必要があると思います。
負債だから仕方ないと責任回避して終わってしまわないように、向き合って資産管理をしていきましょう(自戒を込めて)。
-
【翻訳】技術的負債という概念の生みの親 Ward Cunningham 自身による説明: https://t-wada.hatenablog.jp/entry/ward-explains-debt-metaphor ↩︎
-
UMLモデリング入門: https://bookplus.nikkei.com/atcl/catalog/08/P83580/ ↩︎
-
あなたの話はなぜ「通じない」のか: https://www.chikumashobo.co.jp/product/9784480422804/ ↩︎
-
日本語の作文技術: https://publications.asahi.com/product/17593.html ↩︎
-
顧客と接する際に意識していること: https://zenn.dev/trysmr/articles/ea055a4805535a ↩︎
-
Abc Metric: https://en.wikipedia.org/wiki/ABC_Software_Metric ↩︎
-
Grokking Simplicity: https://www.manning.com/books/grokking-simplicity ↩︎
-
Simple Made Easy: https://www.infoq.com/presentations/Simple-Made-Easy/ ↩︎
-
SimpleとEasyは違う / Simple is not Easy: https://speakerdeck.com/takeru0757/simple-is-not-easy ↩︎
-
ライト、ついてますか: https://www.kyoritsu-pub.co.jp/book/b10011450.html ↩︎
-
いかにして問題をとくか: https://www.maruzen-publishing.co.jp/contents/howtosolveit/index.html ↩︎
-
人月の神話: https://www.maruzen-publishing.co.jp/book/b10111860.html ↩︎
-
データ指向アプリケーションデザイン: https://www.oreilly.co.jp/books/9784873118703/ ↩︎
-
ソフトウェアアーキテクチャの基礎: https://www.oreilly.co.jp//books/9784873119823/ ↩︎
-
レガシーコード改善ガイド: https://www.shoeisha.co.jp/book/detail/9784798116839 ↩︎
-
キャンベルの法則: https://ja.wikipedia.org/wiki/キャンベルの法則 ↩︎
Discussion