カテゴリー
コンピューター 文化

📖 読書感想文1『Googleのソフトウェアエンジニアリング―持続可能なプログラミングを支える技術、文化、プロセス』Titus Winters、Tom Manshreck、Hyrum Wright 編、竹辺 靖昭 監訳、久富木 隆一 訳 https://amzn.to/3YrMBEn

本を手に取るまで。なぜこの本を選んだか

この本の前に、『単体テストの考え方/使い方』Vladimir Khorikov https://amzn.to/3BCLytq を読みました (📖 読書感想文『単体テストの考え方/使い方』Vladimir Khorikov https://amzn.to/3BCLytq – oki2a24) 。そのきっかけとなった次のページに、大きくではないが別の本の紹介もあったのです。

  • 自動テストの種類の曖昧さが少ない「テストサイズ」という分類 スコープとの掛け合わせでわかる“コスパの良いテスト” – ログミーTech https://logmi.jp/tech/articles/329184

そういった時に、これはGoogleから始まったんですが……。具体的には『Googleのソフトウェアエンジニアリング』という本の中で説明されているんですけど。

ここから、今回の本に興味を持ちました。

本を手に取る前に、評判や感想を調べてみる

の検索結果より。

  • Book Talk:『Googleのソフトウェアエンジニアリング』をぼくたちはこう読んだ!(前編)|グロービス・デジタル・プラットフォーム https://note.com/globis_engineers/n/n806de3681b45

    大きく、ぶ厚く、重く、そして内容が濃密すぎ

    読書の仕方を考えた方が良さそう。部分的に読むのが良さそう、と思った。

    章ごとの「要約」を読んでいって、印象的だった部分をピックアップしてみようか。

    要約をピックアップ、読む章を限定する、のが良さそう。

    第2章から第7章が「第2部 文化」としてまとめられているね。

    じゃぁ1章は概要とかはじめになんだろうから、ここは読んだら良さそうと思った。

  • Googleソフトエアエンジニアリング 読書メモ https://zenn.dev/keita69/articles/20220115-book-google-software-engineering

    • 全体の感想と小さな要約が得られる。良い。
  • [書評] Googleのソフトウェアエンジニアリング ~持続可能なプログラミングを支える技術、文化、プロセス|重盛 雅人 https://note.com/happyodangoo/n/ne5e69c9ff1e0

    • もうちょっと長い要約とまとめ、ポイントがリストアップ、図化されている。これも良い。
  • 「Googleのソフトウェアエンジニアリング」でわかるリファクタリングと自動テスト #テスト – Qiita https://qiita.com/miketako3/items/3085e225a35cdf89cd55

    • リファクタリングの章はあったっけ?と思って目次を見てみたが、無い。一部の見出しにはあったので、本内部を横断的にリファクタリングを抽出してまとめたのだと思う。良い。
  • Googleのソフトウェアエンジニアリング – はじめに https://zenn.dev/voicy/articles/8380830d24b0f1

    • 本書を読む目的と、楽しみ方が書かれていて、良い。参考になる。
  • ソフトウェア開発の共通言語をチームで持つために「Googleのソフトウェアエンジニアリング」勉強会をしました – Classi開発者ブログ https://tech.classi.jp/entry/2022/12/21/183000

    • 勉強会を開催するに当たっての読書の仕方、勉強会の進め方が、そのまま自分の読書を進めるにあたってのガイドになりそうで、良い。

    自分たちの開発プロセスと比較することで以下を明らかにしたほうが良いと考えました。

    • 現状はどうなっているか
    • どこにギャップがあるか
    • どこに課題があるか

「7章 エンジニアリング生産性の計測」が気になりました。3ヶ月の期間の目標を立て実行、振り返りを仕事でやっています。が、そもそも目標を立てるのが辛いのです。闇雲にテキトーに目標を立ててしまうが、この章を読むことで良い刺激になるのではないか、と期待しています。

本が届いた。読書開始

649ページある。今までで一番長いし、文字も結構小さい。

2024年10月17日(木)

はじめに

時間の経過に応じたプログラミング

我々が提案するのは、「ソフトウェアエンジニアリング」とは単にコードを書く行為のみならず、組織が時間の経過に応じてコードを構築し保守するために用いるツールとプロセス全てをも包含するということである。

自分のやってる仕事はプログラミングと言うよりもソフトウェアエンジニアリングだなぁと思った。今後はソフトウェアエンジニアと名乗ることにしようかな。

