こんにちは。決済チームでエンジニアとして働いている小須田です。
今回は、多様なメンバーが増えていく決済チームで、「当たり前の品質を保ち続ける」ための取り組みをご紹介します。
TL;DR
- Issueの形式を定め、紐づくPull Requestの粒度をモジュール単位で確定させる
- Pull Requestの形式を定め、マージの影響を明確にする
- コードの満たす品質をCIで担保する
前置き
UPSIDERはエンジニアの採用に力を入れており、決済チームにも多様なバックグラウンドを持つ優秀なメンバーが次々と参加してくれています。それは、新たな強みが多く手に入る環境である一方で、一定以上の品質を保つこととの戦いの場でもあります。
その環境下で私たちが品質を保つ、つまり「当然なされるべきことが、確実になされる」ためには、仕組み化・自動化が必要になってきます。だれがやっても小さい労力で、必須部分が担保される状態が理想ということですね。そこが省力できればできるほど、より本質的な課題に注力する余裕も生まれてくるというものです。
今回ご紹介する内容は、上記の仕組み化・自動化に関するもののうち、タスク・コードの質を担保するためのGitHub上での取り組みに焦点を当てたものです。
逆に今回は、下記の内容には言及しません。
※また、本記事は決済チームのメインである、Go言語によるマイクロサービスを前提とした内容となっています。
Issueの形式を定め、紐づくPull Requestの粒度をモジュール単位で確定させる
IssueもPull Requestも、ドキュメント作成業務には共通することですが、一定以上の質を保ちつつ省力したいなら、定型化してしまうのが効果的です。
定型化で重要なのは、どこになにをどの粒度で書けば良いかが決めることです。そうすることによって、書く側も読む側も迷うことがなくなり、また新しいメンバーの記載漏れもグッと減ります。
UPSIDERでは、チームごとにIssue Templateを作成しており、決済チームでは機能開発時のIssueに下記の内容を記載することにしています。
- Goals
- 目的。Issueのタイトルと密接に関連するものとする
- このセクションにはあまり多くの詳細を記入せず、端的に書く
- Background
- 背景。具体的な事例も書くことを推奨する
- Implementation Ideas
- 設計。概要とともに、テーブル定義、API定義、必要に応じた実装の詳細を記載する
- References
- 参照物。関連Issue、Slackでの重要な会話リンクなどを記載する
画像のように、必須項目なども指定できるIssue Formsが、Public向けのベータ版機能として存在しており、Privateリポジトリでも組織単位で申請することで利用できる場合があります。(参考情報: GitHubコミュニティでの投稿。2022/10/01現在の情報であり、変更の可能性があります) Issue Formsを使えない場合もTemplate自体は利用できるので、ガイドとしてのTemplateを作成し、それに沿わないIssueにはコメントで伝えていくのが地道ながら効果的です。
また、少し特殊な点として「Implementation Ideasの部分でPull Requestの粒度を確定させる」ことをしています。
粒度は基本的にGoのモジュール単位です。決済チームではマイクロサービスの単位でモジュールを切っているため、Pull Requestの粒度と合わせやすくなっています。
具体的には、下記の単位でモジュール = Pull Requestが切られています。
- テーブル定義
- マイクロサービスごとのAPI定義 (gRPC + protobuf)
- マイクロサービスごとの実装
この粒度には賛否あると思うのですが、決済チームではPull Requestは小さく保つことを目指しています。これはレビューのハードルを下げ、マージを迅速に行うためです。 また、この粒度まで確定するルールにすると、実装に入るために一定の内容まで設計を進める必要があります。タスクの進め方も均質化を図ることができ、えいやっで実装してしまうようなケースを抑制する側面もあるのです。
このように、Issueでは形式・内容とともにPull Requestの粒度について、Templateや基準を設けることで均質化を図っています。
Pull Requestの内容と形式を定め、マージの影響を明確にする
Pull Requestも基本理念はIssueと同じです。 定型化して内容を担保し、できた余裕をそのPull RequestのSpecificな内容の議論に当てます。
Pull RequestでもTemplateを作成していますが、担保したい内容は当然Issueとは異なります。プロダクションコードへのマージが行われるため、Issueに比べ注意深く影響を確認できるような項目を増やしています。
下記にシンプルにまとめてみました。
- What: 何を変えたか
- Why: なぜ変えたか
- Reference: 関連Issue, Pull Requestなど
- 必要に応じて「This PR fixes #(Issue)」のように書くことで、Pull Requestとの紐付け機能も利用しています
- Rollback Procedure: 単純にRollbackできるか、できない場合は何が必要か
- Expected Impact: マージされた際の現行への影響は何か
- ここには特に、影響や副作用が出やすい項目のチェックリストを用意
- (Optional)Background: 特殊な事情など
- (Optional)Not Implemented: ToDoとして残したもの
- (Optional)Test Details: 特殊なテスト方式など
これらの項目は一般的なようで、実はメンバーそれぞれが経験してきた職場環境などで文化が異なるため、自分で書き方を考えたり他の人の書き方を読んだりするのにエネルギーを使う部分だと思います。 実際にレビューしている身としては、決まった場所に決まったものが書いてある(なければ指摘をすれば良い)という状態は、かなりストレスフリーです。現状決済チームのメンバーは、これらをきちんと書いてくれており、とてもいい状態だと思っています。
コードの満たす品質をCIで担保する
詳細なコードレビューに関しては、コーディングルールなど用意しているものの、メンバーの強みに頼っている部分が大きいと思っています。それらは今回のテーマとは少し外れるものなので、いまは言及しません。ただし、本質的な部分のレビューに注力するためにも、仕組み化による余裕が大事になってきます。
決済チームのPull Requestのコード品質に関する仕組みは主に2点で、CIによるBuild & Testが正常終了することと、特定権限のレビュアーからApproveされることです。(このレビュアーは自動でCode Ownerが任命されます)
今後追加したい内容としては、テックブログの第2回でも触れていたテストカバレッジの観点をPull Request上から確認できるようにしたいと思っています。検討は必要ですが、カバレッジをマージ条件に加える可能性もあるでしょう。
決済チームのCIはGitHub Actionsを利用していますが、UPSIDERは基本的にmonorepoを採用しているため、他チームの環境に合わせたWorkflowも数多く存在します。
当然変更内容に応じたWorkflowのみを動かしたいのですが、その場合はブランチ保護がうまく働かず、「動かしたWorkflowのみ正常終了すればマージ可能」ということができません。
これを解決するため、UPSIDERではMerge GatekeeperというPull Requestマネジメント用の機能を作成しました。これにより上述でやりたかった細かなマネジメントが可能になります。
実はMerge Gatekeeperは決済チーム独自のものではないのですが、MITライセンスでOSS化してあり、導入もとてもシンプルなので、この機会に紹介させてもらいました。ぜひお試しください。
あとがき
決済チームの当たり前の品質を支える取り組み、いかがでしたか?
シンプルに均質化、省力化しており、できた余力でメンバーにバリバリ活躍してもらおうという姿勢が伝わっていたら幸いです。今回はいわゆる守りのお話でしたので、今後は決済チームの攻めのお話もしていきたいと思います。
お楽しみに!
宣伝
UPSIDERでは、成長企業のための法人カード「UPSIDER」と、すべてのBtoB取引でクレジットカードを利用できるビジネスあと払いサービス「支払い.com」を提供しております。
まだまだプロダクトで実現したいことがたくさんあり、プロダクトの急激な成長に伴う課題も増えている中で、一緒に事業を前に進めてくれるエンジニアを絶賛募集中です。
カジュアル面談もやっておりますので、少しでもご興味のある方は、ぜひご連絡ください!!!