「エンジニア組織の開発生産性・開発者体験向上の取り組みをシェアしよう! by Findy Advent Calendar 2023」のシリーズ2・18日目の記事です。
はじめに
ペイトナーファクタリング事業部でEMをやっている 脇田(@shimpeee_)です。
2023年の1年間で行った、チームの開発生産性改善につながった取り組みをいくつか紹介します。
正直、1つ1つの取り組みそのものにはほとんど目新しさはないです。ただ、当時どういった課題があり、どういった過程を経て取り組みを行うに至ったかのストーリーは、どんな現場であっても唯一無二です。社内のメンバーに向けて、将来一緒に働くメンバーに向けて、そして自分自身の業務の棚卸として、チームの活動の歴史を残しておきたいと思い書きます。
1年前の状況
ちょうど一年前、開発生産性アドベントカレンダーでチームの活動を書いていました。
ざっくり言うと、「いろいろ施策やったけど、定量的な数値改善は見られなかったね。1番の要因は、PRあたりの変更行数が大きいことだね!」と、PRサイズを小さくしなきゃだめだーと気づくまでのストーリーとなっています。
あれから一年間、PRサイズを小さくすることを中心として各種施策をやってきました。中でも効果が大きく、今でも継続している取り組みをいくつか紹介します。
取り組み紹介
フィーチャーフラグを使ったトランクベース開発
背景〜導入まで
※ フィーチャーフラグそのものの説明は割愛します。こちらの記事がよくまとまっておりますので参考まで。
PRサイズを小さくするのに最も効いたのはフィーチャーフラグの導入です。
1年前の記事では、「フィーチャーフラグなるものがあるらしいので、使っていきたい」という締めくくりでしたが、今ではもはや「フィーチャーフラグなしでどうやって開発するんだ?」くらいには不可欠になっています。
フィーチャーフラグ導入前のチームには、「機能として不完全なコードをmasterにマージする」という習慣がありませんでした。
基本的に「masterにマージ = ユーザーに見せられる状態」 という方針でしたので、当然1つ1つのPRサイズも大きくなります。変更行数が数千行を超えるPRがたくさんありました。
大きな機能開発時はリリースブランチ戦略を取ることでPRサイズを下げること自体はできていましたが、都度masterをマージして最新化しつつコンフリクトを解消する作業は非常に辛いものがありました。
フィーチャーフラグおよびトランクベース開発の導入は、単なるプラクティスの導入だけでなく、不完全なコードをmasterへマージするという新たな文化づくりでもありました。
当時は僕含めて他のメンバーもフィーチャーフラグ・トランクベース開発共に未経験だったので、不完全なコードをマージしていくことには結構な不安がありました。
まずはメンバー全員で
- フィーチャーフラグとは何なのか
- どんなメリットがあるのか
- 想定されるリスクは何か
- 具体的な運用イメージ
といったことを、「よし、これならリスクを最小限に抑えつつ運用開始できそうだ!」と全員が納得できるまで議論しました。
基本的にはどんなことも「まずはやってみようぜ!」とクイックに試していく文化があるペイトナー社ですが、この時はやや慎重に導入を進めていた記憶があります。自分達自身がプラクティスの可能性を信じきれていないと、本来良いものであっても扱いきれず終わってしまっては勿体無いですからね。
結果
「PRサイズは原則100行以下、大きくても150行以下」を目標で運用し、元々は数百行だったPR変更行数が今では100行を切るまでになりました。PRサイズが小さくなることのメリットはあえて言うまでもないですが、
- レビュー負荷の軽減
- リードタイム短縮
- コンフリクトリスク低下
- バグ発生リスク低下・品質向上
といった恩恵を大きく享受できています。
改善ポイント
今ではチームにとってなくてはならない存在になったフィーチャーフラグですが、いくつか改善ポイントはあります。
改善ポイント①:フラグ除去作業が高難易度
フィーチャーフラグは、基本的に以下のように if文で囲う形で使っています。
if Flipper.enabled? :search puts 'searchフラグが有効' else puts 'searchフラグが無効' end
一連の機能リリースが完了すると、最後にフラグを除去する作業が発生します。
この時、新規で実装した機能であれば単純にフラグを取り除くだけというシンプルな作業になることも多いです。
しかし、既存機能の改修となるとそう単純にはいきません。既存のロジックを活かしつつ新機能の実装を組み込んでいくので、フラグを使った分岐も複雑になりがちです。そうすると、フラグ除去の際に、残すコードと消すコードの区別がつきづらくなります。
実装者本人ならコンテキストの詳細を把握しているかもしれません。しかし、実装者以外にとっては残すコードと消すコードの区別は非常に難しい作業となります(これは実際にフラグ運用をやってみるまで気づかなかったポイント)。
フラグを使う際は、TODOコメントとして「リリース後削除すること」を記載していましたが、加えて「実装者以外でも削除時の作業が分かるよう、詳細にコメントを残す」ことをルール化して、現在運用中です。
改善ポイント②:PRは小さくなったが、全体像が見えづらい
これは直接フィーチャーフラグとは関係ありませんが、「PRサイズが小さくなったことで、PR同士の関連性が把握しづらい」という弊害が生まれました。
これに対しては、PRのテンプレを見直し、概要欄に「やらなかったこと」を明記するようになってレビュワーの負荷がかなり軽減されました。
「あえて後回しにしてるのか、考慮できていないのか、忘れているのか?」を想像しながらレビューするのは、想像以上に認知負荷が高いです。
あとは、後述するユーザーストーリーマッピングをやるようになり、1つの大きな開発の全体像の共通認識が醸成され、「全体像が分かりづらい」という状態から脱しつつあります。
レビュー基準の明確化
「レビューコメントにプレフィックス(must, imo, nits, ask 等)をつける」というプラクティスはごく一般的かと思います。うちのチームでは、
- mil(modify it later = 今じゃなくていいけど、あとで必ず修正してね)というオリジナルプレフィックの追加
- mustとmilの線引き明確化
- 各プレフィックスのコメントに対する対応ルール明確化
を行いました。
やったことは割とシンプルですが、リードタイム短縮や開発者体験の向上に効いた施策です。
背景〜オリジナルプレフィックスの作成まで
元々、レビューでコメントをする際には must, imo, nits, ask 等のプレフィックス(以後、ラベルと表現)をつけて、コメントの意図を明確にする文化は根付いていました。
ただ、
- must の基準も人それぞれじゃない?(おれのmustとあなたのmustは違う)
- 内部品質に関する指摘のみが残っており、リリースしてユーザーに提供しても大丈夫な状態の時は、一旦マージしてそのあと指摘内容対応した方がユーザーへの価値提供早くできてよくない?
- 結局どこまで対応しなきゃいけないの?このPRで対応しないにしても、別タスク切って対応するかしないかは誰がどうやって決めるの?
といったモヤモヤを抱えており、もう少しルールを明確化しようということになりました。
既存の各ラベルの定義を改めて言語化していると、「mustではないから一旦リリースはしちゃっても問題ないんだけど、コード規約・コード品質・パフォーマンス・ユーザビリティ観点で、このPR内じゃなくてもいいけど絶対に対応はしてほしい」を表現できるものが現状ないことに気づきました。
「mustではないから〜(中略)〜絶対に対応はしてほしい」な状態を表現できるラベルを他社事例を参考に記事漁ってみました。しかし、意外と見つからなかったので、こうなったら作ってしまえ!ということで、オリジナルラベルを作ることにしました。
議論の結果、「Modify it later」略して「mil」に決まりました。キャッチーかつ発音しやすい、かつ意味も分かりやすい、お気に入りです。
(完全に余談ですが、僕は仕事においても守破離を大切にしており、まずは型を守るとこから入ることが多いので、変に独自性を発揮することを基本的に避けるようにしています。なので、オリジナルラベルの作成過程、特にみんなでラベル名を考えるのは楽しかった思い出です。)
レビュー基準とルール
レビュワー&レビュイー双方の目線合わせのため、各ラベルを使うための基準を作成しました。
ラベル | 意味 | 対応 |
---|---|---|
must | PRの中で必ず対応してほしい! | 同一PR内で必ず対応する。 |
mil(modify it later) | あとで必ず対応してね! | 新たに課題を作成し対応する。 |
imo(in my opinion) | 自分の意見や提案・好み。自分ならこう書くけどどうかな? | 新たに課題を作成し対応する。 |
nits(nitpics) | 些細な指摘。ほんの小さな指摘だけど、できれば直してほしい。インデントやタイポ | 新たに課題を作成し対応する。 |
[must]
と[mil]
の区別
[must]
- Jira課題の受け入れ要件を満たしていない
- バグがある
- セキュリティ・個人情報漏洩リスクがある
- 計算量が大きすぎる
- マージ後の修正コストが非常に大きい
- DB設計、URL設計等
[mil]
must
には該当しないが、コード規約・コード品質・パフォーマンス・ユーザビリティ観点で必ず対応してほしい
上記をベースに、
- mustの指摘がなければ、レビュワーはApproveとする
- must以外を同一PR内で対応するかは、実装者に委ねる
という運用ルールを設定しました。
結果
基準が明確になったことで、当初の課題感であった、
- must の基準も人それぞれじゃない?(おれのmustとあなたのmustは違う)
- 内部品質に関する指摘のみ(= ユーザーには提供できる状態)の時は、一旦マージしてそのあと指摘内容対応した方が、ユーザーへの価値提供早くできてよくない?
- 結局どこまで対応しなきゃいけないの?このPRで対応しないにしても、別タスク切って対応するかしないかは誰がどうやって決めるの?
というモヤモヤの解消と、結果としてPRがマージされるまでの時間が短縮されました。
恩恵としては、定量的観点でのリードタイム短縮よりも、定性的観点でのモヤモヤ解消の方が大きかった気がします。
「早くリリースしたいのに、細かい指摘があってなかなかマージされない、、、もうユーザーには見せられるのに、、、」という状態で指摘の修正対応を続けるのは、レビュイー・レビュワー双方にとって辛いことです。
もちろん、「じゃあ今回の対応はここまでにして、一旦マージしましょう」のようなコミュニケーションを都度取ればいいだけなのですが、それも相応のコストと心理的不安を伴います。
今回のように、ルールで解消できる部分はルール化して、気持ちよく開発ができる状態を作ることをEMとしては常に意識しています。
コーディング規約の充実
元々「コードレビュー観点」として、
- Rails way に則っているか?
- DRY, KISS, YAGNIの原則に則っているか?
- 命名は適切か?
- 規約や記法がプロジェクトの作法に則っているか (空気を読めているか)
- (他にもたくさん)
といった項目は明文化されていました。
しかし、これらの観点はやや抽象度が高く、実際のPRでのコードベースで議論する際の指針としては使いづらさもありました。
そこで、大枠の方針は上記コードレビュー観点に任せるとして、具体のコードベースでのルールを決めるため、コーディング規約を作成することにしました。
今の組織フェーズでは、イチから規約を網羅的に作るのはコストが大きすぎるかつ過剰だろうとの判断で、具体例ベースで積み上げて作っていく方針にしています。
PRレビューでの具体のやりとりで規約化した方がよさそうなネタがあれば、規約ネタのDBに溜めておきます。
溜まった規約ネタは、スクラムイベントとは別で開催している週次のチーム全体定例の中で全員で議論を行い、規約かするか否か、する場合はどのような規約にするかを決定します。
この定例にはCTOも参加しているので、様々な観点で議論ができ、スピーディーに意思決定ができる場として非常に有意義な議論ができています。
こういったルールメイク系の取り組みは、一旦やり始めたはいいものの形骸化しがちなので、定例のアジェンダに組み込むことで仕組み化し、継続することができています。
またしても余談ですが、この定例のファシリテーションは僕がやっているのですが、規約ネタ議論のファシリテーションはとても難しいです。最終的には決めの問題となることが多く、答えのないお題がほとんどです。
そんな中、参加者に対して健全な対立を促し、合意形成しながら最終結論までもっていくのはまさにファシリテーションの真髄だなー(超難しいなー)と思いながら毎週やっています。
ユーザーストーリーマッピング
2年ほど積読していた『ユーザーストーリーマッピング』をふとしたきっかけで読んだ時に、「これは今すぐ取り入れるべきだ!!!」と直感しました。直感の理由を当時はうまく言語化できてなかったですが、間違いなく今のチームに足りないピースである確信はありました。
チーム全員ユーザーストーリーマッピングは未経験だったので、すぐにチームで輪読会を行い、次の大きなリリース案件で早速実践してみました。ちなみにその案件は、特許取得にもつながった「Moneytree LINK」との連携でした。
ただ、見よう見まねでユーザーストーリーマッピングをやってはみたものの、うまく活用するのは想像以上に難しかったです。
マッピングを終えた直後は、とても恩恵を感じられていました。
必要となるユーザーストーリーを全員で洗い出し、『ユーザーストーリーマッピング』の本に登場する「スライス」の概念でMVPを選定し、最初のリリースまでにやるべきストーリー/後回しで良いストーリーの線引きができました。
ここまでがトータル3hほどで完了し、「3hでMVP選定まで終わった!すげー!」と盛り上がっていました。
しかし、PJを進めるうちに、大きな手戻りやPOと開発者間での仕様の認識齟齬が何度も発生しました。
手戻りや認識齟齬発生の原因を振り返ると、プロジェクトのWHYについての理解が甘く、「ユーザーストーリーマッピングの最も大きな目的のひとつである『共通認識』の醸成ができていなかった」、原因はこの一言に集約されました。
また、PJ途中でストーリーの追加や変更が入りますが、作ったユーザーストーリーマップとJiraとの紐付けが最新化されず、次第に誰も見なくなってしまいました。一度作ったあとの活用方法に課題が残りました。
以上の反省を生かし、現在進行中の新たなPJでは、「共通認識の醸成」をテーマとして、とにかくストーリーのWHYを突き詰め、かなりの時間をかけてユーザーストーリーマッピングを行いました。
期間にして約2週間、チームとしてマッピングだけをし続けました。非常にハードな作業となりましたが、PJ初期のコミュニケーションに投資したおかげで、実装フェーズに入ってからは非常にスムーズに開発を進められています。
メンバー全員の共通理解が得られている状態なので、常にユーザーストーリーマップを見ながら会話をし、常に最新化される流れを作ることができています。「作ったあと見られない」という課題も、同時に解消することができました。
AIレビュー
AIコードレビューツールである「CodeRabbit」を導入した話を、別記事にまとめました。
結論としては、費用対効果高くてめちゃくちゃいいね!という手応えなので、今後もがんがん使っていきたいと思っています。
終わりに
最後まで読んでいただきありがとうございました!!!
ペイトナーに少しでも興味を持っていただけましたら是非、ペイトナー 採用情報 をご覧ください!!
現在ペイトナーでは、以下ポジション積極採用中です!!!
- リードエンジニア