訳注にコードベース(codebase)とは「ソフトウェアを構成するソースコードの集合」とあった。今までコードベースという言葉をなんとなく使っていたが、これで1つすっきりした。

第1部 主題

1章 ソフトウェアエンジニアリングとは何か

10年、あるいはそれ以上の期間であれば、暗黙的で明示的であれ、ほとんどのプログラムの依存関係はおそらく変化するだろう。この認識こそが、Google でのソフトウェアエンジニアリングとプログラミングの間の区別の根本にある。

ソフトウェアエンジニアリング = プログラミング + 時間に関する何か、ともいえそう。

こうしたスケールの問題は、ポリシー絡みの件であることが多く、ソフトウェアの持続可能性の問題にとって根本的なものである。つまり繰り返しやらなければならないことをやるのに、どれだけのコストがかかるのかと言うことだ。

スケールさせたいのであれば、ポリシー を用意すると良い、ということだと思う。

1.1 時間と変化

連続してスタートアップに参加している開発者は、10年間の開発経験があるにもかかわらず、1年か2年以上存続することが想定されているようないかなるソフトウェアの保守経験もないに等しいという話が、合理的な理由によってあり得る。

言われてみれば、確かにそうで、開発経験が長ければ保守経験も長い、ということにはならない。面白い。また、そうであっても、クラウドを利用したインフラの用意が簡単になったことに一因があると思うのだが、寿命の短いシステムであってもスケールするシステムを実現できる、というのも面白い。

アップグレードを最初から計画していなかったプロジェクトでは、3つの理由によりこの移行は苦痛に満ちたものになる可能性が高い(3つの理由は、相互に複利的に悪化させ合っている)。

  • プロジェクトでまだ行われたことのないタスクを実行することになるため、より、多くの隠れた前提条件が組み込まれている。
  • アップグレードを試みるエンジニアは、この種のタスクの経験がある可能性が低い。
  • どちらかと言えば、インクリメンタル(imncremental: 段階的に増える)なアップグレードではなく複数年分のアップグレードをやっているので、アップグレードのサイズが通常より大きい場合が多い。  そして、それゆえに、そのようなアップグレードを一度実際に経験すると(もしくは途中で断念すると)以降のアップグレード実行のコストを過大に見積り、「二度とやらない」と決意してしまうことになるのも無理からぬことだ。

「アップグレードのサイズが通常より大きくなる」というのはすぐに思いついた。次に思いついたのが「より多くの隠れた前提条件」。最後にそうなのかなぁとちょっと疑問符がついたが前提としてアップグレードを計画していなかったとあるのでなるほどと思ったのが「この種のタスクの経験がある可能性が低い」。いずれにせよよく整理されていて良いと思った。

また、「「二度とやらない」と決意してしまうことになる」という気持ちはとても共感した、してしまった。結構あるあるなのかな、と感じた。

1.1.1 Hyrumの法則

他のエンジニアに使われるプロジェクトを保守している場合、「これは動作する」と、「これには保守性がある」とを分ける最も重要な教訓は、我々がHyrumの法則と呼ぶに至ったものだ。

あるAPIに十分な数のユーザがいる時、APIを作った者自身が契約仕様として何を約束しているかは重要ではない。作られたシステムが持つあらゆる観察可能(observable)な挙動に関して、それに依存するユーザが出てくるものである。

「Hyrumの法則」、読んでみたが、一読しただけではわからん。何を言ってるんだ。これは。

読み方は、「はいらむのほうそく」で良さそう。

後方互換性維持大変だよね、につながってくるみたいな話か?

ここら辺を読んで大体わかった。「提供側の想定した仕様とは別に、実際に使えてしまう使い方で使われてしまうものである」ということだね。

落ち着いて目を少し先にむけてみると、参考ページで取り上げていた例をまさに、これから読む「1.1.2 例:ハッシュの順序付け」で書かれようとしているね。

1.1.2 例:ハッシュの順序付け

データベースからレコードを持ってくるときに、order by が無くとも大抵の場合はプライマリキーのIDの昇順でソートされて帰ってくるので、しばしばつけ忘れてしまう、というのもHyrumの法則の一例だと思った。

短命で書き捨てなので order by を付けないで済ませてしまうのはプログラミングだが、長く保守するので忘れずに order by をつけるのはソフトウェアエンジニアリング、というのが本書のニュアンスだと感じた。

