「実装意図」「実装根拠」を伝えるということ

この記事は、[KMC Advent Calendar 2022](https://adventar.org/calendars/8005) の10日目の記事です。
また、[ten986 Advent Calendar 2022](https://qiita.com/advent-calendar/2022/ten986)の10日目の記事でもあります。
普段は ten986 Advent Calendar 2022 で個人ブログを開発しながら、そのブログ上にポエムを書く活動をしています（？）
ちなみに体調不良で大遅刻しました。

# 想定読者

- **既にチーム開発を行なっているが、レビューでのやり取りに課題を感じる人**
    - **メインです**
    - 特に **品質が重要な** チーム開発の場合重要です
- ↑のような人に対して、**教える際のチェックリストがほしい人**
    - 箇条書きにしたので、各項目ごとに意識できると思います
- **チーム開発初心者で、レビュー時のやり取りが分からない人**
    - 本当はメインターゲットにしたかったんですが、にしては抽象的な内容が多めなので、「こういうことが必要になるんだろうな」くらいの気持ちのがよさそうです

## おことわり

個人開発や小規模開発では、必ずしも重要ではないです。
自分の頭にある実装方針が全てである可能性があるためです。

# 前書き

**あなたは企業の製品開発チームのメンバーです。**
ここでは日々、実装タスクの洗い出しやその実装、そして Pull Request の作成やそのレビューが行われています。

さて、チーム開発でコードを書いていく上で重要なことは何でしょうか？
チーム開発である以上メンバーで歩み寄りながら開発を進めるべきなのですが、その点で非常に重要になるのが **「実装意図、実装根拠を伝えること」** だと考えています。

実際筆者は、レビュー時のやり取りで **「なぜこの実装にしたか」** と聞くことが多いですが、これは「実装根拠」をすり合わせ、**よりよいコードに辿り着くため** に行なっています。また、**レビューコメントが多くなる場合は、総じて「実装根拠」が伴っていないことが多い** と感じており、「実装根拠をコードに乗せ、伝えてくれれば」と思うことがよくあります。
（実装意図が不明瞭である場面は出会っていないと思います。チームのプロセスが順調に動いていることによると思っています）
特に研修段階では、「どのように実装意図、実装根拠を伝えるか」という能力は不足していることが多く、また非常に重要視しているので、特に重点的に教える努力をしています。

そこで、チーム開発を進める上で、なぜ実装意図や根拠を伝えるべきなのか、そしてその伝え方について説明していきます。
チーム開発でどの視点が足りないか？　や、どの能力が不足しているか？ という気づきになれば幸いです。

## この記事での定義

- 実装意図
    - どのようなことが実現したいか？
    - そのためにはどのようなコードを書く必要があるか？
- 実装根拠
    - なぜそのコードが正しく動くのか？

# 「実装意図や根拠」は伝えるべき

実務でコードを書くうえで、「動くものを作る」こと自体はあまり難しくありません。みんなコードは書けます。
しかし、コードが動くだけではチーム開発では受け入れられません。

なぜならチームで開発する上では、 **「どのようなことが実現したいか」** がまずあって、それを実現するためコードがあるためです。コード自体が目的ではないです。
実現したいことさえ伝わっていれば、いくら動かないコードだとしても、レビュワーは修正することができます。レビュワーの脳内でも、「実現したいことから、どのようなコードが書くべきか？」をシミュレーションできるためです。 **これが、この記事で言う実装意図です。**

そして、コードを書く際には、 **「なぜ、このコードで実現したいことが実現できるのか」** が非常に重要になります。
動きそうなコードを書くこと自体は簡単ですが、それが「正しく動くこと」を保証する必要があります。そのため、理由づけをしていきましょう。**これが、この記事で言う実装根拠です。**

# どのようにすれば「実装意図や根拠」が伝えられる？

企業の開発メンバーを想定するため、「動くコード、動きそうなコードが書ける」ことは前提とします。
（この前提が満たされていない場合は、そもそも難しい実装や未知の分野の担当をしていると思うので、実装に入る前にあらかじめ詳しい人がサポートに入るべきです）

## 実装意図や根拠の伴った「コードを書く」

コードの実装意図や根拠をチームメンバーに伝えるためには、そもそも **実装意図や根拠の伴ったコードを書く** 必要があります。

### 実装意図について

- **実現したいこと** が明確である
    - 普通、カンバンなどを用いてチケット化されている
    - 逆に、チケットは実現したいことが明確であるべき
    - （この記事の前提条件である）
- **実装範囲** が明確である
    - これも、普通チケットで範囲が定められている
    - （明確でない場合、複数回実装されたり、実装漏れが起きたりする）
- これらの実現したいことが、**コード上のどこで実装されているか？** が分かる
- これらはチームの方針に寄るところが多く、「どのように書くか」「どこまで具体的に書くか」はチームで合意が取れているとよい

### 実装根拠について

- **「上手く動く理由」が明確に説明できる**
    - 理由づけがなければ、それは **「なぜか動くコード」** でしかなくなる
        - レビュワー視点ではこの「理由づけ」を試みるので、 **「なぜか動くコード」に対しては理由づけが効かず多くのコメントが付く**
- **言語やフレームワークの知識** を用いて説明できる
    - 「この記述だとこういう挙動をするから・・・」 など
    - 知識に基づいて、「別の実装方法はなかったか？」が検討余地
- あまり知られていない知識（自分の知らない知識）は、**信頼できる情報源** を用いる
    - 言語やフレームワークについて詳しくない場合は、調べていく
        - これについては **「検索力」** は必要になる
        - 調べれられない or 面倒であれば、他のメンバーに聞いてもよい
    - 開発においては、**既存実装を参照する** 場合も多い
        - この場合、 **既存実装の実装意図** を必ず考えること
        - 実務のコードには基本的に実現したいものが背景に存在し、**結果であるコードのみを見ても信用できない場合もある**
        - 逆に実装意図が分かれば、ガンガン再利用して効率化してよい。コピペ上等
    - ドメイン知識についての情報源は、開発体制による
    - **情報源は、可能であれば共有する**
        - 自明な知識は共有しなくてもよい場合があるが、慣れなければ共有する方向でよい
- **設計方針** が適切である
    - 上手く動くにしても、実装によって今後の実装に影響が出ることもある
    - コードに触れていたり、知見を収集していたり、製品の朽ちる様子を見たりする必要がある気がする
        - すぐ得られる知識というより、経験は必要
- **上手く動くことを検証する**
    - 動作確認をする
    - テストコード実装

## 実装意図や根拠を「伝える」

さて、コードに実装意図を乗せることができれば、 **実装意図を伝える** ことができるようになります。

- 大前提として、**正直に伝えること**
    - 「自分が知らないこと、分からないこと」を隠したい気持ちを捨てて、自分の知ってる情報を正確に伝えることを意識する
    - 「分からない」と言えば、その知識は教えてくれる
        - レビュワーは怒りたいわけではなく、対話をしたいので
- **正確に伝えること**
    - 「正確に文章で伝える方法」に自信がない場合は、 **テクニカルライティング** について調べるとよい
        - すでに良記事が多く存在していると思う
- **実装時に考えたことを伝える** 
    - 「このような背景があった」
    - 「このような対策をするとよい結果が得られた」
    - 「逆に、これはダメだった」
    - 「結果、このような実装になった」
    - これらは実装した本人なら分かるが、**他の人には非自明な情報** である
        - レビュワー視点としてもエスパーすることは不可能ではないこともあるが、**実装した本人が伝えるのに比べて非常にコストが高い**
- コードやPRのメッセージを見れば、実装意図や根拠が伝わる状態にする
    - **適切なコメント、命名、ファイル整理** などにより、実装意図は伝えられることが多い
        - そのため、あえてメッセージで明記しなくても伝わる
            - （伝わってしまうが、その影響でメッセージを書かなくていいと勘違いしてはいけない）
        - この辺りは記事も多く、命名だけで記事になったりする
    - **対応したチケット** を書く
        - チケットに書かれていることからズレた対応範囲があれば、明記する
    - **上手く動くことの検証方法** を書く
        - 動作確認方法
        - **自分が検証した時は自明でも、他人が知らない情報は結構ある**
    - 伝わらなかった場合には、「コメント」がつく

## 実装意図や根拠で「話し合う」

ここまでができれば、「実装意図の伝わる Pull Request」が出せるでしょう。 そうすれば **「実装意図を元にしたレビュー」** ができるようになります。 これも少しコツがいると思うので、まとめていきます。

### レビューする側

- **「実装意図」を汲み取る**
    - 「実現したいこと」があってのコードなので、それを必ず理解する必要がある
    - レビュワーは実装意図を理解する必要があるものの、実装意図に対してレビューすることはあまり多くないはず
        - レビューとは別のプロセス（チームの会議や、PR以前のチャットなど）で方針を定めておくべきなので
    - 正しく動かなかった！ ということはあるが、それは「正しい挙動 ≒ 実現したいこと」が存在するから
- **「実装根拠」を理解する**
    - 基本的にレビュワーの仕事はここであってほしい
    - **設計方針** について考える
        - 「実装根拠」に挙げた一番難しいポイントなので
- **レビュワー視点による「実装意図」「実装根拠」を考えた上で、レビューする**
    - **コードが正しく動くだけでは不十分**

### レビューを受けて

- **「この部分を直してください！」** とコメントをされた場合
    - レビュワー視点での「実装意図」「実装根拠」の方が上回っているので、普通はその通りに直せばよい
    - 「修正しました！」程度のコメント返しでよい
- **「このような実装の方がよいと思います」** とコメントされた場合
    - **レビュイー、レビュワーのどちらが良いか不明** だが、「実装根拠」はレビュワーから提示されている
    - 明らかにレビュワーの根拠が強い場合
        - 「自分はこのような根拠で書きましたが、そちらのがよいと思うので修正しました！」のようなコメント返しになる
    - 明らかに自分の実装根拠の方が強い場合（少しレア）
        - 「自分はこのような根拠で書いたので、修正していません」のようなコメント返しになる
        - 実装根拠となるソースを提示すると、伝わりやすい
        - **重要なのは、コメントされても修正が必ずしも必要ではないということ**
    - どちらの主張も通る場合
        - 明らかにレビュワーの根拠が強い場合以外は、大体こうなる
        - そして、やりとりが多くなる
        - 往復が少なそうならPR上でやりとりしてもよいし、面倒なら同期的ミーティングをしてもよい
- **「なぜこのような実装になっているのですか？」** とコメントされた場合
    - **質問** であるので、基本は **「実装意図」「実装根拠」** について自分の意見を返せばよい
        - 例外を除き、特にコードの修正は必要ではないことが多い
    - **「実装意図」「実装根拠」** が不明瞭の場合が多い
        - PRのメッセージに追記することで、伝える
        - （例外）コード上で、コメントや命名などを変えることで、不明瞭さがなくなることもある

# 逆に、「実装意図や根拠」を伝えてもらう側として必要なこと

長々と「伝える側」について書きましたが、伝えてもらうためには **環境** も重要です。

- **分からないものは分からないと言える環境**
    - **心理的安全性** は大事
    - 「分からない」と言ったら評価が落ちるかも・・・と思わせてはいけない
- **ドメイン知識についての情報源**
    - 実装根拠のところで書いたが、アクセスしやすいドキュメント体系が必要
- **時間**
    - 時間が限られている場合、品質どころではない