SMARTCAMP Engineer Blog

スマートキャンプ株式会社(SMARTCAMP Co., Ltd.)のエンジニアブログです。業務で取り入れた新しい技術や試行錯誤を知見として共有していきます。

「仕様」のレビューをPRでしていませんか? 〜Design Documentが解決したスパゲッティコードとの向き合い方〜

はじめに

こんにちは!

2022年度の新卒として入社して早一年が経ちます、ピーターこと佐々木です。

私の配属先のプロダクトであるBOXIL EVENT CLOUDは、様々な背景(後述)から自分含め3人いる開発メンバーの誰一人既存のコードがどのような思想のもとで書かれたものか分かっていない状態からスタートしました。

表から見るとそんなに規模の大きくない1つのサービスに見えるのですが、アプリケーションが2つに分かれており、DBも別々に管理していたりと、全体像を把握するだけでも一苦労に見えました。

その上、ソースコード自体も詳細に分かれすぎていて、複雑に入り組んでいます。いわゆるスパゲッティコード状態です。

そんな状態のプロダクトとの付き合いももうじき1年になります。

そこで今回は、どのようにしてBOXIL EVENT CLOUDにチームとして立ち向かっているのかについて紹介いたします。

プロダクトの概要と開発背景

BOXIL EVENT CLOUD について

スマートキャンプでは、主にSaaSを導入したい企業様向けに、それぞれの企業様のプロダクトの紹介の場を設けることで、潜在顧客様との接点を作る手助けをさせていただいております。

オンライン展示会を開催するプラットフォームとして、そのような接点の1つとしての役割を求めらているのが、私たちが開発している「BOXIL EVENT CLOUD(ボクシル イベント クラウド)」(以下、イベクラと言います)です。

イベクラの開発背景

イベクラは、もともとベトナムでのオフショア開発から始まったプロダクトで、スマートキャンプのエンジニアはあまり関わってこなかったプロダクトでした。

しかしながら、開発効率を上げるために約1年前にオフショア開発から社内開発に切り替えました。そうして生まれたのが、私たちイベクラチームです。

ですが、ある問題が浮上します。それは引き継ぎの際にあまり整理されたドキュメントなどが得られなかったことです。その結果、私たちは中身を全く知らないプロダクトをパッと渡されたところからメンテナンスを始めるという状況に等しいところから、開発を始めなければなりませんでした。

最初の課題

そのため、すでにある大量のコードがどのような思想で書かれたものなのか不明だったのが最初の課題でした。

例えば、

  • このGemはどういう目的で、いつ入れられたものなのか、今後も必要なのか
  • 今あるこの機能は一見不要そうなのだが、どういう経緯で作られたものなのか
  • システムが複数リポジトリ、複数AWS環境に跨っているが分かれている必要はあるのか
  • 大量にあるテストコードが本当に意味のあるコードになっているのか

などです。

そして、実際に調査する中で求められているビジネス要件に対して、1+1を計算するのに量子コンピュータを持ち出しているような、過度な道具や手段を用いているところが多々見つかりました。

いわゆる「ハンマーしか持っていなければすべてが釘のように見える」状態で作られたプロダクトと言えるやもしれません。

そして出会ったのが、今回ご紹介したいDesign Documentです。

Design Documentとは

GoogleのDesign Doc

一般的にはGoogleのDesign Docが有名で、それをアレンジしたものとして、私たちのチームでは活用しています。

これは、ソフトウェアの設計を定義するためのものであり、開発者自身がコーディングタスクに着手する前に作成し、主に実装方針と設計がその際に考慮したトレードオフと共に書かれているものです。

詳細は、こちらをご覧ください。

Design Docs at Google

イベクラチームにおけるDesign Document

このDesign DocをDesign Documentとして、イベクラチームでは「仕様のレビューを行なう文章」として捉えています。

※前提として私たちはスクラム開発で業務を進めています。

Pull Requestを作成するとき、次のような問題背景を書くと思います。

  • 何が問題なのか / なぜこの変更が必要なのか
  • 今の仕様・設計はどうなっているのか
  • 変更の目的/歴史的背景
  • 設計上のトレードオフ

これらをPRを出す前・コードを書く前に書いておいて、その内容をチームでレビューしてからコードを書き始めましょうというものです。

これにより、PRを出すときには、レビュアーはすでにその変更の背景を理解しているため、実装のレビューに集中できます。

GitHubのIssueとして書いて、PRにリンクするのも1つの手だと思いますが、私たちはNotionで行っています。レビューを行なうのに、それは特定の行、単語にコメントが書ける方が適していると考えているからです。

フォーマット