ハック(hack) 訳注: 間に合わせの荒い解決策だが、何とか動いているもの、またはそのような解決策をでっち上げること。

我々は「クレバーが褒める言葉ならそれはプログラミングだが、クレバーが責める言葉ならそれはソフトウェアエンジニアリングだね」と言うようになった。

1.1.3 「何も変化しない」状態をとにかく目指すのはどうか

逓減 (ていげん): 時間と共に少しずつ減ること。

変化は内在的に善であるわけではない。変化それ自体のためだけに変化すべきではない。しかし、変化の能力は備えていなければならない。

変化できるように備えておけ、と言いたいのだろうから、結局、不特定大多数が扱ういわゆる普通のシステムの取り扱いおいては依存ゼロではないので、変化しない状態を目指すのはダメだ、と言い切っても良いと思う。

1.2 スケールと効率

問題がゆっくりと悪化しているのに、唯一無二の危機的瞬間としては絶対現れずに気がつかない事態は、たやすく起こり得るものだ。

時間が経てば経つほどバージョンアップしにくくなる、もこれ。

コミットメント(commitment) 41 訳注:目的の達成に専念し、必要手段を取る義務を負う、責任ある関与を確約すること(コミット[commit]すること=真面目に取り組むこと)。

よく聞くが、他人にうまく説明できなくてモヤモヤしてた言葉。

組織がコードを生産し保守する際に依存する、すべてのものは、全体のコストとリソース消費の点でスケーラブルであるべきだ。特に、組織が繰り返し実行しなければならないものは全て、人的労力の点でスケーラブルであるべきだ。この意味で、一般的なポリシーの多くはスケーラブルであるようには思えない。

著者の強い主張が込められているように感じた。が、全然理解できない。同意できない、という意味ではなく、自分の頭が悪くてなに言っているのかわからない、という意味で。

1.2.1 スケールしないポリシー

開発用のブランチ(branch)の伝統的な利用法が、スケーリングの問題を内包したポリシーのもう一つの例である。 …略… だが、組織のサイズ(とブランチの数)が増大していくと、同じタスクを遂行するにもかかわらず、負担するオーバーヘッドの量が絶えず増大することがすぐに明らかとなる。

これは最近体験している。外部からコードベースへの変更が頻繁に行われ、元とするブランチが絶えず変化するので、その変化が起きているかの定期的チェックのコストや、実際に変化に対応して追いつくのが大変 (たまにコンフリクトが起こったりして時間が取られる)。

1.2.2 よくスケールするポリシー

「製品が、インフラストラクチャーの変更の結果として障害や他の問題に陥った場合、問題が継続的インテグレーション(Continuous Integration/CI)システムでのテストで表面化していなかったならば、インフラストラクチャーの変更に落ち度は無い」というポリシーだ。

難しい、よくわかっていない、理解できていない。多分、責任範囲を明確にする、という役割も担っている。

我々は、組織がスケールする際に、専門知識と共有コミニケーション掲示板が大きな価値を提供することを発見した。

情報共有のために、教育目的も含めて、ウィキを使っている。大きく貢献している。しかし、ウィキはコミュニケーションを取るには機能が不足している。ウィキにコミュニケーション手段が付加されると、学びもより加速するのだろうか。

知識にはウィルスのような拡散性があり(viral)、専門家は媒介者である。

これは実感がある。

1.2.3 例:コンパイラーのアップグレード

インフラストラクチャーの変更が頻繁になれば、なるほど、変更が容易になる。

これも実感がある。溜めて1回で変更するよりも、都度頻繁に変更する方がトラブルの箇所と範囲が小さくなるので楽。

大半のコードが何回もアップグレードを経てきているエコシステムでは、コードが土台となっている実装の細部に依存しないようになる。その代わりコードは言語やOSが実際に提供を約束する抽象化層に依存する。

自身が実装するときに、フレームワークのドキュメントに書いてあるやり方に出来るだけ沿うようにしてきた。引き継ぐときにわからなくなったら私ではなくフレームワークのドキュメントを読んで欲しいからだ。このやり方は、本書のような観点からももたらされるしメリットもある、といえそう。

1.2.4 左への移動

一般的に正しいと言われる事のうち、我々も正しいとわかったことに、たいていの場合は開発者のワークフローの中で問題を早期発見するとコストが下がる、という考え方がある。

