こんにちは。 Sansan 事業部プロダクト開発部で iOS アプリエンジニアをしている中川です。
本記事は Sansan Advent Calendar 2020 の 23 日目の記事です。
今回は iOS アプリ開発ではなく、チーム開発する上での課題と解決へのアプローチに関する話なので、 iOS アプリエンジニアに関わらず、同じ悩みを抱えている方には読んでほしいです。
Sansan iOS チームでの課題
私が所属するチームでは Pull Panda と呼ばれる GitHub をチームで利用する際に欲しくなる Slack と連携したリマインダー機能 (Pull Reminders) や Pull Request で設定したルールに従って、レビュワーを自動アサインする機能 (Pull Assigner) に加え、 GitHub の情報を元に様々なレポートを表示してくれる機能 (Pull Analytics) を兼ね揃えたサービスを愛用していました。
この Pull Panda ですが、 2019/06/17 に GitHub が買収することを発表しました。*1
これに伴い、 Pull Panda で利用していた Pull Reminders とPull Assigner は GitHub の標準機能として搭載されました。*2
そして、 GitHub は 2020/10/14 に Pull Reminders と Pull Assigner を止めることを Pull Panda 利用者へ通達します。それに伴い、チームでも移行作業を行い、使ってみたのですが、 Pull Assigner について、いくつかの機能差異がありました。
機能 | Pull Assigner | code review assignment |
---|---|---|
GitHub Teams を利用した自動アサイン | ○ | ○ |
自動アサインのアルゴリズム設定 (Load balancer / Round robin) | ○ | ○ |
特定メンバーの除外 | ○ | ○ |
選択されたメンバーのみに通知 | ○ | ○ |
自動アサインのカウント方法の選択 (Count existing members / Ignore existing members) | ○ | ✗ |
自動アサイン後のチームアサインをどうするか? (Delete after assigning reviewer(s) / Do not delete) | ○ | ✗ |
自動アサインする際に参照するレビュー回数の閲覧 | ○ | ✗ |
自動アサインする際に参照するレビュー回数のリセット | ○ | ✗ |
Pull Assigner と code review assignment の機能差異
Sansan iOS チームで code review assignment に移行する前の Pull Assigner の設定は以下でした。
機能 | 設定 |
---|---|
Auto-assign | One reviewer |
Algorithm | Round-robin |
Proxy team | None |
Counting method | Ignore existing reviewers |
Team review request | Delete after assigning reviewer(s) |
この設定は code review assignment では実現できず、運用でカバーすることになりました。
そして、自動アサインに参照しているレビュー回数が見れなくなったのはチームのレビュー負荷が分からなくなってしまい、なんとなくレビューを多くしている気がするけど、チームに頼れなかったり、レビュー回数を見て、自身のスループットを振り返ったりが出来なくなってしまいました。
こちらについては GitHub の Insights や Pull Analytics でも分からず、代替手段がありませんでした。
レビュー負荷を見える化しよう
取り得る代替手段が存在しないなら、用意しましょう。
チームメンバーやそのメンバーがレビューした Pull Request は GitHub から取得可能です。
チームメンバーの閲覧用にホスティングサーバーが欲しくなるので、すでに利用実績のある Heroku を利用します。
Heroku では多くの言語をサポートしています。*3
Web API は GitHub GraphQL API を叩いて、 JSON レスポンスを返すだけのシンプルなものなので、個人的に学習している Go を選択しました。Go での Web Framework は人気があり、パフォーマンスが売りの gin を使います。
最初のプロトタイプは以下のようなものになりました。
Pull Request の作成日を指定して、指定した作成日から現在までのチームのレビュー回数のランキングが見られます。
一旦、見られなくなったレビュー回数は見られるようになったので、チームの KPT の場でお披露目してみました。
メンバーからのフィードバックで出来ていないことは以下になります。
- 集計する範囲の期間指定
- Pull Request の Diff の合計を表示
現在の構成のままで Pull Request の Diff の合計を表示しようとしてみましたが、結果が表示できませんでした。
原因は Heroku の 30 秒タイムアウトに引っかかってしまったようです。*4
リクエストの処理フローはフォームで指定された Created の内容を元にチームメンバーを取得したあとにチームメンバー分のレビュー回数に加え、 Pull Request の情報も取得しに行く都合上、 30 秒ではレスポンスを返せなくなってしまいました。
Heroku の 30 秒タイムアウトを突破する
一度のリクエストでの処理が多くなってしまったので、分割します。
分割するのにクライアントでの処理も必要になってしまったので、 gin で行っていたフロントエンド処理を分離します。 gin には RESTful API を残し、別途、フロントエンド処理を行うために Vue.js を利用します。
Vue.js は既存プロジェクトへの導入のサポートが強く、 Vue CLI を既存プロジェクトのルートディレクトリで動かせば、適切に必要なファイルを配置してくれます。今回は以下の設定で Vue CLI でプロジェクト作成をしました。
vue create . # Vue CLI v4.5.9 # ? Please pick a preset: Manually select features # ? Check the features needed for your project: Choose Vue version, Babel, TS, Router, CSS Pre-processors, Linter # ? Choose a version of Vue.js that you want to start the project with 3.x (Preview) # ? Use class-style component syntax? No # ? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes # ? Use history mode for router? (Requires proper server setup for index fallback in production) Yes # ? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Less # ? Pick a linter / formatter config: Prettier # ? Pick additional lint features: Lint on save # ? Where do you prefer placing config for Babel, ESLint, etc.? In package.json # ? Save this as a preset for future projects? (y/N) N
npm run serve
でローカルでサーバーが立ち上がり、フロントエンドの開発がすぐに始められます。
ホットリロードも有効なので、コードを変更するだけでブラウザで反映されて、開発における反復処理を高速で回すことが出来、スピーディーに開発できました。
メンバーからのフィードバックを反映させたプロトタイプは以下になります。
開発を終えて
Web の進歩は目覚ましい
Vue CLI でプロジェクトを作るだけでフロントエンドのデファクトスタンダードの設定が完了しているという開発体験はよりスピーディーにプロダクト開発に入ることができました。 TypeScript によるコンパイル、 ESLint による静的解析、 WebPack によるホットリロードでコーディングの変更による影響が短時間にフィードバックを得られ、再び、コーディングに戻れるのは素晴らしいなと思いました。 iOS にもホットリロード欲しい…。
フロントエンドでオーバースペックな技術を選択してしまい、学習とデバッグに時間がかかって完成が遅れた
今回、 Vue.js を選択したわけですが、その中でも取り分け最新の構成にしてしまっています。
2020/09/20 にリリースされたばかりの Vue.js 3.0 で新機能である Composition API を使って、 Component 分割までしました。
また、 Vue.js は TypeScript をサポートしてますが、自分自身が使ったことがない TypeScript を選択しています。
とても、勉強にはなったのですが、開発後期にはモチベが続かず、 Vue.js 2.0 で JavaScript で書けば良かったなぁと後悔してました。
最後に、同じような課題に悩んでいる方の参考になったのであれば、嬉しいです。
また、自分たちはこういう取り組みをしているよというアイデアがあれば、コメントで教えて下さい!
*2:Pull Assigner and Pull Reminders are available on GitHub as code review assignment and scheduled reminders.
*3:公式サポート言語として、 Node.js / Ruby / Java / PHP / Python / Go / Scala / Clojure に加え、 Linux 上で走るなら、どんなプログラム言語でもサードパーティの buildpack によって Heroku で利用することが出来ます。
*4:https://devcenter.heroku.com/articles/request-timeout#timeout-behavior