yigarashiのEMブログ

学んだことや考えていることを書きます

エンジニアの異動は推奨すべきなのか? - 組織の成長について考える

最近エンジニアの異動について軽く議論することがありました。自分はチームの安定性の側面からやや否定的な立場だったのですが、その議論で刺激を受けて周辺領域も含めて考え直したところ、組織の成長という軸で色々な知識がつながって面白かったのでまとめてみます。

議論の前提

異動も含めてエンジニア組織について考える時、まずは外せない前提がひとつあると思います。それは、安定したチームないしバリューストリームを維持することです。「チームトポロジー」の3章では以下の言葉を引用し、複雑なシステムの開発にはチームの効果的なパフォーマンスが欠かせないことを論じています。

ハイパフォーマンスなチームを解散するのは、単なる破壊行為では済まない。企業レベルのサイコパスと呼ぶべきものだ。

現代のソフトウェア開発の変化速度や複雑性に対処するには個人では限界があり、チームとしての活動が欠かせません。チームメンバー間で強い信頼関係が生まれることで、実験とイノベーションが起こり、パフォーマンスはさらに向上していきます。チームがそうした安定した状態に至るには一般に2週間から3ヶ月と長い時間がかかるので、仕事のたびに人をアサインするのではなく、安定したチームに仕事が流れ込むのが良いとされています。

エンジニアの異動に関する議論は、この前提をクリアした上で如何に新しい価値を生み出すのか、という視点で考えるのが良いだろうと思います。

エンジニアの異動に期待される価値

エンジニア組織において戦略的に異動を推奨する時、おおよそ次のようなことが期待されていると考えます。

  • チームの成長
    • 異なるやり方をする人がチームに入ることでUnlearnが起こる
    • チーム間で知識とプラクティスが交換され洗練される
  • 個人の成長
    • 異なる環境に身を置くことで手数が増えたり視野が広がったりする
    • 人脈が形成され帰属意識が高まったり、組織的な課題に挑戦しやすくなる

こうした価値が積み重なって組織全体が成長し続けることが最終的な目的になるでしょう。上で参照した「チームトポロジー」の3章でも、チームは安定している必要があるが、固定してもいけないと述べられています。安定したチームを破壊しない程度に人が流動することは前向きに捉えると良いようです。

高い効果を期待できる異動

安定したチームを維持しつつ、チームや個人の成長を期待する時、高い効果を期待できる異動のパターンがいくつか思い当たります。

ひとつはジュニアメンバーの異動です。ジュニアメンバーはチームのコミュニケーションやバリューストリームに与える影響が少ないので、チームの安定性についての心配は少ないでしょう。一方でジュニアメンバー本人の成長という観点では大きな価値を期待できます。さまざまなやり方を身につけ、一緒に仕事をしたことがある知り合いが社内に増えるのは良いことです。わたし自身、入社一年目に別のチームに半年だけ異動してそうした価値を享受した経験があり、納得感の強いところです。一方で、これが100%正しいとは限らないことには注意が必要だと思います。チームやその人の特性によっては、ひとつのことに早く習熟し、自己効力感を感じられることで良いフィードバックループが回り出す場合もあるでしょう。あくまで本人の希望やマネージャーの観察に基づいて慎重に采配すべき事柄だと思います。

次のパターンは特定領域の専門知識を持った人の異動です。これは、チームトポロジーにおけるイネイブリングチームが支援先を変えるのに近いものです。うまくいけば専門的な知識が複数のチームに伝播していきます。このパターンが機能する前提は、異動する専門家本人が、チームが専門的な能力を備え自律的に活動することに責任を持ち、実際にそれを成功させていることです。まさにこれはイネイブリングチームのミッションです。当然、本人しか変更できない要素がバリューストリーム上に残っているなら安易に異動するべきではないでしょう。チームの安定性を大きく損なう可能性があります。

最後はチームのリーダー的存在の異動です。リーダーが異動すると劇的なUnlearnが期待できます。他のメンバーにリーダーシップが芽生えることで個人の大きな成長も期待できます。もちろん短期的なチームの安定を度外視したやり方なので、そう乱発できるものではないですが、うまく戦略的に実行すれば組織の力を底上げできると思います。

