スケールとトレードオフ:「Googleのソフトウェアエンジニアリング―持続可能なプログラミングを支える技術、文化、プロセス」を読んだ
いわゆるビックテックの一角として不動の地位を確立しているGoogleの、ソフトウェアエンジニアリングに関するトピックを余すところなく書き詰めた一冊である。
本書はまず、「ソフトウェアエンジニアリングとは何か」から書き出されている(以下に引用)。言葉遣いや用語の定義にうるさい私としては、この構成に非常に好感が持てる。
Google社内でときに言われるのは、「ソフトウェアエンジニアリングとは時間で積分したプログラミングである」ということだ。
1章 ソフトウェアエンジニアリングとは何か
生産的にプログラミングをし続けることができる―書籍のタイトルにもなっている「持続可能なプログラミングを支える技術、文化、プロセス」を確立し改善し続けることが、ソフトウェアエンジニアリングだと言っている。単にコードやシステムを作成するのがプログラミングや開発だとしたら、それらを将来に渡って効率的に継続させる仕組みを考えるのがソフトウェアエンジニアリングなのだ。
プログラミングや開発を継続したとき、すなわち時間が経過すると何が起こるか。一般的には、プロダクトが成長し、組織やチームの規模が増大していく。この際になってもまだ、仕組みが効果的に機能することが重要なのだと本書は主張する。「スケール(する)」や「スケーラブル」というキーワードが頻出することからもそれは分かる。
また、そのような仕組みを構築していく上で、慎重かつ入念にトレードオフを決定していった様子も伺える。ここで改めて書くまでもないが、一般的な問題解決には「銀の弾丸」は存在せず、解決策ごとに長所と短所がある。コードレビュー、バージョン管理、テスト、CI/CDなどの多岐にわたるトピックについて、Google内部で起こった問題と、解決策および考慮したトレードオフが詳細に解説されており、ケーススタディとして非常に参考になる。
あとがきにもある通り、
Googleのソフトウェアエンジニアリングは、大規模かつ発展中のコードベースの開発と保守の方法における、並外れた実験であり続けてきた。
本書を通読すると、Googleのソフトウェアエンジニアリングが並外れていることが理解できる。また、その歴史やノウハウを惜しげもなく公開する行為に、Googleにとっては本書の内容はただの通過点であり、競合他社が真似をしたとしても追いつけないだろうという自信が垣間見えるようにも感じる。
以下は特に印象に残った箇所を引用する。トピックごとにまとめている。
文化
存続期間の長いプロジェクトでは、最初の決定が行われた後に方針を変更する能力があることが不可欠である場合が多い。そして、重要なのは、それが、決定者が間違いを認める権利を有していなければならないのを意味することだ。
1.3.5 決定を再考すること、間違うこと
ここだけでなく、機敏さ (aglie) をもって改善していくことが繰り返し強調されている。
Googleに何年も在籍しているエンジニアでも、やっていることの内容を把握していると感じていない領域が依然としてある。それでいいのた!「それが何か知らないので、説明してくれませんか」と言うことを恐れてはいけない。何か知らないものがあることを恐れるよりは、またとない機会が眠る領域として受け入れよう。
3.4.1 質問を尋ねよ
Googleのエンジニアは無敵なのかと思っていたが、ちょっとホッとする一節である。
組織の文化というものは、ドロドロした人間的なものであり、多くの企業では後付けで扱われるものである。しかしGoogleにおいて我々が確信しているのは、その環境の成果物(例えばコード)にのみ焦点を当てるより、まずは文化と環境に焦点を当てる方が良い結果につながるということだ。
3.7.1 知識共有の文化を養う
成果物よりも文化と環境が優先されるべき。言うは易く行うは難し。
コーディング・コードレビュー
自分という存在と、自分のコードとは別だ。
2.4.3 謙虚、尊敬、信頼の実践
いろいろな記事や書籍で言及されているが、これは大事。
Googleには非常に力強いコードレビュー文化があり、リーダビリティはそのような文化の自然な延長である。リーダビリティは、1人のエンジニアの情熱から始まり、生身の人間である専門家たちがGoogleの全エンジニアをメンタリングするという公式プログラムへと発展していった。
3.8.2 何故このプロセスがあるのか
プログラミング言語ごとにリーダビリティをチェックする担当が存在する。また、コードごとにそのオーナーが存在する。レビュープロセスでは、これらのメンバーによるレビューが通ってはじめて、PR(GoogleではCL: Change Listと言うらしい)がマージできる。こうすることで、コードの可読性が担保されるとともに、誰がオーナーか分からないコードが生まれにくくなる。
「小さな」変更とは通常、約200行までのコードに限定されるべきだ。
(中略)
Googleでの変更の大半は、約1日以内にレビューされることが期待されている(これはレビューが1日以内に終わることを必ずしも意味せず、最初のフィードバックが1日以内に提供されることを意味している)。
9.4.2 小さな変更を書け
PRの大きさ、レビューのレスポンスの早さの参考に。
変更説明というものは、1行目に要約としてその変更がどんな種類のものかを示すべきだ。
(中略)
最初の行は変更全体のようやくとなるべきだが、何が変更されているのか、そして何故変更されるのかの詳細についても説明が及ぶべきである。「バグ修正」という説明があるだけでは、レビュアーや、将来のコード考古学者にとっては助けにならない。
9.4.3 良い変更説明を書け
テスト
我々は上記のように区別しており、もっと伝統的な「ユニット」または「インテグレーション」の区別は用いていない。その理由は、我々がテストスイートに望む最も重要な特性は、テスト範囲とは無関係に、速度と決定性 (determinism) だからである。
11.2.1 テスト規模
Googleではテストを規模に応じて(特大・)大・中・小に分類している。確かに言われてみれば、「ユニット」と「インテグレーション」の区別を鵜呑みにしていたが、そうではない区別も考えられる。
信頼不能性が1%に接近すると、テストは価値を失い始めるということだ。
11.2.1 テスト規模
信頼不能なテストとは、非決定性要素によりたまに失敗するテスト。
何故、テストを書くことを命令として強制するところから始めなかったのだろうか。 テスト小グループは、テストに関する命令を出すようシニア幹部陣に求めることを検討したが、すぐにそれは行わないことに決めた。コードの開発方法についての強制は、どんなものであろうが、Googleの文化に真っ向から逆らうものであると同時に、おそらく進歩を鈍化させるものだ。それはどんな思想が強制されるかに関係ない。成功する思想は広まるものであるというのが我々の信念であり、したがって専念するべき点は、成功を実証してみせることとなった。
11.4.4 今日のテスト文化
文化の醸成についての良い示唆。強制するのではなく、試させて価値を感じさせてはじめて根付く。
・テストダブルより本物の実装が優先されるべきである。 ・テスト内で本物の実装が利用できないなら、フェイクが理想的な解法である場合が多い。 ・スタビングを使いすぎると、不明確で脆いテストにつながる。
13.10 要約
自分の場合、テストではすぐにモックを使う傾向にあるが、本物を使ってしまう方が良いとのこと。
ドキュメンテーション
Googleで最も成功を収めている取り組みは、ドキュメンテーションをコードのように扱うとともに、伝統的なエンジニアリングのワークフローへ組み込むというものであり、エンジニアが単純なドキュメントを書いて保守するのを楽にしている。
10章 ドキュメンテーション
「コードのように扱う」というのは良いやり方。具体的には次の通り。
Googleが取っているアプローチは、C++のAPIはそのリファレンスドキュメンテーションをヘッダーファイル内に存在させておくのがふさわしい、というものだ。他のリファレンスドキュメンテーションもまた、直接Java、Python、Goソースコードに埋め込まれている。
10.5.1 リファレンスドキュメンテーション
また、wikiベースのドキュメンテーションをしている組織は多いだろうが、Googleもかつてはそうだった。しかし、スケールの途中で問題が発生している。おそらく、多くの方にも見覚えのある光景なのではないだろうか。
wikiドキュメントには真のオーナーがいないため、多くのドキュメントが廃れていった。新ドキュメント追加に関するプロセスが施行されていなかったため、重複したドキュメントやドキュメント集が現れ始めた。GooWikiの名前空間はフラットで、誰もドキュメンテーション集をうまく階層化できなかった。
10.3 ドキュメンテーションはコードのようなものである
ランディングページ(ポータル)の存在が重要であるとも主張されている。
要は、ランディングページが必ず目的を明確に特定しているようにし、それからさらなる情報を得るための他のページへのリンクのみを含めるようにするのだ。もしランディングページ上で交通整理の警官以上のことをやっているものが何かあったら、そのランディングページは本来の仕事をしていない。
10.5.5 ランディングページ
バージョン管理
Googleでは、Piperと呼ばれる独自のVCSを利用している。GitHubのようなVSCとの大きな差異は、リポジトリのディレクトリやファイルごとにオーナーシップの概念が取り入れられていることのようだ。
Googleでは、VCSを掌握することで、オーナーシップと承認の概念をより明示的にすることができている。またその概念を、コミット操作の試行中ははVCSによって強制できる。
また、依存するコンポーネントやライブラリのバージョンを選ぶことができない。とんでもない話に思えるが、解説を読むと納得がいく。
「単一バージョンルール」は、組織の効率にとって驚くほど重要である。どこにコミットすべきか、あるいは何に依存すべきかについての選択の余地をなくすことで、著しい単純化を結果として得ることができる。
16.7 要約
CI
・CIシステムは、どんなテストを利用するべきか、またいつ利用すべきかを決定する。
(中略)
・CIは、早くて信頼性の高いテストがリポジトリー提出前に配置され、遅くて決定性の低いテストがリポジトリー提出後に配置されるように最適化されるべきである。
23章 継続的インテグレーション 23.4 要約
CIの勘所がよくまとまった要約。
CD
技術の状況が移り変わる速さと予測不可能性とを前提とすると、あらゆる製品にとって、競争的優位とは、迅速に市場への投入ができる能力の中に存在するものである。
24章 継続的デリバリー
リリーストレインと呼ばれる一定周期でのリリース作業が行われ、いかなる理由でもこれは延期されない。
リリースの責任の1つは、製品を開発者から守ることである。 トレードオフを行う際に、開発者が新機能をローンチすることについて感じる情熱と切迫感が、既存製品のユーザーエクスペリエンスに勝ることは、決してありえない。
24.7 チームの文化を変える:デプロイに規律を組み込む
コンピュート環境
データセンターの拡大は複雑な手動のプロセスで、特化したスキルセットを要し、(全マシンを用意した時点から)何週間もかかるので、内在的なリスクがあった。それにもかかわらずGoogleが管理するデータセンターの数が増加していることが意味するのは、データセンターの拡大が人間の介在を要しない自動プロセスとなっているモデルへGoogleが移行したということだ。
25.1 コンピュート環境を手なづける
「データセンターの拡大が人間の介在を要しない自動プロセスとなっている」というのは、とてつもない話だ。
マネジメント
マネジメントの仕事の定量化は、作ったウィジェットの数を数えるより難しい。だが自分のチームが満足かつ生産的でいられるようにすることは、マネジメントの仕事の重要な尺度である。とにかく、バナナを育てているのに林檎を数える罠に落ちてはならない。
5.2.1 恐れるべき唯一のものは……えっと、全てだ
管理職のみなさま、なにとぞ。
障害を取り除く助けになる答えの全てを知っている必要はないが、答えがわかる人々を知っているとたいてい役立つ。
5.5.4 障害を取り除け
人脈を作っておく意義。
このプロセスには3つの主なステップがある。まず、目隠しを特定しなければならない。次に、トレードオフを特定しなければならない。それから、決定を行って解法を反復しなければならない。
6.1.1 飛行機の比喩
ここでも「解法を反復」とある。一度決めたやり方は定期的に見直す。
よくある誤りは、チームに一般的問題ではなく特定製品を担当させることだ。
6.2.2 問題空間の分割
本当によくある誤り。視野を狭窄させてしまうだけでなく、モチベーションも下げる恐れがある。
つまり自分しかできない決定的に重要なものを意識して識別し、それらに完全に専念すべきだ。他の80%を落とすことを自身に明示的に許可しなければならない。
6.3.3 ボールを落とすことを学べ
改善のための計測
その利害関係者がそのデータを使わないのであれば、その計測プロジェクトは常に失敗だ。計測結果に基づいて具体的決定がなされるであろう場合にのみ、ソフトウェアプロセスの計測を行うべきである。
7.2 トリアージ:そもそも計測するほどの価値があるか
文章にしてみれば当たり前のように読めるが、これを守れていない計測もよく見かけるような…。