はじめに
STORES レジのiOSアプリ開発をしているたまねぎです。
この記事では、 STORES レジアプリチーム内で「チーム開発プラクティス」を作成したことの紹介をしています。
チーム開発プラクティスとは
まずチーム開発プラクティスとは何かについてですが、一言で言うと「チーム開発を進めやすくするための具体的なアクションリスト」のことを指しています。
本記事では、これを作るに至った背景やモチベーション、実際の進め方や成果物などを全体的に説明していきます。
作成の背景
まずは、チーム開発プラクティスを作成するに至った背景についてです。
小規模チームでの開発フロー
STORES レジアプリは、2021年6月にリリースしたプロダクトで、リリース後もスピード感を持って機能追加や改善を進めています。
開発体制としては、開発初期から現在に至るまで常に1.5~2人という少人数体制で開発を進めてきており、 特にリリース後から現在に至るまではフルタイムのエンジニアが私1人だけという状況が続いていました。(マネージャーを除く)
エンジニアが少ないという背景もあり、開発フローや環境の整備は最低限のことしか行っておらず、具体的には以下のような流れでスクラム開発「風」のフローで業務を進めていた形になります。
- 2週を1スプリントとし、毎スプリントリリースを行う
- スプリント初日をリリースプランニング日として、そのスプリントでリリースするバージョンの機能を決める
- スプリント最終日に、PMやデザイナーも含めて振り返りを行う
- QAチームのリグレッションテストが完了次第、アプリの申請を行ってリリースをする
課題点
この開発フローでは大きな問題は特になく、技術的な挑戦や運用業務をしながら、ほぼ毎回のリリースで目に見える機能追加を行うことも出来ていました。
そのため、小規模チームとしては順調に回ってはいたのですが、別の視点で見ると、「少人数である」「初期段階からプロダクトに携わっている人しかいない」という前提があったからこそスムーズに進められていた背景があったと思っています。
これらのことから、今のスタイルのまま今後チーム規模を拡大してギアをさらに一段上げようとすると、開発作業が進めづらくなるのではないかという懸念がありました。
具体的な課題と解決のためのアクション
具体的に新メンバー参入時に課題になると考えていたのは以下のような点です。
- 開発作業が個人の能力に依存しており、複数エンジニアでの開発に最適化されていない
- 最小限のドキュメントしかないため、初期キャッチアップコストが高い
- 開発作業における決め事が、現メンバーの脳内にしかない
そしてそれぞれの課題に対して、実際に新しい仲間が入社してくれるタイミングで、問題解決のためのアクションもTryし始めました。
本記事では、これらの取り組みの3番目に当たる「チーム開発プラクティスの作成」についてピックアップしてお話をしていきます。
作成のモチベーション
チーム開発プラクティスを作るモチベーションになったのは、「開発作業における決め事が、現メンバーの脳内にしかない」という状況です。
STORES レジアプリチームにはコーディング規約のようなものはなく、過去からの積み重ねによる共通認識が各エンジニアの頭の中にあるだけでした。
さらに開発の進め方についても同様で、毎スプリントごとの振り返り(KPT)で改善は回しているものの、そこで生まれたTryの取り組みなどは書き捨てのドキュメントに残っているだけの状態でした。
もしこの状態で新メンバーがチームに合流した場合、
- 「リファクタリングしたい部分を見つけたけど、これってどうやって進めればいいんだろう?」
- 「ドキュメントってどのレベルまで書かないといけないんだろう?」
- 「開発をガンガン進めるために残業沢山しないといけないのかな...?」
などなど、 簡単な言葉で表すと「チームのノリ」のようなものがわからない状態になっているのではないかという懸念があったと思っています。
「チーム開発プラクティス」の作成は、こういった課題を解決するために進め出した動きになります。
作成の流れ
ここからは具体化に向けての実際の動きになります。
方針決め
まず作成するにあたってどういったものを作りたいかは、以下のような方針を立てました。
- 一度決めたことも状況に応じてどんどん変更していけるものにしたい
→ ルールのように強い強制力を持たせるのではなく、Tryの集合知のようなものにする - チームで継続的に更新していきたい
→ 特定の個人を中心にメンテするのではなく、メンバー全員が自由に更新しやすいものにする - 誰かが決めたことに従うためのツールではなく、チームでの共通認識を言語化するためのツールにしたい
→ 業務の中で気づいたことや意識したいことをチーム内で話し、共通認識が取れたものを項目として追加する
進め方
方針が固まった後はバージョン1.0を作成する作業に入りました。実際に行った流れは以下の通りです。
- 現在自分(既存メンバー)の頭の中にある開発プラクティスを言語化し、草案としてまとめる
- 既存メンバー+新メンバーに、漏れている観点やそれぞれ意識していることなどをさらに加筆してもらう
- 草案が完成した段階でプラクティスの読み合わせを全員で行い、認識の擦り合わせや項目の修正を行う
叩き台については、ある程度自分の方で作成する形にはなってしまいましたが、ここでは「メンバー間で会話をして認識を合わせた」ことが重要だったなと感じました。
誰かが作った取り決めを守ってもらうことではチームの文化は醸成されないので、各個人が自分事として考えるタイミングを設けることが必要だったと思います。
バージョン1.0全文
これらのステップを踏まえ、現在の私たちの開発上の取り組みを明文化したものが、下記のチーム開発プラクティスです。
# はじめに このドキュメントは、「必須で対応しなければならない」という強制力を持ったものではなく、開発業務を補助するためのものとして用意しています。 チームに新しく加わった人が「このチームはこういう意識で開発進めてるんだな」とわかるものになると良いなと思っています。 内容はチームメンバー全員にオーナーシップがあり、振り返りを通して適宜更新していくことを想定しています。 # 実装 ## コーディング - コードはチームで共同所有する。対象部分に精通した人に依存させることはしない - 警告は放置せず、気づいた箇所はすぐに修正する - Lintのルールは適宜disableするだけでなく、ignoreすることも積極的に行う - 使わなくなったコードは、コメントアウトするのではなく削除する - エラーの発生は握りつぶさず、ユーザーへのフィードバックやログ送信など、状況に応じて適切な対応を行う - 「何をしているか」をコメントの記載で示さない。命名などでわかりやすくすることを意識する - 「なぜそうしているか」についてはコメントで補足する - プロジェクト全体の一貫性を重視する. 既存のコードから同様のAPIやネーミングがあれば可能な限り揃える - 既存のコードを変更する必要があればリファクタリングを行い、全体の一貫性をキープする ## リファクタリング - 実施するにあたり許可を取る必要はない - プランニングの内容に捉われずにいつでも実施して良い - 大規模リファクタリングについては状況次第で要相談 - 基本的には、一気に変更を加えるのではなく、小さいサイクルを継続的に回すことを推奨 - 別PRにしてキレイに切り分けることよりも、気づいた時にスピード感をもって対応することを優先する - ただし、コミットは極力分けるようにする - リファクタリングをにあたり、テストがない箇所はそれに合わせて追加する # テスト ## ユニットテスト - ロジカルな部分やクリティカルな部分については、ユニットテストで確実に動作を担保する - Viewレイヤーについては変更が起きやすい部分でもあるため、無闇にテストを拡充する必要はない - もちろんクリティカルな部分については記載したほうが良い - テストが失敗した場合、一旦コメントアウトすることで問題を回避しない ## 手動テスト - 自動テストで担保しきれない部分を中心に確認し、基本的には自動テストの方を拡充する - PRのdescriptionに実施したテスト結果を記載し、何を確認したのかわかるようにする ## QAテスト - 不具合が発見された箇所は、可能であれば自動テストを書いて問題の再発を防ぐ - QAフェーズでの品質アップを最大化するため、開発時に特殊ケースの考慮を疎かにしすぎない # コミュニケーション ## コードレビュー - レビュワーは実装者個人を批判するような記載はせず、あくまでコードに対して建設的な意見を述べる - 指摘事項を「別で対応する」という選択はせず、そのPRで問題を解決する - ただし対応内容が大きすぎる場合はその類ではない - スケジュールの問題などで妥協したApproveを出すことはしない - レビュワーは、レビュイーにどんな対応をして欲しいのか伝わるように工夫する - [must][nits]などのラベルをつける - Code Suggestion を使う ## ドキュメンテーション - 継続的にメンテナンスできるものに注力して作成する - 保守されずにすぐ陳腐化するようなドキュメントを無闇に書く必要はない - サービスSPECはドキュメント化して常にメンテナンスして管理していく # 働き方 ## プロジェクトの進め方 - 進捗の遅れを残業でカバーするようなやり方は持続可能ではないのでやらない - 1人が過労働を始めると、そこに引っ張られて他の人も同じ働き方になりがちなので注意する - 問題が起きている場合は隠すことはせず、素早くチームに共有して解決策を検討する - スケジュールを守るためにクオリティを落とすことはせず、スコープやスケジュールを調整することで解決できないか考える - 変更を拒絶するのではなく、変更に耐えうる設計を常に維持しておく - 上手くいくように慎重に進めるよりも、まずやってみてうまくいかなかったら素早く捨てる - デザインや体験を含む改修については確認フローを踏む - スプリント振り返り時など、プラクティスのアップデートをした方が良い点に気づいた場合は、その都度更新する
作ってみてどうだったか
このドキュメントを元にして認識を合わせることにより、ふわふわしていたチーム内での共通認識を、新メンバーも含めてしっかり言語化することができました。
時間を取って「自分達のチームはこういう方針で進めていこう」という話が出来たのも、今後の業務の進めやすさに良い影響があったと思います。
さらに、元々のモチベーションは「新メンバーにチームの方針を伝えやすくする」ことでしたが、結果的に「既存メンバーの認識や意識も整理された」ことにもなりました。
動き方に迷った時など、基本に立ち返る指針としても活用できるものになったと思います。
まだ作り始めの段階なので、未成熟な部分や足りない観点などもあると思いますが、これは継続的なアップデートを通して良くしていくことを前提としています。
そのため、今後については以下のような流れで、開発フローの中に明示的なプラクティス更新タイミングを設けることになりました。
- スプリントごとの振り返りで、Keep, Problem, Tryをチーム内で話し合う
- Tryの中で開発プラクティスに取り込んだ方が良いものは、その場で追加・修正する
書き捨てのドキュメントではなく、チームの成長と共に進化していくものとして育てていきたいと思っています。
おわりに
以上が STORES レジアプリチームの開発プラクティス作成の話でした。
もし私たちのチームに少しでも興味を持っていただけた場合、モバイルアプリエンジニアはもちろん、他のポジションも絶賛採用活動中です。
関連するリンクも下記にまとめてありますので、良ければこちらもご覧いただければと思います。
関連リンク
採用
ブログ
技術登壇
- iOSDC Japan 2021: SwiftUI+GraphQLで新規プロダクトの継続的破壊(Con… / Takuya Yokoyama - YouTube
- iOSDC Japan 2021: 初めてのハードウェア対応 / Takeshi Yokokoji - YouTube
- SwiftUIっぽくした話 - Speaker Deck