いまのところ、上に述べた以外で突出したメリットのあるパターンには思い当たりませんでした。もちろん上記以外のパターンでも一定の効果は期待できると思われますが、組織として推奨するほどではないということです。ここの裾野を広げるためには、採用技術やアーキテクチャを揃えて認知負荷を下げたり、業務フローから属人性を排除したり、ピープルマネジメントの方向からメンバーを育てたりして、地道に人員の交換可能性を高める追加の戦略が必要になってくると思います。

そうした活動を突き詰めていくと、「異動という文化」が発展した、社員同士の信頼関係の強い組織ができるのかもしれません。「チームトポロジー」では、そうした高信頼な組織ではエンジニアが1年に1回チームを変えてもパフォーマンスが落ちないケースに言及されています。逆に、そうではない普通の環境では1年半から2年はひとつのチームに留まるべきで、さらにチームの一体感を高めるために支援も必要だとされています。

異動以外の手段

エンジニアの異動に期待される価値は、異動以外の手段でも得られるように思います。例えば以下のようなものです。

  • 優秀なスクラムマスターによる継続的なUnlearn
  • イネイブリングチームによる特定の領域に関する支援
  • ギルドのような特定の領域に関する知見交換のグループ

今回は「異動」というテーマから出発したので議論が偏りましたが、本来は「組織の成長」が一番上にきて、その実現方法として異動と上に並べたような内容が対等に並ぶのが健全なメンタルモデルだろうと思います。個人的には、これまで学んだスクラムマスターのテクニックや組織設計が異動という戦略を代替しうる点が非常に面白く、これまで学んだ知識が少し抽象度の高いところで繋がった気がします。

まとめ

この記事では「エンジニアの異動は推奨すべきなのか?」という問いに対する現時点のわたしの回答をまとめました。基本的には、チームの安定性の損失と組織が得る成長機会を比べて、得だと思う人には異動を推奨すれば良いし、損だと思うなら推奨しないという当たり前の結論に至りました。得になりやすいパターンはいくつかあり、得なケースが増えるように組織として工夫することもできそうです。

組織やプロセスがよくできていれば自ずと異動はしやすくなるので、ある種のヘルスチェッカーとしての側面が強いように思いました。間違っても異動の量をそのままKPIにしてはいけなくて、チームの安定性をいたずらに破壊してしまうので、異動を阻害する組織の課題にブレークダウンして取り組んでいくのが良いでしょう。一方で、組織の成長という観点では異動以外の手段によって似たような価値を享受することも可能で、広い視野で組織のあり方について考えることが重要だと思いました。

「Measure What Matters」を読んで思うOKR導入の困難さ

ここ半年でメンティーを2名持ち、1on1によるメンタリングと評価プロセスの一部を担っています。その過程で、目標設定や評価をもっと良くしたいと思うようになりました。せっかく時間を使うなら、成長を支援する、パフォーマンスを引き出す、上位の目標を意識させるといった目的をより高いレベルで達成したいものです。OKRというやり方があることは知っていたので、エンジニアリングマネージャー必読の翻訳書 7選 - Yusuke Ando a.k.a yandoで紹介されていた「Measure What Matters」を読んでみました。

学んだことの概要

組織として目標に向かって高いパフォーマンスを発揮するために、「目標("O"bjectives)」とそれを達成するための計測可能な「主要な結果("K"ey "R"esults)」のツリーをつくり、CFR(Conversation、Feedback、Recognition)による継続的パフォーマンス管理で頻繁な検査と適応を行います。OKRの主な効用は以下の4つとされています。

  • フォーカスとコミット
    • 少数のObjectivesを定めることになりフォーカスが生まれます。また、集中すべきポイントが明らかになり、そこに計測可能なKey Resultsが組み合わさることで強いコミットメントが生まれやすくなります
  • アラインメントと連携
    • 経営陣から末端のコントリビューターに至るあらゆるレイヤーで、目標に向けて意識を統一することを「アラインメント」と言います。OKRでは、一部の目標や全ての主要な結果をボトムアップに設定することで、社員のエンゲージメントを高めながらアラインメントします。またOKRの設定をオープンなプロセスにすることで、達成すべき共通の目標が明らかになり、チームや部門を超えた連携が生まれやすくなります
  • ラッキング
    • Key Resultsを計測可能なものにすることで進捗をトラッキングすることが容易になります。それにより、頻繁に設定したOKRを適切なものに調整することができます
  • 驚異的な成果へのストレッチ
    • OKRを報酬と切り離し、一部のObjectivesを野心的にすることで、驚異的な成長やイノベーションを生み出す土壌を作ることができます。書籍中では、Objectivesは設定時点では実現困難に思えるものにする、達成にコミットする目標と野心的な目標を明確に分けるといった事例が紹介されています

