📝

チームの生産性と向き合う

2024/05/07に公開

こんにちは @glassmonekeyです。

Ubie 株式会社に転職してあっという間に二ヶ月が立ちました。
現在私は toC 向けのアプリケーションに配信する施策を入稿・管理するシステム「案件管理システム」の開発チームに所属しています。

そのチーム内で現在、私はテックリードというロールで、日々の開発を一人のエンジニアとして進めつつもチームの生産性改善、技術的な意思決定のファシリテーションなどに取り組んでいます。

今回のエントリでは、何かと話題となるエンジニアリングの生産性ですが、テックリードとしてどのように向き合ったのか、どのように改善し今後どうしていくのか?を紹介します。

生産性の定義

前提として生産性を正しく計測することは難しく、それこそ生産性を下げる行為だと私は考えています。

@hiroki_daichiさんの開発生産性について議論する前に知っておきたいことに詳細は譲るとして、一般的には生産性は以下のどちらかを示します。

  • 物的生産性 ... 生産物がどの程度の労働力によって得られたかを示す指標。エンジニアリングにおいてはソースコードなどが該当する。
  • 付加価値生産性 ... 生産されたものに対して付加価値(≒ 売上)が労働力によって得られたかを示す指標。

ここでは「生産性」というワードがどちらを示しているのかが大事です。エンジニア間だと暗黙的に前者かもしれませんが、会社や組織としては後者に取り組むべきです。どれだけ物的生産ができていても付加価値をもたらすものになっていなければ本末転倒です。
とはいえ、後者を測定をすることは非常に難しいです。

そこで「付加価値生産性」を実現するための「物的生産性」という整理で、チームでは前者の「物的生産性」を考えることにしました。
本質的には「付加価値生産性」が重要なので、ガチガチに取り組むのではなく定性的に価値が出そうなポイントを常日頃チームでコミュニケーションを取りながら取り組んでいきました。

前提

私が担当している「案件管理システム」では文字通り私達のチームによる開発はもちろんのこと、以下のような開発体制で開発をしています。

  • 週 3~4勤務の業務委託メンバーも参加するようになり、自分含めて2~3 ヶ月でチームメンバーが増加した点。
  • 案件に関わる社内の他チームも案件管理システムを開発している点。

このような状況だったので、開発時のコミュニケーションコストが増加しており、如何にして下げられるか?が重要なポイントになっていました。
管理画面そのものは Next.js を採用していますが、開発チーム全員がフロントエンドや Next.js に長けているわけではないという状況でした。

取り組んだこと

明示的にリストアップしてから取り組んだわけではないですが、スプリント終わりに振り返りで判明した課題を中心に潰していきました。
大きく以下の 2 つのポイントで解消していきました。

  • コミュニケーション方法の整備
  • 仕組みの整備

特にコミュニケーションに関して改善に取り組んでおくと、後者の仕組みの整備はチームで一定スケールすると考えたので、
まずはコミュニケーション方法の整備から取り組みました。

かなり具体ですが実際にチームで取り組んだ例を示します。

コミュニケーションの整備

ドキュメント拡充

急に新メンバーが増えたことや、関わるチーム自体も増えたことで暗黙知から形式知への転換が急務になっていました。
コアメンバーが日常的にアドホックな質問に答えることが常態化していました。

暗黙知を形式知にしていく上で、ドキュメント拡充をチームで取り組んでいきました。
特に重要なポイントとしては、オンボーディングを通してドキュメントを拡充する場合、オンボーディングをされる側、つまりは新メンバー側で一定言語化の try をしていくことです。

オンボーディングを実施する側は、暗黙知が定着している状態なので、新メンバーの不明なポイントを判断する点は難しいです。
新メンバーの場合そこは自身の不明なポイントを記載すれば良いので、ある種自明といえます。
また、新メンバーにオーナーシップを持ってもらうためにも、一緒に改善していくという空気づくりは重要な要素といえます。

大体既存メンバーは忙しく、ドキュメント化は劣後しがちなのでそういう組織の力学にも反しない無理のない改善になるのでおすすめです。

PRテンプレート・コードオーナーを設定する

