技術的負債が生じるメカニズムとその返済プロセスについて
スタートアップを創業する友人から、
初期プロダクトのアーキテクチャに関して相談を受けることが割とあります。
しかし、特に開発初期においては、データベースに保存されているデータと、アプリケーションで扱うドメインモデルが完全に一致していることが多く、経験的にアーキテクチャは、あまりに変なことをしていなければ、ほとんど問題にならないと感じています。
一方で、ある程度開発が進み、アプリケーションの複雑性が増してくると、データとドメインモデルの間に差分が生じてくることが多く、不文律によって維持されているアーキテクチャの曖昧さと、その曖昧さが生み出す複雑性が開発のボトルネックになっていきます。
どのようなエンジニアであっても、過去に技術的負債が蓄積したソフトウェアを触った経験があると思います。一方で、それが生み出されていく過程については解像度が低いことも多く、自分が 0 から作っていれば避けられたものだと感じている方も多いかと思います。いざ自らがプロダクトオーナーになり、プロダクトを作っていくタイミングでは、将来的に生じうる技術的負債をできるだけ初期から潰しておきたいと感じるのは理解できる話です。しかし、この努力は割と無駄で、無理な話だと感じています。
この記事では、自分の経験から、技術的負債が生じてきたメカニズムと、それを乗り越えるにあたって必要だった知識や実践をまとめていきます。
技術的負債が生じたメカニズム
自分が開発をしてきた中で、技術的負債が生じる理由は主に二つありました。
- ドメインモデルとデータのずれ
- 機能改善 << 新機能開発
ドメインモデルとデータのずれ
導入でも少し触れましたが、開発初期に想定していたアプリケーションのユースケースが顧客ニーズを満たすために必要十分であることは滅多にありません。初期開発の時点で行なっていた工夫が全く的外れで、使われないデータが残っていたり、逆に顧客の求めるワークフローに対応するには、全くデータが足りなかったりします。
業務システムを提供するサービスであれば、業務オペレーションは顧客ごとに微妙に異なっているため、多くの顧客と話をするごとにドメインモデルはより汎用的なものに修正されていきます。一方でデータは、ハードウェアに束縛されているため、そこまで柔軟に変更することはできません。
もちろん余裕があれば、ドメインモデルとデータの差分を吸収するレイヤーを用意することはできますが、初期開発のタイミングで、ほとんど一致しているモデルの詰め替えを行うレイヤーを用意することは、かなりの無駄であり、必要性を意識することは難しいでしょう。惰性で行なってしまうと、差分を吸収するという責務を維持することは困難になっていきます。実際、差分を吸収した後のドメインモデルですら信頼性が高くはないため、不必要かつ早すぎるアーキテクチャの最適化だと考えられます。
機能改善 << 新機能開発
スタートアップは死ぬ前に売上を上げなくてはなりません。
そのためにはお金を払ってくれる顧客を獲得することが必要で、弱い立場のスタートアップとしては、まだサポートしている機能の少ないサービスを導入していただくために、顧客のニッチな要望に応えることで積極的に導入理由を作っていく必要が生じます。エンジニアのリソースが限られている中で、すでにうまく動いている機能のリファクタリングに時間を割くことはなかなかできません。
技術的負債の返済を開始するシグナル
上記のように徐々に技術的負債が蓄積していくわけですが、返済にすぐにコストを割くことはできません。最初に行う負債の返済には、ドメインモデルの整理やそれに伴う全体的なアーキテクチャの刷新が必要になることが多く、ある程度の期間を要し、短期間での返済はほとんど不可能です。また、複雑化したドメイン知識を紐解く必要があるため、新規にエンジニアリソースを獲得しても、開発速度は上がりません。負債を作った本人が地道に返済をしていく必要があります。
その際、プロダクトが以下のような条件を満たしている必要があると考えています。
- 既存機能で新規顧客が獲得できている状態
- ビジネスサイドのオペレーション改善によって、線形成長が加速している状態
既存機能で新規顧客が獲得できている状態
いわゆる一種の PMF が達成されている状態です。
ある程度の一般性を持って顧客の事業課題を解決できている状態であり、一定の期間を要する技術的負債の返済作業に耐えうるだけのプロダクトを作れている状態です。この状態になっていないプロダクトであれば、コストをかけて負債を返済するだけの価値がまだない可能性があります。
ビジネスサイドのオペレーション改善によって、線形成長が加速している状態
負債の返済作業の期間中に、プロダクトの提供価値を上げられるのは、ビジネスサイドの介在価値によるものです。事業成長をし続けなくては、組織のモメンタムが維持できなくなっていきます。ビジネスサイドが独立して事業成長を牽引できる状態になっていないのであれば、技術的負債を返済している最中にモメンタムが完全に失われてしまう可能性があります。
技術的負債を返済するにあたって最も重要なこと
さて、ここまでの条件を揃えることができたとして、最大の関門は技術的負債の返済に着手することです。
自分は経営者という立場でもあったのですが、目の前に存在するあまりにも大きな負債に対し、さまざまに理由をつけて逃げの選択肢を考えていました。「今の自分の知識があれば、こんな負債は作らずに済んだのに、、、。」ビジネスモデル的にも技術的にも、負債が生じており、最初からやり直したい衝動に駆られ、ピボットの誘惑がちらつきます。
しかし断言します。
ピボットしてもうまくいきません。
自らが作り上げた負債の解消を行えないとすれば、今の知識で行う新たなチャレンジも、負債を積み上げた段階で途中で投げ出すことになります。結局は気持ちの問題です。どのようなドメインを選び、どのようなプロダクトを作ったとしても、必ず初期のドメイン知識が浅い状態での意思決定の負債は積み上がっていきます。過去の尻拭いをすることは、プロダクトを通して大きな価値を作るためには絶対に避けては通れないものです。腹を括って、全力でコミットしましょう。
技術的負債の返済のロードマップ
さて、ここまでで技術的負債の返済に取り組む覚悟ができているはずです。
また、プロダクトは、少なくとも現在のターゲット顧客に対して必要十分な機能を備えています。
技術的負債の解消によって達成すべきことは、突き詰めれば、「エンジニアのオンボーディングコストを低減すること」に尽きると考えています。
どこに何が書かれているのか、何を見ればどんなドメイン知識が学習できるのか。
暗黙的な依存関係を排除し、これらを明確に定義することは、開発速度を高め、アプリケーションの信頼性を高めます。
ここからオンボーディングコストを下げるリアーキテクチャリングの具体的な手順について検討していきます。
自分はこのような手順で負債の解消を進めました。
- データとドメインモデルを分離する
- 手続的な処理の階層を浅くする
- バックエンドから View モデルを返せるようにする
データとドメインモデルを分離する
まずは、暗黙知化しているドメイン知識をデータと紐づけて学習ができる状態を作ります。
具体的にはデータベースに束縛されたデータと、アプリケーションで利用するデータとの間に境界を引きます。データには変換レイヤーで適宜加工を加えたり、データを解釈する関数を定義していくことで、どのデータがどんな知識を持っているのかを整理していきます。
この作業を行うことで、アプリケーションで扱うデータそのものが秘匿化され、データは抽出したい情報に対するソースとして理解できるようになります。結果的に随所でデータのプロパティに直接アクセスして処理を行うような、ビジネスロジックの分散を防ぐことができるようになります。
手続的な処理の階層を浅くする
次に、ネストが深くなりがちな処理のレイヤーを浅くしていきます。
テクニックとしては、処理に必要なデータを DB やユーザーから取得するモジュールと、取得されたデータを使って実際に処理を行うモジュールに分離すると良いでしょう。このように設計をすることで、特定の処理に必要なデータが何であるのか?それぞれのデータはどんな知識を持っているのか?といったドメイン知識を処理レイヤーから学習することができるようになります。
必要なデータがあらかじめ示されていれば、新規に獲得したエンジニアがアサインされたタスクごとに必要最小限の知識について学習するだけでタスクをこなしていけるようになります。
バックエンドから View モデルを返せるようにする
最後に、フロントエンドに散らばってしまったビジネスロジックをバックエンドに集約していきます。
すでにある程度ビジネス要件が明らかになっているため、フロントエンドの要求に従って、適切な View モデルをバックエンドで用意してあげることが可能になっているはずです。
バックエンドがビジネスロジックの Single Source of Truth となるように、解釈済みのデータをフロントエンドに返してあげられるようにしましょう。
最後に
ここまで色々と書いてきましたが、結局伝えたいことは 2 つです。
- 技術的負債は必ず生じうるということ
- 技術的負債の解消には、リーダーの覚悟が最重要だということ
自分は、CEO 兼 CTO という立場で、プロダクト自体の提供価値が短期的には上がらないが、ものすごく大変な技術的負債の解消というタスクの前で、かなり足踏みをしてしまいました。
結果的には、
- 自分よりも遥かに経験豊富な経営者が、技術的負債の解消を当然生じる問題として話してくれたこと
- 昨年のインボイス制度の導入によって、法律的に決済基盤の対応が必要になったこと
以上の二つがきっかけとなって、なんとかプロジェクトを進めてくることができました。
このプロジェクトを開始する前から、常にアラートを出し、プロジェクトが開始してからも一緒にやり切ってくれたエンジニアメンバーにも本当に頭が上がりません。
また、開発経験が豊富なエンジニアが新しくジョインしてくれて、希望的観測が支配的になっていてうまく進んでいなかったプロジェクトマネジメントを、忖度なくスケジュールを切ってガシガシを進めてくれたことがこのプロジェクトをやり切れた大きな要因になっています。
ビジネスサイドも、技術的な支援に工数を割くことが難しい中、速度を緩めることなく事業成長を牽引してくれていたことも非常に大きな要因でした。
結局は、困難を乗り越えられるようなチームで、困難を乗り越えるに値するプロダクトを作っていくことが重要だということです。
ちなみに、実は今はこのプロジェクトの最終テスト段階なのですが、技術的負債の返済のプロジェクトがひと段落したタイミングの連帯感と、次に着手できることへのワクワク感は何にも勝る快感です。それを楽しみに勇気を持って困難にぶち当たってみてください。
そしてもし、綺麗になったアーキテクチャで、一緒に価値を作っていってくださるエンジニアの方がいらっしゃいましたらご連絡お待ちしています。
Discussion