「0→1」フェーズにおける技術的負債との向き合い方
以前から「スタートアップのなかで『技術的負債』というものをどう扱うべきなのか」というテーマに対して関心が高かったのだが、今年の6月から「0→1」の新規事業に関わるようになって、自分の中でなんとなく考えがまとまりそうなので、雑に吐き出してみる。最近、社内でも「技術的負債」が話題にあがることが多く、その中で同僚のエンジニアからあがった意見も参考にしている。
そもそも技術的負債とは
@t_wada さんの次の記事に答えが書いてある。
【翻訳】技術的負債という概念の生みの親 Ward Cunningham 自身による説明 - t-wada のブログ
個人的には次のように解釈した。
- 「手を抜いた雑なコード」は技術的負債とは呼ばない。それはただの低品質なコードである
- 仮説検証や経験からさまざまな学びを得ることは正義
- そこで得た「学び」と「現状のソフトウェア」とのギャップを「技術的負債」と呼ぶ
このような「学びから生まれる技術的負債」に加えて、仮説検証を最速で行うために(あとで返済する前提で)わざと作り出す「計画的な技術的負債」と呼ぶべき類の負債もあるように思う。
いずれの負債も基本的にはポジティブに捉えてよいと考えている。「学びから生まれる技術的負債」はそれだけ多くの学びを得ているということだし、「計画的な技術的負債」もそれによって仮説検証を加速させることができるからだ。
難しいのは、そのようにして生まれた技術的負債を「いつ」「どのように」返済していくかということだ。
これらの技術的負債のほかに、特定の顧客からの要望やビジネス上のやんごとなき事情によりプロダクトに組み込まれた「大人の事情による負債」というのもありそうだが、こちらはあまりポジティブに捉えるべきではないように思う。それらの対処法にも興味はあるが、「0→1」フェーズでは発生することは考えにくいため、この記事ではスコープ外とした。
「0→1」フェーズにおける技術的負債
「0→1」フェーズでは必然的に「技術的負債」が大量に生まれやすい構造になっている。
まず「0→1」フェーズについて整理しておく。現在所属している Ubie株式会社では、事業フェーズを次のように定義している。
(ちなみにUbieは、担当するフェーズごとに「Ubie Discovery」と「Ubie Customer Science」という2つの組織に分かれている。私は 「0→10」を担う「Ubie Discovery」に所属している。)
「0→1」フェーズでは、PSF(Problem/Solution Fit)を目指す。PSFとは、ユーザーが抱える課題(= Problem)を発見し、それらを解決する「MVP(Minimum Viable Product)」(= Solution)が特定できている状態である。
言い換えると、「仮説はある。だが実際はどうなのか、何もわからん」状態から、仮説検証を何度も繰り返し、そこから学びを得てユーザーの課題やプロダクトのあるべき姿を探っていくフェーズである。
「新たな学びを得ること」こそが「0→1」でやるべきことなので、多くの「学びから生まれる技術的負債」が発生するのは当然であり、健全に検証サイクルが回っている証とも言える。また、いかにすばやく仮説検証が繰り返せるかが重要になってくるため、「計画的な技術的負債」も効果的に利用していきたいところである。
とはいえ、技術的負債は必ず「返済」する必要がある。「学びを得ることは正義」とはいえ、なんでもかんでも負債として抱えると、のちのち返済に苦しむ未来は容易に想像できる。また、積み上がった技術的負債によって、仮説検証のスピードが落ちてしまっては本末転倒である。
したがって、生み出される負債の量をうまくコントロールする必要がある。
どのように技術的負債を取り扱うか
「学びから生まれる技術的負債」の場合
「学び、学び」と書いているが、プロダクト開発をしていると様々な種類の学びが得られる。
- 新たに獲得したドメイン知識
- ユーザー調査などから発見した解決すべき課題
- その課題を解決するための新たなソリューション
- アーキテクチャに関するベストプラクティス
- ライブラリやフレームワークのAPIや機能に関する知見
- コードレビュー、勉強会、SNSなど様々な経路を通じて知った「もっといいコードの書き方」
- シャワーを浴びながらひらめいた実装アイディア
もっとたくさんあると思うが、次の2つに大きく分けられそうである。
- 仮説検証による学び
- エンジニアリングに関する学び
前者の「仮説検証による学び」は多ければ多いほどよい、というのは自明だろう。
後者の「エンジニアリングに関する学び」は、エンジニアとしての成長を意味するのでよいことではあるのだが、「0→1」フェーズにおいては、そこから生まれる技術的負債が、仮説検証を妨げる要因になりがちではないかと感じる。
ソースコードの品質が低すぎると、バグフィックスに追われてそもそも検証が進まないというのは想像しやすい。
例えば、安易な例だが「使ったことはないけど、このフレームワークは流行ってるし今回の要件に向いてそうなので採用!」というような意思決定は、仮説検証による学びよりも、新しい技術を使うことによる学び(とそこから生まれる技術的負債)に多くの気を取られてしまうためリスクが高い。すでに利用実績があって、知見が溜まっているものを選択したほうがよいだろう。
(では「手に馴染んだ枯れたフレームワーク」を採用すればよいかというと、「0→1」に成功してその先のフェーズに進んだときに「時代遅れのフレームワーク」になっていて、世の中に広まっている新たなベストプラクティスを採用しづらい状況になっている、というようなこともありうるので難しい。)
また、「0→1」フェーズでは細かな単位で「作っては捨て、作っては捨て」を繰り返す。未熟なアーキテクチャや全体設計になっていると、一回一回の変更に時間がかかってしまう。経験を積むことでよりよい設計が見えてくることも当然あるが、最初から仮説検証のスピードを維持するためには「ある程度の安定性はありつつ変更も加えやすいようなアーキテクチャ」といったものを初期の段階からしっかりと組めるに越したことはない。
(が、初期構築に時間をかけすぎると、そもそも仮説検証をスタートできないので、こだわりすぎるのもよくない。難しい。)
「技術力が高くなければ『0→1』の開発はするべきではない」と言うつもりは毛頭ないし(そんなことを言えば自分にブーメランが返ってくるだけだ)、たとえ何かを妨げる結果になったとしても、何かしらの学びを得ることはそれ自体尊いことだと思う。
しかし、特に「0→1」フェーズに限って言えば「エンジニアリングに関する学び(とそこから生まれる技術的負債)」は、極力小さくなるようにコントロールするべきではないだろうか。(別の言い方をすれば、エンジニアリングに関する不確実性は、できるだけ小さくしておくほうがよい。)
「計画的な技術的負債」の場合
「計画的な技術的負債」というのは、例えば「将来的には自前のバックエンドが必要になりそうだけど、今はひとまず SaaS で検証を進める」とか、「このコンポーネントは共通化できそうな気がするけど、そもそも検証したら要らなくなるかもしれないし、いったんコピペで対応する」といったものをイメージしている。
「計画的な技術的負債」に関しては、仮説検証を加速させるブースターのような役割があるので、積極的に利用したほうがよさそうだ。
ただし負債としてたまり続けると、腐臭を漂わせることになるので、返済することは絶対に忘れるべきではない。
「計画的な技術的負債」の場合は「学びから生まれる技術的負債」とは違い、それを積んだ背景やコンテキストが明確で、返済すべき条件やタイミングがあらかじめ想定できているはずだ。したがって、ADRやTODO
ファイル、コメントアウトなど(フォーマットは何でもよいが)記録を残し、いつでも確認できるようにしておくことが大切だろう。
また、「返済のしやすさ」もある程度考慮したうえで負債を積むこともできるはずである。
例えば「自前のバックエンドにデータを移しやすいような SaaS を選定する」とか、「フロントエンドのインフラストラクチャ層でデータアクセスを抽象化しておいてバックエンドのリプレイスの影響を受けにくいようにしておく」とか、「共通化しそうなコンポーネントは名前のプレフィックスを合わせる」とか、やれることはたくさんある。
さいごに
あくまで個人的な経験から得た「学び」をまとめたものである点はご了承ください。みなさんの意見も聞かせてもらえると嬉しいです。