我々の抱えている案件管理システムでは、チームをまたいで PR のレビューを相互に依頼することがあります。
そのためにはレビューをするうえでの型を作っていくことが大事です。
人によって内容がマチマチであり、「どういうことを確認してから作られた PR なのか?」というところから推理することもありました。
特にチーム外からの PR は緊急なのかどうかが重要であり、緊急の場合今の抱えてるタスクより優先すべきです。そのため頻発するとハレーションが起きがちです。

コメントアウトに例を記載しておくことで、ジョインした直後のメンバーの PR を作るハードルを少しでも下げることを狙っています。

# 概要
<!--
* このプルリクエストで何を行うのかを記載しよう
* 例: このプルリクエストでは、ユーザーがログインできるようにするための機能を追加します
-->

# 関連リンク
<!--
* PBIのリンクや関連するIssueのリンクを記載しよう
-->

# 確認したこと
<!--
* このプルリクエストで確認したことを記載しよう
* 画面の変更の場合ならスクショなども貼り付けよう。
* 例: ローカル上でエラーが発生しないことを確認しました
-->

# チェックリスト
<!-- 以下のチェックリストを埋めることで、プルリクエストの品質を向上させましょう -->

- [ ] チェックリストA
- [ ] チェックリストB
- [ ] チェックリストC

# レビュアーに確認してほしいこと

<!--
レビュアーに確認してほしいことを具体的に記載しよう。特にほかチームへの依頼を含む場合は、具体的に書こう。
例)
〇〇な実装をしてみたが、この実装で問題ないか確認してほしい。
-->