ざっと読んだ感想としては、目標管理におけるアジャイルなやり方という印象で、非常にシンプルでパワフルなツールだと思いました。OKRをうまく運用することができれば、熱量と規律を兼ね備えた働きがいのある組織になるイメージを持ちました。しかし一方で、OKRが機能するための条件は非常にレベルが高く、導入するのは簡単ではないと感じました。以下に気づいたポイント列挙して、もう少し思考を深めてみようと思います。

OKR導入で難しそうなポイント

リーダーの向上心が前提

OKRは、リーダーに狂気的な熱意があり、社員を動員して最大限のパワーを引き出して、なんとしてでもプロダクトを成長させたいと思う時にこそ役立つものだと思いました。リーダーが徹底して目標にコミットする姿勢を見せることで、それがコントリビューターにも伝播しハイパフォーマンスな組織になっていきます。反対に、リーダーが大きな成長を志向しなかったり、目標へのコミットメントが弱かったりすると、OKRを機能させるのは難しいように見えました。というかそもそも、そういったぬるい環境ではOKRを運用する必要すらないでしょう。

プロダクトに関する豊かな共通理解が必要

OKRではKey Resultsをボトムアップに定めることが推奨されているようです。必要十分で計測可能なKey Resultsを定めるためには、ビジネスモデルやKPIツリー、プロダクトの理解が欠かせません。ある目標を達成するために、どの指標やプロダクトの側面に着目すれば良いのか、自分の職能で何をしたらそこに貢献したことになるのかといったことを、誰もがよく知る必要があります。これは容易なことではないでしょう。

個人のKey Resultsという矛盾

現代的なアジャイル開発の文脈では、ひとりで何かを達成するのは基本的にバッドプラクティスです。コラボレーションを重んじチームとしてゴールを達成するのが良いとされています。こうしたやり方の中で、個人で完結するKey Resultsをうまく定めるのは難しく感じます。チームのKey Resultsをそのまま持つのがひとつの案ですが、当事者意識やコミットメントが弱まってしまうようにも思います。

報酬をどうやって決めるのか

OKRは報酬と切り離すことで野心的な目標設定やイノベーションを促進するとされています。一方で、OKRを導入しようとする企業では、報酬と密接に紐づいた旧来の評価制度を置き換える文脈でOKRが現れることが多いと思います。つまり良い形でOKRを導入しようと思うと、OKRは評価制度とは別であることを懇々と説明し、さらに「報酬はどう決めるのか」という問いにも改めて答えなければいけません。これは容易な変化ではないでしょう。少なくともボトムアップでどうにかなるような問題ではないと感じます。

まとめ

OKRがパワフルなツールであるという学びを得たものの、基本的には高い視座からの経営やマネジメントのためのツールであるので、自分の道具箱にはまだ収まりきらない印象でした。導入にあたっても多くの障害物がありそうです。目標管理でも、透明性、検査、適応、確約といった概念が現れているのは面白く、不確実な世界で成果を挙げるためのポイントを抽象化して捉えられたのは収穫でした。

「チームトポロジー」を読んで組織とシステムを設計するための知見を得た

