はじめに
エージェンシー開発チームでPMをしている若林です。
ランサーズエージェンシー株式会社ではLancersAgentとPROSheetというサービスでフリーランスの方向けにお仕事を紹介するエージェントサービスを運営しています。
背景
エージェンシー開発チームは2021年の下期ごろから開発体制が拡充され、2022年には3本のプロジェクトが並行して開発されている状態になっていました。
参考
2020年までのリリース数と2022年のリリース数の比較
年度 | masterマージ数 |
---|---|
2020 | 53 |
2021 | 106 |
2022 | 386 |
2022年は2リポジトリの合計(363+23)
※途中から新規の機能を作ったためリポジトリ自体も増えて2つのリポジトリで開発することになりました
# masterマージ数集計
git log --after '2022/01/01' --before '2022/12/31' --oneline --merges | grep "master" | wc -l
今まで細々と維持を続けていたチームが急にスピードをあげて開発をすることになり、こんな壁にぶち当たることになります。
よくある課題
- コンフリクト
- 検証渋滞
本プロジェクト特有の課題
- トリガー地獄
- リポジトリが増えた
こんな壁があったとしても、事業成長を止めないために「出したいタイミングでリリースを継続していく」ことが必要になってきます。
「今」欲しいと言われた機能を2ヶ月後に出したとしても喜ばれないので、欲しい機能をタイムリーに継続的に出すことが開発チームには求められます。
今までより多くなったメンバーと大きくなったスコープで、スムーズにリリースし続けるためにチームとして取り組んできたことを1年の振り返りも兼ねて記載していきたいと思います。
コンフリクト
Aさんの方が早く開発していて途中から開発要望が入ってBさんも同じ機能に対して別の開発を始めました。
Aさん方が速くリリースしてBさんがリリースしようとした時に、Aさんの開発差分を取り込めていなかったため修正箇所が競合してしまいました。
その結果一度受け入れOKとなったものが正しく動作しなくなってしまったりというデグレードが発生するパターンもありました。
上記のようなコンフリクトを回避するための取り組みとして大きく打ち手を打ったのは、以下2パターン。
- 小さく速く出す
- 同じところを触らない
1個目の「小さく速く出す」については読んで字の通りですが、開発者だけでなく、レビュワーやテスターもまとめて一気に実施するのではなく、
機能が確認可能になった時点で、できた順にレビューをしていく、順次テストをお願いするなどの運用をして、機能を細かくして速く出すということをやっていました。
それでも、大きな開発になってしまうとマスターマージまでの機能を小さくできない時もあります。
そんな時には機能を触る人(チーム)を分けることで対応していました。
運用として大きく変わったところは、開発定例会議。
今まではアップサイド開発、維持などチームごとにバラバラにやっていた定例をまとめて、開発進捗・リリース予定と開発範囲を確認してお互いの機能に影響がないかを洗い出す。
コンフリクトが発生しないように調整可能な場合は開発順序を変えるということをしていました。
開発順を変えられない場合であっても横の人がどの機能を触っているかわかることで、影響範囲の伝達ができ、重大エラーとなるようなコンフリクトが発生せずにリリースを続けられました。
検証渋滞
開発者10人に対して検証環境(ステージング)が一つ、ステージングで開発完了したものを本番環境にリリースするという運用をしていました。
容易に想像がつくかもしれないですが、人間が介在してくるところで渋滞が発生します。
[渋滞ポイント]
- 検証環境への反映待ち
- 検証環境での受け入れ待ち
これらを回避するためにやったこと
- 検証にリリースする人を複数人に増やす
- 検証環境を複数用意する
週ごとに検証環境のブランチを作成してその週で検証するブランチは全て検証用ブランチにマージしていきます。
その検証用ブランチは開発者であれば誰でも追加、検証環境への反映ができる状態にしました。
このことにより一人に検証反映の負荷が偏らず、検証環境への反映待ち時間を減らすことができました。
また、ステージングの前の検証環境をSREチームに用意してもらい、事前にある程度受け入れを行ってもらうことができました。
これによって最終的にはステージングで確認が必要だとしても大きなエラーを事前に潰すことができて、検証待ち時間を短縮しました。
トリガー地獄
本プロジェクトはINSERTとUPDATEのタイミングでトリガーを使い、別テーブルに格納することで履歴を残していく方式を従来からとっていました。
[トリガーを使っていたことでリリースタイミングで困っていたこと]
- 最新のトリガーが本番を参照しないとわからない
- トリガーとテーブルに差分があるとエラーになる
このうち最新のトリガーが開発環境で見れなかった事象については週次のDBのレプリケーション時にトリガーを含めてdumpをとってリストアする形式にSREチームに変更してもらったことで解消し、開発環境でも最新のトリガー状況がわかるようになりました。
トリガーとテーブルの差分についてはトリガーの記載方法を変えることで解消しました。
今までの書き方
INSERT INTO 履歴テーブル VALUES (null, NEW.id, NEW.カラム名, NEW.カラム名, NEW.カラム名, NEW.カラム名)
変更後の書き方
INSERT INTO 履歴テーブル SELECT null, 元テーブル.* FROM 元テーブル WHERE id = NEW.id
カラムの修正を行うたびにトリガーにもカラムの変更を反映する必要があり、トリガーとテーブル間での不整合が起きやすい状況になっていたため、リリース時に頻繁にエラーを起こす原因となっていました。
トリガーの記載方法を変更したことにより、テーブルとトリガーの不整合が発生しなくなり、リリース時のエラーが大幅に軽減されました。
リポジトリが増えた
参照するリポジトリが増えることで管理コストも上がりましたが、プロジェクト全体のチケットを参照できるKANBANを作成することでリリースの抜けもれなく運用することができるようになりました。
(将来的には新しいリポジトリに機能全体を移行していきたい)
まとめ
こうやって書いてみるとリリース運用の試行錯誤の1年だったなという感じです。
来年以降は体制もまた変わっていくので、より良い開発スタイルを開発チームとユーザで目指していければと思います!(抱負)
明日は@manamin0521さんです。