これが本書での「左への移動」の定義。雑に検索して出て来る「システム開発において、セキュリティ対策やテストを開発の初期段階に組み込む考え方」とは異なる点を押さえておく。

開発プロセスの早期に、品質、信頼性、セキュリティを強調するツールとプラクティスを提供することこそが、Googleのインフラストラクチャーチームの大多数にとって共通ゴールである。

Googleのインフラストラクチャーチームは問題の早期発見するためにツールとプラクティスを用意し続けている、と。その次の文を読むと、ツールとプラクティスは数をたくさん用意することでチェック回数をまず増やし、個々の質はブラッシュアップしていけば良いと考えているのだと思う。

1.3 トレードオフとコスト

エスカレーション(escalation) 66 訳注 : 冗長な判断を仰ぐ部下からの報告事項。

これがエスカレーションの定義か。今までの使い方は、困ったことが起きた時にエスカレーションですと言って上司に相談する時に使うイメージだ。

だがゴールは合意であって、全員一致で異議がない状態ではない。 …略… こうしたこと全てに内在しているのは、全てに理由が存在しなければならないという思想である。

ゴールに辿り着くために、いろいろな意見が出るがそれぞれに理由が必要、理由があることによって反対であっても納得はできるからだと思う。

1.3.1 例:ホワイトボードマーカー

最終的に、エンジニアリング集団内での決定というものは、非常に少数の物事に帰着する。

  • これをやらなければならないのでやっている。(法的要件、顧客の要件)
  • 現在のエビデンスに基づき、現時点でわかっている中で、これが(ある適切な決定者が決定した限りの)最良の選択であるのでやっている

よくわからなかった。この帰着したパターンが良い物であると言いたいのか、悪い物であると言いたいのか、そういうものなのだとただ単にわかったのか、何が言いたいのかがわからなかった。

1.3.2 意思決定への入力

データを比較衡量する際の一般的なシナリオは2つある。

  • 全ての関与する数量が計測可能か、少なくとも推定可能である。これが通常意味するのは、CPUとネットワークの間のトレードオフ、あるいは料金とRAMの間のトレードオフを評価している場合や、あるいはデータセンター全体でN個のCPUを節約するために2週間のエンジニア時間(engineer-time)を費やすかどうか検討しているような場合だ。
  • 微妙で捉えにくかったり、計測方法がわからない数量もある。これが「どれだけのエンジニア時間がかかるかわからない」という形で現れることもある。またそれよりさらに漫然としている場合すらある。たとえば、下手に設計されたAPIのエンジニアリングコストはどう計測すればよいだろうか。製品の選択が社会に及ぼす影響ならどう計測するか。

比較衡量は、ひかくこうりょう、と読む。この2つのシナリオを元にトレードオフとコストについての論が展開されていく。

2番目の類型の決定では、簡単な答えはない。経験、リーダーシップ、前例に頼ってそうした問題を切り抜けることになる。 …略… しかし、我々からの大まかな提案として最善なものは、全てが計測可能または予測可能なわけではないことを認識し、この類型の決定を、1番目の類型の決定と同様の優先度と一層の慎重さとをもって取り扱うことを試みるというものである。

いくつかのヒントがあるかとも思ったが、そんなものは無い、だった。全てが計測可能予測可能では無い、ということを日々合意しておくことくらいか。

1.3.3 例:分散ビルド

