ピザ2枚分の人数のMLプロジェクトのPMを1年間やった知見
ピザ2枚分の人数のMLプロジェクトのPM(プレイングマネジャー)を1年間やった知見
背景
2023/10から現在(2024/11)まで1年くらいプレイングマネジャーをやっていました。
規模としてはピザ2枚分(自分を含めて5~7人前後)の機械学習エンジニアのプロジェクト上での管理をしつつ、自分でもチケットを消化していました。
そこでの教訓を共有します。
この記事のスコープ
マネジャーとしてやっていたこと
主に技術開発のPoCで、タスクを作成・管理しつつ、ピザ2枚分(自分を含めて5~7人前後)の機械学習エンジニアのリーダーをやっていました。また、顧客とのやり取りやその結果生じた開発タスクの調整、会社との方針とタスクのすり合わせ等もやっていました。
自分もタスクを消化していたので俗にいうプレイングマネジャーでした。
ただし工数管理、社内手続き(稟議など)、社外手続き(契約など)などはノータッチで、PjMに委ねていました。
チーム向けにマネジャーとしては、以下の2つのタスクに大体ずっと取り組んでいました
-
生産性を最大化する
-
冗長性を高める
このチームへの動きについてフォーカスを当てます。
記事ではスコープ外のこと
社外向けに折衝したり、その結果や組織としての方向性からタスクを計画・実行したりもしました。ただ、そういった仕事はエンジニアが1人だけの小さなチームでやっていたころの延長線上だったので省略します。
あくまで他のエンジニアを管理するエンジニアの立場になって、何が違ったか・何をやったかという話を書きます。
話を広げると書ききる前に燃え尽きるため、PjMやPdM、組織間のやりとりや組織・コミュニケーションの設計の話はここでは扱いません。
なぜ生産性と冗長性の向上か?
生産性の向上
生産性の向上は、以下のことにつながります。
-
一定期間でできるだけ多くのことを実現する
-
同じことについてできるだけ早く実現する
同じ稼働時間でより大きなことをでき、同じことをやる際に稼働時間がより短い方が利益や価値が出ます。組織の値付けや評価が工数ベースであれ価値ベースであれ生産性の向上は有益で、大体の組織で目標として言及されていると思います。
冗長性の向上
冗長性は生産性につながるものです。
リーダーが全部チケットを切って、相談に乗って、レビューして、資料を書く体制だと、リーダーが止まると全て止まります。リーダーの業務時間だけチームが動くことになり、チームのスループットはリーダーがネックになります。
このような状況だと、リーダー以外の生産性をどれだけ上げても(仮に100人雇ったり、100人力のメンバーを1人雇ったりしても)、リーダーのところでタスクの消化が止まります。冗長性の課題はボトルネックに近しく、ここを多重化したり委譲したりすると、タスクの消化が止まりにくくネックになりにくくなります。チームの能力を引き出したり、チームの規模を拡大するためにはタスクを消化するプロセス上に単一障害点がなるべく無いように設計する必要があります。
また、長期的にはタスクを委譲しないとメンバーが育たたない、という話もあります。どれだけ教育をしても、結局はタスクを任せてみないことにはタスクをどれほど上手くこなせるか分からないです。ピーターの法則を避けて将来的により上のロールで動けるか判断するためにも、委譲は大切です。
生産性の向上に必要なものは何か?
主に生産性の向上に主眼を置いた時、自分は色々調べて先人の知恵に習っていました。
基本的には工場と同じ
異論はあると思いますが、ソフトウェア開発であっても基本は工場と同じです。
ボトルネックを見つけて改善します。細かな理論は色々ありますが、自分はTOC理論と呼ばれるような枠組みを意識して、測定と計画、介入を繰り返していました。
詰まっている部分 = WIP = ボトルネック以外を改善しても生産性は向上せず、ボトルネックの詰まりが増えるだけ、という考え方に基づいています。他にも色々な考え方はありますが、生産性に着目するなら結局はこの考えかこの考えと似た考え方に則ってやることになると思います。
工場と異なることもある
ただ、ソフトウェア開発、特に機械学習のプロジェクトと工場とで異なることもあると思っています。
大きな違いは並列して作成する製品数と生産設備の汎用性です。
TOC理論ではプロセス間のどこかで大量に生産している製品が詰まり、処理待ちの在庫(WIP)が発生することでボトルネックを特定します。ただしMLプロジェクト、特にPoCや技術検証のようにモデルを作るだけで終わるケースでは、1人が全プロセスを受け持つことができてしまいます。また、1人が並行して受け持てるのはせいぜい2つ程度で、チーム全体でもWIPは高々人数 x 1~2個程度です。この場合、調査、実装、テスト、計算、レポート、レビューのいずれかの特定のプロセスに対してWIPは高々数個に収まります。派手に滞留することがあまりないため、問題があっても見えにくくなります。
生産性と冗長性の向上のためにやっていた全体的な方針
生産性と冗長性の向上のために色々やっていました。ただ、大体以下の2つ(組織とソフトウェア)から生産性にアプローチしていました。それ以外の個人への教育や新しいツールの導入なども大事な要素としてありますが、それ自体は小さなチームでやることと変わらないので省略します。
組織
大体以下の4点からアプローチしていました。
- 小さくチケットを切る
- 測定・計測する
- 振り返りを行う
- 心理的安全性を高める
小さくチケットを切る
そのままです。タスク管理にカンバンを採用していましたが、そこで切るタスク(チケット)を小さくするようにします。
基本的にアウトプットはタスクの大きさ x タスクの消化速度(頻度)で決まります。タスクの大きさを大きくすると消化速度は遅くなり、タスクの大きさを小さくすると消化速度は速くなります。ただし後戻り、タスク間の衝突・調整などのタスク外のコストはタスクが大きいほど高くなります。そのため、アウトプットについてはタスクの大きさを小さくした方が安定して良くなると考えています。
測定・計測する
チケットを小さくするとタスクの流れる速度と量が増します。すると、どの処理でどのくらい時間がかかったが目で把握することが厳しくなります。最初のうちはタスクの消化速度などを数えていましたが、そのうち細かくラベルを付けたり処理ごとの所要時間を自動で出したりすることで、改善する際の判断材料を増やしていました
振り返りを行う
定期的に振り返ることで、懸念の洗い出しや改善策の実施・評価・中断等がやりやすくなります。逆に振り返りをやらないと、懸念の洗い出しや改善策の実施は無視できない問題となって取り組むことになります。懸念のレベルで対応していればすぐに終わったことが、無視できない問題のレベルとなると終わらせるのが大変なことになります。
問題が小さいうちから共有・対処するために、月次くらいの頻度で振り返りが必要だと思います。また、案件全体レベルのこと(チーム間・内外との意思決定、予算・工数)は別途3か月単位くらいで振り返ると更に良いと思います。ただ、この期間の組合せは組織・案件によるところが大きいと思うので、振り返りをスプリントに合わせて隔週と月次、みたいな間隔の組合せもありだと思います。
副次的な効果として、誰が何をやったか、何が得意・不得意か、どういった点に着目して仕事をしているか、なども何となく分かるようになります。これは特定のタスクを誰にお願いするか決めるとき、振り返りでこんなことをやりたいとか、逆にちょっと飽き気味と言っていたな、と判断材料になることがあります。
心理的安全性を高める
チームで働くうえで心理的安全性の大切さはよく言われますが、チームの規模が大きくなるにつれてより大事になってくると思います。
これが低いと後戻りが多くなり、また、振り返りやコミュニケーションの効果が小さくなってしまいます。
感謝を伝える、率直に誤りを認める等々のコミュニケーションの軸はよく言われます。これについては本も沢山あります。ただ、実際にタスクを作って振る側になると仕事の負荷の軸(適切な難易度のタスクを振ること)も大事だと気づきました。いくらコミュニケーションが率直にできても仕事内容がつまらないと熱意やアウトプットが低く・小さくなってしまうので、タスクの中身や難易度にも注意していました。
ソフトウェア
- 自動テストを作る
- コード化・自動化する
自動テストを作る
テストがないコードは動かないか、動いたとしてもどう動いているかは運だと考えた方が良いと思います。少人数で開発する状況なら手動でコードが動くことを確かめるだけでも何とかなります。ただ、規模が大きくなると何かしらの機能が止まって動かなくなります。なのでテストは必要です。
テストは自動で実行されないと結局回し忘れたり、回されなくなったりします。なのでテストといっても、自動で動くテストが必要です。開発規模が大きいほどコードが動かない時の影響が大きくなるので、常に最新のコードベースには自動テストが通ったコードだけを入れるようにしていました。
一方で自動テストは素早く回す必要があります。テストが拡充するほどテストの実行時間が増えますが、PRのたびに10~20分くらい待っていると大変です。なので、テストの実行頻度ごとにスコープを制限し、テスト時間を早める必要があります。依存関係にないコードのテストは動かさない、PRごとのテストはユニットテストや数Batch分の実行テストのみにする、週次ごとに全データでの実行テストをする、などのようにしていました。
コード化・自動化する
ドキュメントは陳腐化します。Docstringの内容が正しいかをテストすることは難しい一方で、Type Hintの内容は誤りを検知するのは容易です。陳腐化して内容が正しくなった時点で、Docstring(ドキュメント)は何も発しませんが、Type Hint(コード)はエラーを発します。
また、コード化・自動化すれば結果は一意になります。ドキュメントは人それぞれで解釈が異なってしまい、結果として行動が一意にならない時があります(と思っています)。コード化・自動化はメンテナンスしなくなった時の弊害が大きいですが、規模が大きいチームでは1人当たりのメンテナンスのコストは小さいです。
Python3.Xをインストールしてください、ではなくDockerのように環境をコードとして管理します。データをURLからダウンロードしてXに展開してください、ではなく以下のコマンドを実行してください、とコード化します。そうすればテストしやすくなりますし、メンテナンスも楽になります。
自動化の対象としては、PRをマージしたらカンバンのDoneに移動する、モデルの変更をしたら該当するラベルを付ける、などもルールや手作業も含まれます。規模が大きくなるほどルールや手作業を守らせるのは大変になります。問題が起きてから手作業で時間を掛けてカバーすることを避けるために、ルールは増やさず自動的に行われる何かを増やすと楽になります。
まとめ
上記のようなことが、2, 3人のチームとピザ2枚分のチームの差として必要かな? と思ってやっていたことでした。
やっていたプロジェクト・組織固有のことが多々あると思いますが、何かしらの参考になれば幸いです。
Discussion