バスナンバー — 同僚たちに「書かないで」と言われたGitHubプラグイン
(scannedinavian.com)- ある開発者は、解雇によって収益を生むコードの唯一の貢献者がいなくなった経験をきっかけに、GitHub Enterpriseで「失ってはいけない人」を見つけるtruck factorプラグインを作ろうとした
- 同僚たちは、この指標がすぐにGoodhart’s Lawに陥り、守るべき人ではなく「解雇してもよい人」を探す管理ツールになり得ると懸念した
- 元のTruck-Factorリポジトリとデータはまだ利用できたが、データ収集日が不明で、READMEの手順もそのままでは再現できず、手作業での補正が必要だった
- 再計算は複数のGitHubリポジトリを
gnu parallelでクローンした後、Javaコードを実行する方式で、Linux kernelはlinguistフィルターなしでtruck factor 12、フィルター適用後は8となった - 元論文の数値である2015年のpreprintの90、正式publicationの57よりも結果が低くなっており、Linux kernelのbus factorが改善したとは見なしにくい
Bus Factorと危険なプラグインのアイデア
- Bus FactorまたはTruck Factorとは、プロジェクトが知識を持つ人材不足で止まってしまうまでに、突然いなくならなければならない最小のチームメンバー数を指す
- 2015年ごろ、会社の解雇プロセスで、会社に収益をもたらすコードベースの一部における唯一の貢献者が解雇されたことが出発点となった
- Truck Numberを思い出した後、GitHub Enterpriseプラグインとして「解雇してはいけない人」を計算するアイデアが出た
- 木曜午後のライトニングトークでこのプラグインを5分間紹介したところ、同僚たちは管理者がこれを「解雇できる人」を探すツールとして使う可能性があると見た
- この反応の核心はGoodhart’s Lawだった
既存のTruck Factor研究と再現の試み
- 元の研究は、複数の人気GitHubプロジェクトについて、プロジェクトが止まるには何人がいなくなる必要があるかを計算した
- 対象にはLinux kernelも含まれていた
- 記事の前半では、最初のpreprintがLinuxについて、止まるには80人が離れる必要があるとしていたと書かれており、後半では2015年のpreprintの数値が90、full publicationの数値が57と整理されている
- mclareとともに、約10年後にtruck factorが改善したかを確認するため、結果の再現を試みた
- 元著者たちのGitHubリポジトリはまだ利用できた
データと実行環境の制約
- 論文のデータはJSONで提供され、元の可視化はスクレイピング可能なCSVを基にしていた
- ただしデータ収集日は分からなかった
- READMEの指示はそのままでは動作せず、GitHub Issueを参考に実行方法を修正する必要があった
- 元CSVの1列目からGitHubリポジトリ一覧を取り出し、全リポジトリをクローンした
gnu parallelで複数のgit cloneコマンドを同時に実行した
gnu parallel、linguist、NixOSで詰まった部分
gnu parallelに-j 8を指定したが、ノートPCの32コアがすべて使われる現象が起きた- 同時に見える
git cloneプロセスは8個で、多数のgit index-packプロセスがすべてのコアを使っていた - 考えられる原因として、
git index-packがforkされた子プロセスであるため、parallelが別のgit cloneを開始してしまう状況を推測した - Truck Factorコードはドキュメントファイルを除外するためにGitHubのlinguistを使う
- NixOS環境でRubyの経験がなく、Ruby Gemsのインストールを時間内に解決できなかったため、Nix flakeでlinguistプラグインをインストールする方法やpull requestを求めた
実際の再計算手順
- 元リポジトリをforkしてローカルにクローンし、READMEに沿って実行方法を合わせた
mvn packageでJavaソースをjarにコンパイルした- まずnumpyのGitHubリポジトリで各ステップを試してから、全リポジトリの再計算を進めた
- mclareは元の可視化のCSVをダウンロードし、1列目をGitHubリポジトリ一覧に変換した
- 実行フローは次のとおりだった
parallel -j 8 git clone ::: $(cat ../meta/repo_list.txt)でリポジトリをクローンするgittruckfactor/scriptsディレクトリへ移動し、awkエラーを避けるcommit_log_script.shで各リポジトリのgit commit情報を抽出するgittruckfactor-1.0.jarを実行して、抽出したcommitデータを処理する
- 自宅の高速なギガビットインターネット接続で、すべてのリポジトリを逐次クローンするのに17.5分かかった
- 各リポジトリの処理もおおよそ18分ほどかかったようだ
Linux kernel再計算結果
- Linux kernelのサンプル出力はTF = 12、coverage = 49.98%だった
- TF authorsにはLinus Torvalds、Mauro Carvalho Chehab、Rob Herring、Thomas Gleixner、Krzysztof Kozlowskiなどが含まれていた
- Linus Torvaldsは5,712ファイル、6.59%と表示された
- linguistプラグインなしでドキュメントとサードパーティライブラリを除外しなかった結果は、Linux kernelのtruck factor 12だった
- mclareが自身のシステムにlinguistプラグインをインストールした後に得たLinux kernelのtruck factorは8だった
計算から抜け落ちている要素と次の確認事項
- この計算はレビュー過程を反映していない
- キャリアが上がるほど、開発者は自分でキーボードを叩いてコードを書くよりもレビューを多く行わなければならないという問題がある
- 追加で確認する項目は次のとおり
- truck factorの計算がgitの
co-authored-byとreviewerヘッダーを反映しているか - 反映していないなら、それを計算に入れられるか
- Linuxの数値が10年後に大きく変わった理由は何か
- 元論文のように開発者aliasをマージするためにLevenshtein distance 1を適用していない点が結果に影響したか
- Linux kernelリポジトリを2015年半ばの時点にcheckoutすると、同じコードが今でも80を出すか
- 2016年にアルゴリズムが更新されたため、その後の数値を出し直せるか
- truck factorの計算がgitの
- 元論文の156件のcitationを調べ、より良い計算法があるか確認できる
- Rustのような最近の大規模プロジェクトは2015年の論文に含まれていなかったため、現在の人気プロジェクトと過去の履歴を比較できる
- 任意のgitリポジトリについて、年ごとのtruck numberを見つけるスクリプトも作れる
さらに低くなったBus Factor
- 確認しようとしていた問いは、truck factorが時間とともに良くなったかどうかだった
- 結果は良くなっておらず、むしろ悪化したという見方に近い
- Linux kernelは、元論文の数値よりも今回の実行結果がはるかに低く出た
- ドキュメントとサードパーティライブラリのフィルタリング有無によって、Linux kernelの結果は12から8へさらに低くなった
- より多くの可視化と詳細はmclareの記事で確認できる
1件のコメント
Hacker News の意見
https://codescene.com/ の機能のひとつがまさにこれです。
知識の島を見つけ、それを頻繁に変更されるコードと結び付けることで、変更が多いのに知識の分散が低く危険な ホットスポットを特定します。
誰かが退職の意向を示したら、その人だけが知っているコードを簡単に確認できるので、引き継ぎ計画も立てやすくなります。
悪用される可能性は考えたことがなく、本来は可視化のためのツールです。そういう使い方をするマネージャーはひどいマネージャーで、すでにそういう人なら、このツールがそれを変えるわけではないでしょう。
昇進したいなら、獲得担当部門に「ナードと親密になる特殊訓練を受けた女性エージェント8人」を要請し、失敗した場合に備えてポロニウム8回分も予備として要請できるでしょう。
完全な作り話に聞こえるかもしれませんが、シード投資を探していたあるユニコーンスタートアップのCEOが、実際に前半に当たる出来事を経験したのを知っています。
3社目では、開発者たちがこの流れを遠くからでも見抜き、ツールの利用や評価そのものを拒否しました。
こうしたツールは価格が途方もなく高いので、承認した側はどうにか投資対効果を引き出さなければなりません。生産性、アウトプット、知識サイロを正しく測る方法がないため、結局「今週の Jose のPRは少ないね」のような話に流れていきます。
問題は、開発者もそれを見て、解雇不能な従業員リストに載るために対象プロジェクトやコンポーネントへ移ろうとする可能性がある点です。理想的には、労働者が一緒に動いて トラックファクターを0にし、誰も解雇しにくくできます。
もちろんそうなると、ほぼ完全な時間の無駄になり、ブロガーの同僚たちが言っていた「すぐに Goodhart’s Law に引っかかる」という元の論点が証明されます。
Amazon には、こうした数値をコードシステムから任意のマネージャーが実行できるレポートとして簡単に見られる仕組みがあり、チームが何をしているのか、どんなリスクがあるのかを確認する別の方法もたくさんあります。個人的には有用だと思います。
バスファクターはひとつの観点にすぎず、別の観点からは、サイロ、他人と協業しないエンジニア、エンジニアを簡単に異動させにくい領域を見つけて改善できるようにしてくれます。
開発者の中には代替可能性を恐れ、自分だけが知っているシステムこそ雇用の安定だと考える人もいますが、逆にそれは技術的リスクであり、優秀なエンジニアがより重要なプロジェクトへ移れない要因にもなり得ます。嫌いなシステムにうんざりしたときに、別の仕事をできる道でもあります。
ただし、代替可能性という発想は大きなオーバーヘッドを生み、有能な人たちを最大限の能力で使えなくします。彼らは実際には代替可能ではないからです。
ある場所では必要ですが、別の場所ではプロセスのオーバーヘッドのほうが、バスファクターよりもプロジェクト成功に対するはるかに大きなリスクになります。
結末は3か月以内の退職でした。
バックエンドでも TypeScript を多用する理由のひとつは、小さなチームが知っておくべき言語をひとつに減らせるからです。そのため、フロントエンド開発者が休暇に入っても実際に連絡を断てますし、他の人がカバーできます。誰かが転職しても痛みは少なくなります。
一度も問題になったことはなく、代替可能性は健全なシステムの一部だと思っています。管理側に数年いて最初に学ぶのは、「誰もが代替可能であり、それはコストの問題にすぎない」ということです。だから知識レベルが高すぎると、むしろ経営陣がそのリスクを下げようとして不利に働くこともあります。特に経済的理由によるレイオフはかなりランダムでもあります。
とはいえ、こうした滑稽な指標を使う場所で働きたいとは思いません。良い仕事をするためにレッドテープを増やせば増やすほど、一緒に働きたいと思う可能性は低くなります。こうしたものは、人々に良い仕事をさせるよりも 指標をゲーム化させがちで、生産性と品質に良くない文化を生みやすいです。
gnu parallelは要求どおりgit cloneを8個同時に実行しており、それぞれのgit cloneが勝手に大量のindex-packスレッドを起動している状況。ここでは
git configでpack.threadsを一時的に1に設定すると助けになる。二乗で増えるため、CPUが多いほど問題はさらに悪化する。32コアなら 32² = 1024 で、実際には Parallel に8個を指定しているので最大256個程度の
index-packプロセスで止まっていたはず。それでもこれをさばくには大量のメモリが必要で、実際には何の得にもならない。解決策は、2つの階層のうち片方だけを並列化すること。
pack.threadsについてのman git-configの説明はこうだ。最適なデルタ一致を探す際に生成するスレッド数を指定し、git-pack-objects(1)が pthreads 付きでコンパイルされている必要がある。そうでなければ警告とともに無視される。マルチプロセッサマシンでパッキング時間を短縮するためのオプションだが、デルタ検索ウィンドウに必要なメモリはスレッド数ぶん乗算される。0を指定すると、Git がCPU数を自動検出し、それに合わせてスレッド数を設定する。git configで一時設定する代わりに、単にgit -c pack.threads=1 cloneを使えばよい: https://git-scm.com/docs/git#Documentation/git.txt--cltnameg...この解釈はいまいち。この文章はすべてのエンジニアリングリーダー向けのものだと思う。
バスファクター は、チームの誰か、あるいは自分自身がバスに轢かれたときにチームがどれだけ苦しむかを意味する。
すべてのチームメンバーについて理想的なバスファクターは0。最初は「全員を使い捨てにしろ」と聞こえるかもしれないが、実際にはほぼその逆で、そこが要点。
チームは a) 自律的で、b) 謎がないと言えるほど良い状態であるべき。理想的な状態では、全員がすべてがどう動いているかを理解している。新入社員はすぐ価値を生み始められるべきで、退職する社員は未知の領域が残っていないことに安心できるべき。
全員のBFが0である理想的なチームは望ましい。チームメンバーが代替可能という意味であり、誰かが病気になったり休暇を取ったり実際に辞めたり排除されたりしても、すべてのメンバーが穴を埋められるという意味。
さらに重要なのは、0 BF が 単純性 の反映であること。ソフトウェア、ビルド・テスト・デプロイのパイプライン、ドキュメント、サポート体制がすべて凝集性と一貫性を持っているべき。情報をチームメンバーの中にサイロ化するのは悪いことで、全員がビルドしデプロイできるべき。
0 BF は健全な指標だが、メール数、コミット数、PR数、コード行数、応答速度、GitHub ヒートマップのようなもので測定されることは絶対にない。そうした指標は何も示せず、むしろ有害でひどい指標。
こうした指標で人を評価するのは、タイプライターの前の猿と変わらない。もっと多くのスタートアップがこれを聞くべき。
同じ概念を話しているようだが、その数字が常に同じ向きで使われるわけではないことに驚く。
可能性の境界を押し広げるプロジェクトでは、単純性 が選択肢ではないことがある。もちろんソフトウェアプロジェクト全体の中では小さな割合だが、前例のないことをするときは、コードを可能な限り単純に保つことよりも「そもそもこれをどうやって実現するのか」のほうが大きな心配になる。
コード品質が低くてもよいという意味ではない。ただ、難しいことをしていると複雑なコードが必要になることがあり、何世代か後になってようやく設計パターンが整理され、その難しいことをより複雑でないコードで作れるようになる場合もある。それは10年後かもしれない。
作れる最も複雑なものがToDoアプリ程度なら、社会に大した価値は生み出せないと思う。
バスファクターが高いということは、雇用主があなたの将来の潜在力ではなく、過去にやっておいたことのためにあなたを引き留めているという意味。
元論文の核心的な主張はこの部分。
「私たちの推定はカバレッジ仮定に依存している。現在の著者集合がシステムの現在のファイル集合の50%未満しかカバーしていない場合、システムは深刻な遅延を経験するか、停止する可能性が高い」
ここでファイルの著者は、事前計算された重みに基づいてそのファイルに意味のある貢献をしたユーザーとして定義される。
一方では、この種のダッシュボード指標がすでに何らかの企業向けソフトウェアに入っていないとしたら、むしろ驚くと思う。以前の会社の経営陣は、部署内でメールを最も多く送受信した人が誰かについて 日次レポート を作れるかと実際に尋ねてきた。
どこへ向かうのか気に入らなかったので断ったが、別の同僚が作った。予想どおり、最も多くメールを受け取り送っていたのはシステム管理者だった。複数のサーバーの自動メール送信者として彼のアカウントが設定されていたからだ。彼は1日に数百通の通知メールを自分自身に送っており、購読していたニュースレターやダイジェストメールも加わっていた。
他方で、同僚たちが皆、自分たちの職に影響し得ることをしないでほしいと言っていたにもかかわらず、趣味プロジェクトとして押し通すなら、かなり意地の悪い行動に聞こえる。
ただ、自分が使っているオープンソースソフトウェアが、生存可能性を高めるほど知識をうまく広めているかは見てみたい。
その意地の悪い行動は断った。
「キャリアラダーを上るほど、開発者は直接キーボードを叩く仕事を減らし、レビューをもっとすべきだ」というのは、テック企業でよくある誤解だと思う。
優れた開発者を平凡なマネージャーに変えたいわけではない。
彼はテックリードよりシニア開発者でいるほうがずっとよいだろう。彼がマネージャーになったらチームがどれほど苦しむか、想像しがたい。
この件の悲しい皮肉は、依然として問いの立て方が間違っていることにある
スタートアップがレイオフをしなければならないときの問いは、「誰を解雇しても既存事業を維持できるか」ではなく、「倒産しないだけの速さでプロダクトの次のバージョンを作れるチームは誰か」である
すべての分かれ道は結局分かれ道であり、十分に早く道を選べずに死んだ会社は多い
CPAN はかなり以前から バスファクターを追跡してきた。たとえば https://metacpan.org/pod/Moose は左側の情報欄に Bus Factor 5 を表示している
私たちはこれを 宝くじファクターと呼ぶのが好きだ
誰かが宝くじに当たって、電気も通信網もない熱帯の島へ去っても、プロジェクトを続けられるかという意味である
こう呼ぶと、あまり不気味ではない
バスにはねられた人は即座にいなくなる。同じことではない
スポーツの比喩を嫌う人もいるが、少なくとも軍事的な比喩よりはましだと思う
いずれにせよ、通常は引き継ぎがない場合も多いので、突然であること自体はそれほど重要な要素ではないかもしれない