また、フォーマットは次のようにしています。

  • タイトル/著者/作成日時/最終更新日時
  • 概要
  • 問題背景
  • 提案
  • Sign off(承認)

この他にも項目を追加することもありますが、これが基本です。

また、このDesign Documentにはレビューしやすい以外にもメリットがあります。

Design Documentがチームにもたらすもの

手戻りが発生しない

コードを書いてPRを出してから、「その設計どうなの?」と仕様の検討に戻ることがありません。なぜなら、その認識を合わせるのが、Design Documentの役割だからです。

そのため、PRがマージされるまでの時間もとても短いです。

「後からこのPRでこの修正も入れた方がいいんじゃない?」ということもありません。

もし後から問題が見つかった場合は、別のDesign Documentとして切り出され、以前のドキュメントをリンクするようにします。

問題認識の差が埋まる

イベクラ開発初期は、自分がタスクにアサインされた箇所しか内部的にどのような仕様になっているかが把握できていませんでした。そのためレビューするのもなんだかとても難しかった印象があります。しかし、Design Documentを書き、あらかじめ整理されたドキュメントを読むことで新しく開発に参画した人でも問題の背景がわかり、レビューがしやすくなります。

また、チームで設計のレビューを行なうので、技術に長けている人の知見が活かしやすくなります。逆にプロダクトに詳しくなかったり、知見があまりなかったりしても自信を持ってPRを作成できます。

考えが整理される

チームメンバーに変更の背景を伝えようと文書化する過程で、思考が整理され無駄のない修正になります。

おっちょこちょいな開発者は、この修正で動くからいいだろうとたくさんコードを書いてPRを出してから、よくよく調べたら今実装したクラスはすでに実装されていて、それを使えばいいだけだったということに気づくことがあるかもしれません。

逆に、一見不要そうな機能でも実は使っていることもあります。このクラス使ってなさそうだから削除してしまえとPRを作ったら、実は使っていたなんてことは山ほどあります。

そのようなことは、コードを書き始める前に問題背景を明らかにし、現在のコードになっている歴史的背景をまとめておけば起きないはずです。

応用が効く

Design Documentの考え方は、レビューのためだけに使うのも勿体無いです。

リモートで働く上で、議論を進めるのにもかなり便利だなと感じています。

周りにある全ての議題・問題に対して、Design Documentを書くことで非同期的に議論を進めることができ、会議時間が減らせると思います。

Design Documentのポイント7選

実際に運用する中で、分かってきた7つのポイントについて紹介します。

問題背景を書くことに99%の労力を割く(つもりで書く)

フォーマット に書いたような構成でDesign Documentを書いていますが、このドキュメントを書くのに最も意味があるのは問題背景の部分です。

人によって何を問題と捉えているかは、実は違うことがよくあります。

「問題だと思っていたことが仕様でした」ということや「別の問題を解決したから今のコードになっている」ということはたくさんあります。

イベクラで例を挙げると、ジョブキューで行っている動画の視聴記録の保存処理があります。この処理は負荷が高く、他のプロセスを圧迫する可能性があるため独立させていますが、その背景を知らないと管理のしやすさを優先してまとめようという話になるかもしれません。

したがって、自分達が使っているアーキテクチャはどのようなもので、かつ歴史的経緯はどうなっているのか、という背景を明らかにすることが重要です。そして、「確かにそれが問題だね」という共通認識を持つことが一番大事です。

これを疎かにすると、間違った方向にプロダクトを進めてしまう可能性もあります。

そのため、1行のバグ修正でも背景が共有できてなかったら書きます。

Design Documentを書くのは、手間だと感じるかもしれませんが、マージされるまでの時間の短縮になるので結果的に効率は速くなると考えています。

こちらとは思想が真逆ですが、今のプロダクトの状況的にこの判断が今はベターだと思っています。

読者が知っているであろうことから始める

現在の仕様を知らない、未来の開発チームが見ても話がわかるようにDesign Documentは書いておく必要があると思っています。

そのために、現在のチーム内で周知の事実であってもなるべく省略はせず、今新しく入った人が見ても問題背景が分かるように説明しておくことが大事かなと思います。

未来の開発者がコードを見て、なんでこういう仕様になっているのだろうと疑問に思ったときに、そのコードが書かれた時にプロダクトが抱えていた問題が正確にわかれば、どう修正していけばいいかも自ずと見えてくるはずです。

過去のPRを読みに行く

問題背景を調査するために、過去のPRを遡ることが重要でした。

git blameは欠かせません。

今からやろうとしている修正が、実は過去に一度失敗した方法だったなんてこともここで分かります。

この機能、このライブラリ、この変数、使ってなさそうだな、消しちゃえーっとやってしまってから、実は使ってましたなんてことが山ほどありました。