チームトポロジー 価値あるソフトウェアをすばやく届ける適応型組織設計を読みました。チームの形やインタラクション、担当プロダクトの認知負荷について悩んでいたので、何かまとまった知識をインプットしたいと思って手に取りました。内容は期待以上で、組織設計とシステム設計について考える良いガイドラインを得られました。特に琴線に触れたのは以下のようなポイントです。

  • 組織設計のパーツを4つのチームタイプと3つのインタラクションモードに絞り込むことで、各チームの責任とふるまいが明確になり成果を挙げやすくなる
    • チームにミッションを与え成果を上げさせるのは難しいことだと思います。チームタイプとインタラクションモードを指定することによって、発揮すべき影響が明確になるのは面白いと思いました。インタラクションモードが明確になることで、影響を受け取る側の振る舞いを同時に伝えられるのも巧妙だと思います
  • バリューストリームに沿った職能横断チームが基本で、そのチームを支援し認知負荷を下げるために他の3つのチームタイプがあるという構造
    • 近年のアジャイル開発の基本である職能横断チームを中心にして、その活動を「会社」という単位で最適化する考え方を読み取ることができます。会社の方針とも整合する方向でよく腹落ちしました
    • 個人的には、コンプリケイティッドサブシステムチームの考え方が非常に現実的で気に入りました。このチームタイプは、高度な専門性が必要で各チームで面倒を見るには認知負荷が高すぎるコンポーネントを切り出して、専門家チームを組んで引き受けます。各チームに専門家を配置するのが難しいという制約に対する現実解です。この考え方を進めると、例えば複数プロダクトの同じ専門性が必要なコンポーネント(例えばレコメンドシステムとか)を集めることで、専門家のフルタイムのポジションを作り出すといったことも可能かもしれません
  • 適切な境界で分割された疎結合なシステムを、十分な能力を備えた適切なサイズのチームで運用する状態を目指す
    • 理想の状態はいつもこれで、そこに至り、そして居続けるためにコンウェイの法則やチームタイプ、インタラクションを駆使して組織とシステムを設計し続けることが必要です。ソリューションやインターフェースを探索する必要があるなら一時的にコミュニケーションを強化するし、一定の水準に達すればコミュニケーションを少なくしたら良いし、状況が変わればまた組織とシステムの形を変え必要なコミュニケーションを取る。そういう当たり前だけど極めて難しいことをうまくやり続けましょうというメッセージを読み取りました
    • コンウェイの法則を踏まえて、うまくやるには組織もシステムもよくわかっていないといけないという点も強調されており、この視点は大事にしたいと思いました

会社単位で突然こうした知識が活きるようなポジションにはまだいないですが、自分のチームという目線でも十分役に立つし、知った状態のほうがよりうまくフォロワーシップを発揮できるように思うので、読んで良かったと思います。エンジニアリングマネージャーを目指す若者の戦略の観点では、テクノロジーとデリバリーを中心に複数領域にまたがる高い視座を獲得できました。

毎日メンティーと一緒にコードを読むと良いことがたくさんある

最近、毎朝30分メンティーと一緒にコードを読む活動を始めました。早朝に集まって稽古をつける感じが道場っぽいと思って「コードリーディング道場」と名付けました。

やり方

  • 会話して画面共有できる環境に集まる
  • メンティーに調査したい内容を決めてもらう
    • サービスの機能の軸でも技術の軸でもなんでも良い
    • 「いまの仕事で触ることになりそうだから」といった感じで選んでも良い
    • とにかく内発的な動機が強いほど良いと思う
  • メンティーに画面を共有して調査してもらう
    • ここが1番のポイント
    • メンターは指示に徹してメンティーに調査の仕方を体で覚えてもらう
    • 1日の枠では終わらないことの方が多いので何日か続けて調べる
  • 以上をメンティーがもういいと思うまで繰り返す

良いポイント1: 業務知識を高速にインストールできる

機能の調査の仕方やドメイン知識、基礎技術といった業務にクリティカルな情報を、インタラクティブに伝えることができます。実際の挙動の見方や、社内ドキュメントの検索の仕方など、身につくと一気に仕事が楽になる情報が自然に伝わるのが良いです。また、単にドキュメントを読んでもらうのではなく、実際のコードを見てもらって「なんでこんなふうになっているんですか?」という疑問から出発できるので、学習効果が非常に高いです。そしてそういう切り口になっていると、文書化しきれない色々な情報がメンターの口をついて出てくることになります。「そこは本当はこうしたいんだけど、今は時間がなくてできなくて……」といった感じですね。こうした生の情報の積み重ねによってシステムが体に馴染んでいくと思うのでバカにできません。

良いポイント2: 単純接触効果を得られる

こうした活動をする場合メンティーのチーム歴は浅いことが多いでしょう。そのような状況では、毎日30分ネタの尽きない会話をできること自体にも価値があります。一緒にコードを読んでいると、「ここちょっと読んだけど全然わからなかった……」「前職ではこういう書き方してたんですよね」といった感じで、相互理解につながる発話が自然と引き出されます。リモートワークに軸足が移りつつある世の中で、こうした何気ない会話はとても貴重だと思います。この点の効果を強く狙うなら、人の組み合わせをローテーションしたり、ペアでなくモブでやったりするのも良いかもしれません。

良いポイント3: メンターの知識が整理される

