プロダクト開発に利用する技術の選択は、不確実性を伴う決断であることが多いです。
私はROUTE06で働く前は個人事業主でした。仕事の多くは、新規プロダクトのプロトタイプや初期バージョンの作成でした。デザインを含めてプロダクト開発をするのは私一人だったので、おおよその要件とスケジュール、予算が合意できたら、作り方は任せてもらっていました。
当時、私が技術を選択する方法は「開発速度や品質に非線形の変化を与える可能性があると感じたらまずは使ってみる」でした。アルファ版*1でもとりあえず使ってみて、上手くいったらそのまま本番稼働させているプロダクトもあります。 足りてない機能や不具合に直面することもありますが、パッチを書いたり開発元にプルリクエストを送りながらプロダクトの開発も進めていました。この進め方は、開発者が一人であれば成果を出せますが、チームで大きな成果を出すのは難しいでしょう。
現在、私はROUTE06のテックリードをしており、チームで大きな成果を出せる技術を選択することが求められています。そこで、技術選定のプロセスに、マイケル・A・ロベルト『決断の本質』*2で述べている合意に関するアイデアを取り入れてみているので今回はその紹介です。
隙を生じぬ二段構え
チーム開発における技術選定では、チームメンバーとの合意(コンセンサスともいう)が重要です。合意について、『決断の本質』から一文を引用します。
コンセンサスには重要な要素が二つある。それは、決定された行動方針に対する高度のコミットメント、およびその理論的根拠に対する強固な共通の理解である。
マイケル・A・ロベルト/『決断の本質』
私はこの文章を読んだ時、『るろうに剣心』という漫画に出てくる「隙を生じぬ二段構え」という戦術を思い出し、とても腑に落ちて理解できました。この戦術は、Aプランがダメだった時のBプランという意味での二段構えではなく、一撃目で生じる隙を埋めるための二撃目。私はこの考え方が好きでいろいろなところで引用しているのですが、マイケルの主張も遠からず通じていると感じました。
コミットメントが重要ということは、多くのソフトウェアエンジニアやプロダクト開発に関わる人の共通認識でしょう。ただ、コミットメントが具体的にどういう状態なのかは、人によって解釈が多少異なっており、認識がずれる隙があると思っていました。その隙を埋めるのが「その理論的根拠に対する強固な共通の理解」です。
また、マイケルはこの状態を作るために必要なものは「決定内容の質の高さ」ではなく、「質の高い意思決定のプロセス」だとも述べています。『決断の本質』では、多くのプロジェクトを分析した結果、失敗した意思決定が行われた時の共通点を見つけています。リーダーは最善の選択をすることに気を取られてしまい、一歩下がって意思決定のためにとるべき「正しいプロセス」を定めようとしていなかったようです。
では、「正しいプロセス」はどのように定めればいいでしょうか。プロジェクトの状況やチームメンバーによって変わるものだとマイケルは述べていますが、最初の一歩を踏み出すには、もう少し足がかりが欲しいですね。
ここで、トム・ニクソンが『すべては1人から始まる』で紹介している「コンセンサスの死」という状況を見てみたいと思います。少し遠回りになりますが、過去の失敗から学ぶべきことはたくさんあります。
コンセンサスの死
『すべては1人から始まる』からコンセンサスの死について述べられている文章を引用します。
これは、できるだけ多くの人の意見を聞いて、誰もば合意するような結論に至ろうと際限なく議論を続けてしまう状態だ
トム・ニクソン/すべては1人から始まる
この文章の手前には、「トップダウン型の意思決定はうまくいかない。」ということも書かれており、私の推測ですが、おそらくトップダウン型の組織を参加型の組織に変えようとしたリーダーが陥りがちな状態なのだと思います。
というのも私は高校生の頃、吹奏楽部の部長をしていたのですが、それまでトップダウン型だった組織を参加型の組織に変えようとし、たくさんの失敗をしました。その一つがここで言われている「コンセンサスの死」でした。部員一人ひとりの意見や不満に耳を傾け、いいチームにしたかったのですが、真逆のことを言う部員がおり、全員が賛成する状態を作ることはできませんでした。
少し残念な気持ちはありますが全員の望みを叶えることはできません。そしてテックリードが叶えるべきはプロダクトとプロジェクトの成功です。そのために力を行使する必要があります。この辺りの話は、以前のブログ*3でも紹介しているので興味がある方はお読みください。
さて、どうしていきましょうか。私は文章を書いています。色々本を読んで、考えた結果、たくさん、細かく、具体的な文章を書いてPull requestを作っています。
理論的根拠に対する強固な共通の理解を作るためのADR
私のチームは、私がテックリードになる前から、技術選定の経緯や結果をドキュメントとして残すADR*4が実践されていました。新しくチームに参加した人から「素晴らしい」や「助かる」といった声を聞くのでこれは十分に機能しているでしょう。
しかし、私はADRにはもっと多くのことを表現できる可能性があると考えており、具体的にはADRで「理論的根拠に対する強固な共通の理解を作る」ことはできないか試しています。そして、ADRをPull requestにして、レビューで議論し、最終的にコミットメントできる場合はApproveしてもらうことで、マイケルの「決定された行動方針に対する高度のコミットメント、およびその理論的根拠に対する強固な共通の理解」を実現することができると考えています。
ADRを書くという行動はこれまでと変わらないのですが、目的がこれまでより明確になったことで内容や表現は少しずつ変わってきました。いくつかこの方法でADRを書いてみて、理論的根拠に対する強固な共通の理解を促すADRの書き方のポイントがわかってきたので3つ紹介します。
1. 自分の主張を決める、反論を恐れず言い切る
複雑な要件のプロダクト開発において、何かしらの技術的な決断が必要な時に、必要な情報が揃っていることは稀で、不確実性を抱えた状態で意思決定をする必要があります。そんな時は、ADRで決定した内容以外にも色々な方法があることを付け加えたくなります。
それらは検討の経緯として列挙されていると検討状況がわかるので良い情報ですが、自分の主張は簡潔に言い切るべきです。その結果レビューで否定されることもありますが、そうした議論の中で共通の理解が醸成されます。
2. できないこと(制約・リスク)を具体的に書いて、許容できるかを判断してもらう
あるライブラリを使うことでUIを実装する工数が大幅に削減できるが、UIのデザインやレイアウトの自由度が少し下がるような状況を想像してください。ADRに「自由度が少し下がる」と書くのは不十分でしょう。書くべきなのは、実際にUIを作るときにどういったことができなくなるのかの具体的なイメージです。ベストなのはUIのイメージ図があることだと思います。
できないことの理解がずれていると、後から大きな問題になることがあるので、特に隙が生じぬように気を付けたいですね。
3. 少し頑張って綺麗な図を書いた方がいい時もある
UIに関係する場合はイメージ図があった方が良いという話をしましたが、それ以外にもディレクトリ構成やプロダクトのライフサイクルなど言葉だけで読んだ人が具体的な状態を想像するのが難しい場合は図を用意することで共通の理解の助けになります。
Next.jsのApp routerは文章だけではなかなか理解できないので、ドキュメントにはたくさんの図があり、参考になるかと思います。
ようは、意思決定した後に起きる具体的な状態を簡潔に表現することが重要なのだと思います。
まとめとおまけ: 全員まとめて意図を知る
私が現在、チーム開発の技術選定の方法として試しているものを紹介させてもらいました。似た状況に対峙している方に何かしらきっかけを与えられたら幸いです。
最後に、チームの状況によって「決定された行動方針に対する高度のコミットメント、およびその理論的根拠に対する強固な共通の理解」を実現する手段は色々あるということを説明するために、『桜井政博のゲームを作るには』で取り上げられていた「全員まとめて意図を知る」という方法を紹介します。
このチームは、様々な背景を持った文化の違うメンバーで構成されており、従来の進め方ではうまくいかなかったので「関係するチームメンバーを全員集めて話をする」ようにしたそうです。チームメンバーの拘束時間を増やすので無駄が多いように見えますが、意図を含めたより深い理解を得ることで、仕様や表現に迷った時目指すべき方法が職種を問わずわかる状態を作れたそうです。
プロダクトの状況やチームの特性をよく見て、迷いなく開発できる状態を作っていきたいですね。
*1:プロトタイプ段階、本番利用にはリスクがある状態
*2:英治出版 マイケル・A・ロベルト『決断の本質』 http://www.eijipress.co.jp/book/book.php?epcode=1094
*3:『チームのアウトプットを最大化し、チームメンバーが迷いなく前向きに開発できるようにリーダーがやるべきこと』内の「寛容でありながらも毅然とした態度でのぞめ」 https://tech.route06.co.jp/entry/2023/04/27/090226
*4:Architecture Decision Records, https://github.com/joelparkerhenderson/architecture-decision-record
*5:https://nextjs.org/docs/app/building-your-application/routing#component-hierarchy