# 他チームへのレビュー温度感/期待値
[レビュー温度感/期待値の定義はコチラを確認](<https://www.notion.so/ubie-inc/2934506a39a54d019fb4f8767fc23d50?pvs=4#74c09ca66f8b476da954d177cd1b70d2>)
<!--
他チームのエンジニアにレビュー依頼をする際は認知負荷削減/コミュニケーションを
スムーズに行えるようにレビューに対する期待値やレベル感を書くようにしましょう。
-->
- [ ] [Low]影響軽微な共有(Lint設定など / approveが無くても進める)
- [ ] [Middle]機能追加に伴う共有(画面の表示内容変更など / approveが無くても進める)
- [ ] [High]意見がほしい (実現方法に迷いがあるときなど / approve必須)
      `レビュー期限: ***年**月**日まで`

# その他
<!--
* その他、特記事項があれば記載しよう
* 相談事や質問事項があればここに記載しよう
-->

モブ・コードレビューの実施

弊社ではリモートワークが中心なので、コミュニケーションの中心はどうしても非同期です。
個人の作業の場合は自由な時間の使い方ができるので効率が良いですが、コミュニケーション効率はどうしても下がってしまいます。

特にコードレビューの場合前提の認識が揃っていなかったりすると平気で二桁コメント以上つき、レビュイーとレビュアーともに疲弊しています。

もともと我々のチームではデイリースクラムを昼頃実施していたので、その時間を流用(場合によっては延長して) 同期的にチームでコードレビューを話ながら実施することにしました。
基本的にはレビュイーが自分の PR を画面共有し、チームでその内容に対してディスカッションを行う形式で取り組んでいます。
いわゆる、モブプログラミングというのがありますが、それのコードレビュー版です。

全てモブ・コードレビューをしているわけではないですが、
前提のすり合わせが必要そうだったりコミュニケーションが一定数発生したり・しそうだったら気軽に行うようにしています。
また、その場でマージまで持っていくことには執着せずに、論点が消えたら解散するといった形で非同期と同期なコミュニケーションを使い分けるようにしています。

おかげで今までものによっては数日浮いてしまってたレビューも、大体 1 日ぐらいでマージできるようになってきました。

仕組みの整備

仕組みの整備自体は私が取り組んだものも一部ありますが、
大半がチームで自発的に取り組めたので、直近の事例を紹介しておきます。

Lint・Testによるガードレールの設置

設計思想や品質部分をレビューで担保する点は非常に難しいので、完璧に行うことは諦めることにしました。
代わりにテストや Lint の拡充で対応することにしました。

特にjavierbrea/eslint-plugin-boundariesを導入したことで、
ディレクトリにもたせていたシステムの構造化は、一定実現できたと考えています。

現在他チーム含めて、開発を進めていますが実情としては特定のディレクトリごとに自治権を設け、それぞれにコードオーナーを設けることでカバーしています。しかし、この自治権の担保のためにはそれぞれ自治性のあるコード群が互いに依存しないことが重要です。

特に我々のチームでは Next.js を採用しており、以下のように App ルーター管理下にアプリケーション構造と組織構造を対応付けした形で運用しています。

└── src
    └── app
        ├── (anken) (我々チームの管理下のリソース)
        └── (others)
            ├── abc (abcチームの管理下のリソース)
            └── xyz (xyzチームの管理下のリソース)

これらの構造に意味づけの設定を以下のようにしています。

{
  "extends": ["plugin:boundaries/recommended"],
  "plugins": ["boundaries"],
  "rules": {
    "boundaries/element-types": ["error", {
      "default": "disallow",
      "rules": [
        {
          "from": "anken",
          "allow": ["anken"]
        },
        {
          "from": "others",
          "allow": [["others", {"team": "${team}"}]]
        }
      ]
    }],
  },
  "settings": {
    "boundaries/elements": [
      {
        "type": "anken",
        "pattern": "src/app/\\\\(anken\\\\)"
      },
      {
        "type": "stream",
        "pattern":"src/app/\\\\(others\\\\)/*",
        "capture": ["team"]
      }
    ]
  }
}

特に以下のように記載することで、others 配下のディレクトリを team という変数で capture できます。

    {
        "type": "others",
        "pattern":"src/app/\\\\(others\\\\)/*",
        "capture": ["team"]
    }

capture された文字列は個別の許可設定をする際に個別の許可設定で参照できるようになります。
以下の設定は team 変数が一致するものの み、import を許可することを意味します。
つまり上記の例の場合 abcxyz 以下のリソースは互いに import を禁止できます。

{
    "from": "others",
    "allow": [["others", {"team": "${team}"}]]
}

また、テストに関しても管理画面ということであまりかけていなかったのですが、
バリエーションが複雑な関数は書くようになってきたりと自然と品質を都度刻むようになってきました。

環境差異を減らす

一般的に、エンジニアリングで向き合うべき課題は一定の不確実性を含んでいます。
そのため、エンジニアリングでは如何にして試行回数を試行回数を増やせるか、施行しやすさを担保することは生産性に直結すると私は考えています。

特に我々が抱えているプロダクトはいわゆる Next.js 製の管理画面であり、クラウド環境上のコンテナ上で実行される Production Build の常態でしか再現しない問題が一定数抱えていました。
そのため状況再現のために、クラウド上に都度デプロイする必要があり生産性を大きく毀損させていました。
さらに検証するための環境は、開発者間で共有している状況であり、専有のための利用が一定数渋滞しがちという課題を抱えていました。

そこで簡単ながらもクラウド上で実行する Dockerfile を流用し、docker compose のような Compose Specification でローカルで実行する環境を再現することにしました。
これにより、ローカルでの状況再現しやすくなり課題に取り組む効率は大幅に改善できました。

また、副次的にチーム内で一定渋滞しがちだった、検証環境の利用も一定数解消されました。

Flakyなリリース失敗を改善

前述の通り我々のチームは Next.js 製の管理画面ですが、一部モノレポ構成となっており、ORM に Prisma を導入しています。
モノレポと Prisma の組み合わせとして注意なのが Build の際にconcurrentlyを扱うと
競合してBuildに失敗するという事象がありました。

状況再現がそもそも難しく、解決は難航しました。最終的には単純ながら、Prisma に関する箇所は並列から直列に Build することで解決できました。

再現に難しいからこそ、日頃からチームでアイディアの共有・相談できたからこそ解決できた事例だと考えています。

今後について

定性的な課題を中心に改善の取り組みと紹介をしました。
生産性と一言にいっても色々観点があるので、計測にこだわらず定性的な改善からでも以外と悪くなかったなと感じています。
特にコミュニケーション部分の改善は、色々レバレッジが効くポイントなのでおすすめです。

しかし、定性的なポイントだけだど、継続的に取り組むことは難しいです。
そのためには、four keys などの定量的なメトリクスに基づいて判断していくことが大事だと考えてます。
全社的に生産性に関して取り組む機運があるので、便乗しつつ改善に取り組んでいこうと思います。

そんな Ubie という会社ではエンジニアを採用中です。
一緒に改善していくぞという方のこぞっての応募お待ちしています。

https://recruit.ubie.life/

Ubie テックブログ

Discussion