これは言わずもがなですね。「ALBってなんですか?」「Webのキャッシュってどうなってるんですか?」といった、メンターの地力が試される質問が次々飛んできます。感覚ではわかっていて、仕事で使えたとしても、他人に分かるように整理して言語化できるのは全くレベルの違う話です。その場で説明できるに越したことはないですが、もしできなかったとしても、一緒にWeb上の資料や実装を眺めながら、自分の脳内にバラバラに置かれている知識をつなげて説明を試みるのはエキサイティングな活動です。この活動を始めてから自分の知識もどんどん整理されていて、メンティーはまだピンときていないのに、自分は点と点が線でつながって大満足しているといった場面が何度も見られます。もっとうまく説明できるようになりたいですね……。

なぜこの活動に至ったか

もともとは、当時のメンターである id:Sixeight さんとメンティーである自分が話して発足した活動でした。もう2年も前のことです。当時の僕は、もっと自在にパフォーマンスを発揮したいのになかなか軌道に乗れず困っていました。それを相談したところ、毎日一緒にコードを読んでみることになったのでした。その効果は著しく、3ヶ月ほどでなんでも自分で調べられる自信がつき、仕事の成果もうなぎ登りとなりました。成長曲線の立ち上がりを一気に早めることができとても感謝しています。

そして時が過ぎ、今度は自分がメンティーを持つことになりました。1on1で会話していると、当時の自分と全く同じ課題を相談されました。ペアコードリーディングが効果てきめんという思い出がすぐに蘇ったので、今度は僕がメンター側になってコードリーディング道場を始めることにしました。受け取ったバトンをしっかり次につなげられているような思いがして、充実感を持って取り組めています。

ただ、そうしてコードリーディング道場によって成長を加速させている一方で、新しく入った人に課題が共通していることが気になってきます。プロダクトの認知負荷や、オンボーディングのコンテンツに改善の余地があるのかもしれません。流行りのチームトポロジー本を読んだりして視野を広げようとしています。コードリーディング道場は効果の高い施策ではあるものの、やはり毎日30分ガッツリ頭を使って会話するのはコストが高いです。そこまでせずともスムーズに成果を発揮できるならそれに越したことはないと思います。現状を生き抜きつつ根本的な改善も進めたいですね。

webextension-polyfill-tsの型定義の自動生成がバグっていたので直した

Fix type generation for WebExtensionManifest.commands by yigarashi-9 · Pull Request #66 · Lusito/webextension-polyfill-ts

珍しくOSS活動をしたので簡単に報告記事を書く。

問題

最近ブラウザ拡張をよく触っている。同僚がmanifest.jsonをTypeScriptから生成できる良い仕組みを整えてくれており、自分も元気に開発を進めたのだが、どうにも型が合わない。最初は型がついたおかげでミスが静的に検出されていいな〜と眺めていたのだけど、よくよく調べるとどうも型定義が間違っている。具体的にはmanifest.d.tsの以下の箇所。

        commands?: WebExtensionManifestCommandsType;
    interface WebExtensionManifestCommandsType {
        /**
         * Optional.
         */
        suggested_key?: WebExtensionManifestCommandsSuggestedKeyType;

        /**
         * Optional.
         */
        description?: string;
    }

MDNのドキュメントにあるように、commandsは任意のkeyでcommand名を指定しつつ、ショートカットキーの設定を与えることになっている。しかし型定義のほうは、commandsに直接ショートカットキーの設定を与える形になっていて誤っている。commandsはRecord<string, WebExtensionManifestCommandsType>といった型になっていると良さそうに見える。

解決

型定義を1行直したら解決と思いきやそうではない。MozillaはWebExtensions APIJSON SchemaライクなAPI Schemaで定義している。今回使っているwebextension-polyfill-tsは、そのAPI Schemaから型定義を自動生成している。今回の問題はその自動生成プロセスのバグによるものであった。

具体的には、API Schemaに対する前処理として、別ファイルでextendしているものをひとつにまとめ(上の例ではmanifest.d.tsの単位でまとめている)、その上で入れ子になっている定義を分割する(上の例だとWebExtensionManifestCommandsTypeのような分割)のだが、その過程でobjectが入れ子構造になっている情報が潰れてしまっていた。

再帰処理の感じから一般のケースとして直すのが難しそうに見えたので、コーナーケースとしてobjectの入れ子を補う処理を加えて修正とした。半信半疑で修正を加えて型定義を再生成したところ、見事に問題の箇所だけdiffができて直ったので自己肯定感がだいぶ高まった。