一休.com Developers Blog

一休のエンジニア、デザイナー、ディレクターが情報を発信していきます

Design Doc でチームを跨いだ開発を円滑に行う

この記事は 一休.com Advent Calendar 2024 7 日目の記事です。

宿泊事業本部 ユーザー向け開発チームの原です。 一休.com と Yahoo!トラベルの主にフロントエンドの開発を担当しています。

今回は、普段の開発でコードを書き始める前段階で Design Doc を作ることで、円滑な開発を進められるようになったというお話をします。

チーム構成について

まず、前提を共有するために私達が普段どのような体制で開発しているかを説明します。
私が所属している宿泊事業本部 ユーザー向け開発チームは、一休.com と Yahoo!トラベルの主に toC のユーザー向けの機能開発をしています。ユーザー向け開発チームのメインのミッションはユーザー体験を向上させることであり、そういった施策の機能開発を素早くリリースできることを大事にしています。
一方、プロダクト開発においては機能開発だけではなく、プログラミング言語や依存ライブラリのアップデートや、アーキテクチャの見直しといったシステムの健全性を向上させる取り組みも重要です。
機能開発とシステム改善を同じチームが両立して行えることが理想的かもしれません。しかし、Nuxt でできたフロントエンドのアプリケーションに関しては、施策に関する機能開発はユーザー向け開発チームが、システム改善はフロントエンド改善チームという専任のチームが担当しています。
これは、変化の激しいフロントエンド開発でベストプラクティスを追い求めるには施策開発とシステム改善をする責務を分けたほうが進めやすいという判断によるものです。
実際、フロントエンド改善チームの取り組みにより、

  • Nuxt2 から 3 へのアップデート
  • Options API から Composition API への書き換え

といった Vue/Nuxt 界隈の進化に追従したり、

  • GraphQL の client-preset の導入
  • デザインシステムの推進

なども機能開発を止めずに完了しています。こういった取り組みにより、かなり開発者体験がいい環境で日々機能開発ができています。

少し古いエントリーですが、フロントエンド改善チームの取り組みは以下でご確認できます。 user-first.ikyu.co.jp

開発チームと改善チームが分かれている状態においては、うまくコミュニケーションを取らないと問題が生じます。
お互いどんな取り組みをするのか共有しないと、

  • 開発チームの施策で触るコードと、改善チームのリファクタリングしたいコードがコンフリクトする
  • 改善チームが行ったリアーキテクトを開発チームがちゃんと理解しないとベストプラクティスではない実装をしてしまう

といったことが起こり得ます。
特に「ベストプラクティスではない実装をしてしまう」というのは避けたい問題です。
そのため、開発チームが実装した機能は小さな修正を除いては基本的に Pull Request (以下 PR) でレビューしてもらうことになっています。
実際レビューの際に、最適な実装にたどり着くまで時間がかかってしまったということが何度かありました。

前置きが長くなりましたが、こうした別のチームにコードレビューを依頼するとき、円滑な開発を進めるために私が必要だと思っていることを紹介します。

コードレビューについて

私はレビュアーとしてコードをレビューするのは非常に労力のかかる仕事だと思っています。
よく「実装が終わって PR を出したので、もう少しで完了します」みたいなことを言ってしまいがちですが、コードレビューは実装と同等か、場合によってはそれ以上の負担が発生しうる作業だと思っています。
というのも、Approve されるとリリースできるという運用においては、レビュアーの仕事はコード書く人(レビュイー)と同等の責任が発生するためです。
いきなり数百行、数千行規模の差分が発生する修正をレビューするときには

  • その施策や修正の背景
  • 実現するための最適な設計になっているか
  • その diff を取り込むことでどんな影響が起こり得るか

などを考える必要がありますが、それらを一から考えるのは、コードを最初から書くのと同じくらいの負担がかかるものです。
上記のような考慮はコードを書く側(レビュイー)は当然考えたうえで実装しているはずなので、レビュイーからレビュアーにうまく伝えられると負担を軽減できます。
どういった工夫でレビュアーの負担を軽減しようとしているかを紹介します。

いきなりコードを書かない

先程も述べたような差分が数百行、数千行規模の PR をいきなりレビューしてもらうのは、PR の description やコメントをいくら丁寧に書いたとしても、レビュアーの負担は大きいです。
そこで実装に入る前の段階で Design Doc を作成して、大筋の実装内容について合意を取るようにしています。
Design Doc は以下のようなアウトラインで書いています。

## このドキュメントの目的
## やりたいこと
// ここではビジネス的な視点でなぜこの施策をするのかを書きます
## 仕様
// ここでは上記のやりたいことを満たす機能要件を書きます
## 対応内容
// ここではシステム的な視点でどんな対応が必要なのかを書きます

このドキュメントの目的、やりたいことが記載された Design Doc のスクショ

Design Doc の目的は、実装者とレビュアーの間で大まかな実装の合意をとることです。

新規ページ作成を例にすると

  • URL をどう命名するか
  • コンポーネントの階層と、各コンポーネントをどう命名するか
  • サーバー(GraphQL)からデータをどのように取得するか
  • 機能要件を満たすロジックをどう実装するか
    • 既存のロジックで使えるものは何か

などを Design Doc で決定します。
特に命名は先に決めておくと実装、レビューともに楽です。

既存のロジックを使えるというアドバイスがもらえる

(↑ 既存のロジックを使えるというアドバイスがもらえる)

Design Doc で事前に実装方針の合意をとることで、「なぜこのような設計にしたのか」をレビュアーがレビュー時に考える必要がなくなります。 また、レビューする段階で大まかな実装イメージがついているので、レビューの負担が軽減されると考えています。

Pull Request を出す際に気をつけていること

Design Doc との乖離がある場合

Design Doc で実装方針の合意をとれたら、実装をして、完了したらレビューに出します。
当然、実装する中で Design Doc で決めた通りにいかなかったり、もっといい方法が見つかったりすることもあるでしょう。
それを何も共有せずレビューに出してしまうとせっかく実装方針を決めた意義が薄れてしまいます。
Design Doc 時の決定と大きく変わる場合は、レビューを出す前に Design Doc 自体を修正して、もう一度合意を取り直すようにしています。
Pull Request の Description やコメントにその旨を書くだけで伝わるような些細な変更の場合は、レビュー段階でそれを伝えるようにします。

レビュアーの負担を最小限に

当然ですが、レビューを依頼する前に自分で見つけられる粗は見つけておくべきなので、自分がレビュアーのつもりでセルフレビューをします。
施策とは直接は関係ないリファクタリングなど、レビュアーが「これはなぜいま修正が必要なのか?」と疑問を持ちそうな箇所はコメントを残しておきます。

  • 動作確認方法
  • 影響する既存機能が元通り動いていることをどうテストしたのか

といった情報も記載します。
また、実装していてもっと良い書き方があるはずだが思いつかなかったような場合、どんなことを試してうまく行かなったということを残しておくとよいでしょう。

最後に

今回はチーム間を跨いだレビューで私が気をつけていることを紹介しました。
常にペアプロ・モブプロを行っていたり、チームの成熟度が高い場合は Design Doc を作成することの必要性は薄いかもしれません。
ただ、実装タイミングでどんな意思決定がなされたのかという情報は、時間が経った後から見返す際、有用になります。
また、

  • レビューのコストは実装と同じくらいのコストになり得る
  • レビュアーの負担はレビュイーの工夫次第で軽減できる

というのはどこでも共通する話だと思います。