実はそうではなかった。分散ビルドシステムの提供によりエンジニアの生産性は大幅に改善したか、時間が経つにつれ、分散ビルド自体が膨れ上がったのだ。 …略… そのインセンティブが除去され、膨張した依存関係が並列分散ビルドに隠蔽されてみると、浪費が横行しかねない、ビルドの膨張に注意をするインセンティブがほぼ誰にも働いていない状況が、我々のせいでできあがっていた。これはJevonsのパラドックス(https://oreil.ly/HL0sl)を思わせる。リソース利用の効率が高まったことへの反応として、リソース消費は増加するかもしれないというパラドックスだ。

トレードオフとコスト。この節の主題のどのようなことをここで説明しようとしているのか、どう繋がるのかピンとこない。が、それはそれとして、Googleの人間であってもやはり人間で、インセンティブに沿って行動が引きずられるという、至極当然なことがわかる。

1.3.4 例:時間とスケールの間での決定

狭い問題空間のためにカスタマイズされた特性の解が、全ての可能性を扱わなければならない一般的な多用途利用のための解より性能が優れているケースはよくある …略… マイクロサービス(microservice)、メモリ内のキャッシュ(cache)、圧縮ルーチン、その他ソフトウェアエコシステム内の全てのどれについて話題にしてるかに関係なく、多用途の行動をフォークするか再実装するかして狭い領域向けにカスタマイズすると、新機能の追加が簡単になったり、最適化が確実にできるようになったりする。

よくわかる。あれやこれや全てに対応しようとするよりも、1つのことにだけ対応するコードの方が内部をいじり易い。

要は、時間の境界またはプロジェクト期間の境界(データ構造、シリアライゼーションフォーマット、ネットワーキングプロトコル)にまたがって動作する可能性のあるインターフェイスのフォークは避けろということだ。一貫性には大きな価値があるか、一般性にはそれ自体のコストがついて回る。そして、独自の方法でやることでうまく行くことも多い(注意深くやりさえすればだが)。

汎用性を捨てて、独自性に乗り換えたいときに、やめておいた方が良いパターンをここでまとめてくれている。

1.3.5 決定を再考すること、間違うこと

データ駆動文化にコミットすることの、意外と知られていない恩恵は、間違いを認めるという能力と必要性の組み合わせだ。

言われてみればそうだ。万物は流転し、データはその時点や場所で変わり、根拠にするデータ内容は変わるからだね。

エビデンス駆動であるべきだが、しかし計測できないものであっても価値があるかもしれないことも、また認識しておかなければならない。それこそが、リーダーであれば求められることだ。すなわち、判断力を駆使して、その物事が重要であることを断言しなければならない。

リーダーは決めることも仕事であり、その判断材料はいつも満足いくものとは限らないから、ということだと思う。

1.4 ソフトウェアエンジニアリング対プログラミング

プログラミングとはコードを生産する即時的行動である。ソフトウェアエンジニアリングとは、コードを利用しなければならない期間中に有用に保つのに必要であり、またチームを横断した共同作業を可能とするポリシー、プラクティス、ツールのセットである。

プログラミングとソフトウェアエンジニアリングには優劣はなく、どのような領域を扱うかが異なるだけ、と理解した。

1.5 結論

本書は以下全てのトピックについて議論している。それらのトピックとは、組織についてのポリシーと、プログラマー個人にとってのポリシー、ベストプラクティスを評価し洗練する方法、そして保守性のあるソフトウェアに投入されるツールと技術である。

ここの文章で言われてるのは、ポリシー、ベストプラクティス、ツールの3つ。一方で本書の目次を見ると、第1部から第5部の中で主に取り上げているのは、文化、プロセス、ツール、の3つ。一致しないから、何かダメと言うことでは無いのが面白い。

1.6 要約

プログラミングはコードを生産するものである。

ソフトウェアエンジニアリングはその周辺を含み、どちらかと言うと、そのあと保守も含んだ領域になる。

ポリシーは、プロセスをスケーラブルにする素晴らしいツールだ。

ポリシーに則って開発者が自律的に動けるからだ、と思っているが、本書でそんなこと書いてあったかどうか覚えていない。

プロセスの非効率な部分と、他のソフトウェア開発タスクはスケールアップが遅い傾向がある。茹で蛙問題に注意せよ。

この章を読む前に最初に親から読んだ。その時にこの項目は全然意味がわからなかった。今もよくわかっていない。が、多分、自分がコントロールできない部分だからだ、ということだと思う。

おわりに。第1章を読んで

2024年11月1日(金)に第1章を読み終わった。

気になった箇所を抜粋して、そこに対するコメントを記す、というスタイルで本書は読んでみようと思っている。この方法の場合、抜粋した箇所に近視眼的にコメントしてしまい、前後の文脈を捉えられない状態になってしまう、これは読書時もそうだが、読書後のこのメモを見返したときに顕著に現れてしまうだろう、と、そう考えている。

しかし、それでもこの方法で今回は読書しようと思う。まとまった時間が取れないし、そもそも取れたとしても内容が高度で長いので集中力がもたない。なので、X (旧Twitter) 的な感じに細切れ細切れに読んでいこうと思う。

また、最初の部分なので第1章を読んだが、次は気になった章を読もうと思っている。

コメントを残す