しかし、ちゃんと事前にgit blameしてPRを見に行くと、周辺の修正が一緒に見られるので、どの機能を作るために必要だったのかが一瞬でわかります。

この過去の経緯をしっかり把握しておくことが、スパゲッティを解くのには欠かせないと感じました。

もう過去のPRを読み、問題背景に書かずには私はPRを作れません。

PRから辿れるようにする

新しくプロジェクトに関わってきた人が、なんかこのコード読みにくいな、と思った時に、そのコードが書かれた経緯が遡れることはとても重要だと思っています。

これは私たちが実際にその状況に置かれて痛感しました。

背景を知っていれば「あ、このコードは一時的な解決策として書いたものだったけど、後でリファクタしようと思っていたんだな」とか「この機能は今後使われる見込みがないから、一時的にこの状態なんだな」と判断できます。

昔は、こういうビジネス要件があったから、作られた機能だったが、今の要件に照らすと入らないというのも自信を持って言えます。

しかし、過去のPRに変更背景が記載されていないことも多々あり、化石から恐竜の姿を想像するように、当時の背景を推測しかできないこともありました。

そういうことが起こらないように、これから作るPRには、Design Documentのリンクを貼っておきたいです。

議論の足跡を残しておく

Design Document上では議論をします。

そのため、行ごとに指摘がしづらいGitHubのIssue機能は使わず、Notionでドキュメントを書くようにしています。

また、ドキュメント内で、このような感じで合意を取っています。

チーム間、メンバー間でのすり合わせが大事なので、誰と議論したのかを残しておくことが大事です。

  • [x] Aさん
  • [x] Bさん
  • [ ] Cさん

実装後はDesign Documentを更新しない

Design Documentに詳細に問題背景を書くこと、これはそのドキュメントで果たすべき責任範囲を定義するのとほぼ同義です。

そのため、実装後にDesign Documentを修正し、後からこの修正も入れようと考えるのは、よくないと感じます。

もし、仕様が変わって新しいことをするときは、新しいDesign Documentとして、何が問題だと思ったのかを明らかにするとともに、歴史的経緯として前のドキュメントのリンクを入れておくといいと思います。

タスクと紐付ける

現在私たちは、バックログの管理をNotionで行なっています。

そして、チケットをすべてDesign Document形式で書く運用にしています。

そうすることで、管理がしやすいと思っています。

導入による心理的な変化

業務への関わり方が不慣れだった私目線での良かった点をあげます。

チームへの発信がしやすい

Design Documentは書くだけならタダなので、もっとここをこうした方がいいんじゃないか?という提案をチームに発信しやすくなりました。

これにより、なんかちょっともやっとするところがあるんだよな、でも話に行って作業の邪魔をしてしまうのも悪いし…という時に、サラッとドキュメントを書いて、見ていただくようにするとお互いの好きなタイミングで議論が進められるので、気兼ねなく相談できるなと感じています。

タスクを進めるときに迷いがない

どうやってタスクを進めようかという迷いがなくなりました。

最初の頃は、何をどこから調べればいいのか、どういう形に持っていったら理想なのかと頭を悩ませていましたが、今は違います。

歴史的背景を明らかにして、何が問題なのかを整理すれば自ずと解決策は分かるということに気づきました。

自信を持ってPRが出せる

事前にチームと問題を共有し、自分が何をするかをすり合わせているので、後からそもそも問題解決方法がいけてないという指摘を受けることがないからです。

今後の課題

イベクラでは、全てのタスクが調査の側面を持っていて、現在の仕様確認と歴史的背景を一度整理するところから入らないことには話が進みません。

そのため、プランニングでポイントをつけることも一切できていないです。

対して別サービスのBOXIL SaaS 開発チームでは、プランニングの段階で何をどのように修正するかの精度が高いです。

誰かしらが現在の仕様について知っていて、その人を中心にみんなで話し合いながら、どういうふうに実装していくかの方針までをプランニングで決めていました。

Figmaでどういう風にメソッドが生えているかを図を使ってわかりやすくして、問題背景の共有が同期的に行える状態にあります。

そのため、誰が実装しても同じくらいの時間で終わるみたいな見積もりが成立すると思っています。

しかし、イベクラチームもDesign Documentを書き続けていくことで、歴史的背景がドキュメントとして蓄積され、いずれは誰もが仕様を理解している状態に来るのではないかと思っています。

そうなった時に、やっと私たちのスクラム開発がスタートするのです。

最後に

まだまだチームとしてどのように開発を行なっていくのが効率的かは模索中です。

今後もチームでの効果的な業務の進め方の改良を続け、小さなチームでも大きな成果を出せるということを証明していきます。

ここまで読んでいただきありがとうございました!