「標準」「規約」を思慕するエンジニアはAIに心の安寧を求める

## はじめに

[ジーズアカデミー 技術記事書いてみた編 Advent Calendar 2024](https://qiita.com/advent-calendar/2024/gsacademy)の４日目を担当します[philosophy_note](https://x.com/philosophy_note)です。2021年に東京LAB11期を卒業して現在は卒業生の方が起業した会社でエンジニアとして働いています。

アドベントカレンダーで執筆するのは今回が3回目になります。

↓去年の記事

https://qiita.com/philosophy_note/items/294bd82a369aa5465d8f

↓３年前の記事

https://qiita.com/philosophy_note/items/0b6f8751e61728c26d30

改めて見たらエンジニアになってもうすぐ３年になります。
時の流れを早く感じるとともに己の未熟さに悲観する毎日です。

最近はコードレビューを通して他の人のコードにコメントする機会が多くなりました。
勉強不足なことに加え、悩みやすい性格であることを自負する私は理想的なコード提案をするのに悩む毎日を過ごしています。
今回は流行りの生成AIを活用してその悩みを解決しようとした検証になります。

## コード×AI

2022年11月にChatGPTが公開されて以降、
コーディングと生成AIは密接不可分なものとなりました。
私も日々ChatGPTやGithub Copilotを使用しています。

より良い活用方法を模索する中で、
Forkwell様主催の次のイベントに参加しました。

https://forkwell.connpass.com/event/330408/

イベントの内容は非常に勉強になり、
次の本も入手して読みました。

[コード×AIーソフトウェア開発者のための生成AI実践入門](https://gihyo.jp/book/2024/978-4-297-14484-5)

テクニックの紹介に留まらず、
中長期的な視点での活用も記載されており
大変勉強になりました。

その中で私が興味を持ったのが、
スタイルガイドやベストプラクティスを明示的に参照させて
AIに具体的な提案をさせる考え方です。

## 標準への誘導

Github CopilotやChatGPTにコードを生成させる際、
『1~100までの数字のうち、15で割り切れるものを集めた配列をPythonで返却して』
などといったプロンプトを与えることが一般的です。

これでも問題ありませんが、
スタイルガイドを参照させることでより適切なコードを生成させることができます。

この考え方が有用であると感じたため、
既存のコードの変更を行う際です。

テストやリファクタリングをAIに依頼する際、
適当に次のようなプロンプトを与えていました。

『このコードのテストを書いて』
『リファクタリングして』

このプロンプトでもある程度はコードを生成してくれますが、
既存の実装に引っ張られて不適切な記述のまま生成されることや
効率的なコードが生成されないことがあります。

これに対して、
解答の選択肢を限定することでAIからより具体的な提案を引き出すことを実施します。

前述したイベントでは『Martin Fowlerのリファクタリングカタログを参照してリファクタリングしてください』
といった例が紹介されていました。

このように、参考資料を明示的に提示することで
AIによるコード生成の精度を向上させることができます。

ということで試してみました。

## 結論

指定しないケースよりも具体的な回答は返却されるが、
ハルシネーションが発生しているケースが多いため、
あくまで補助的なTipsとしてのみ使用すべきだと思いました。
（上述したコード×AI本のP.189と同じ結論です）

以下、この点を踏まえてお読みください。

## 規約・資料一覧

使用するケースのたびにスタイルガイドや資料を探すのは面倒なので
自分が普段する技術についてAIが参照できそうな資料をまとめて使用することにしました。

|技術|スタイルガイド|URL|
|---|---|---|
|Ruby|Bozhidar BatsovのRubyスタイルガイド|https://rubystyle.guide/|
|Rails|Railsガイド|https://railsguides.jp/|
|RSPEC|Better Specs|https://www.betterspecs.org/|
|JavaScript|Airbnb JavaScriptスタイルガイド|https://github.com/airbnb/javascript|
|JavaScript|Standard JS|https://standardjs.com/|
|TypeScript|TypeScript Deep Dive|https://basarat.gitbook.io/typescript|
|TypeScript|Google TypeScript Style Guide|https://google.github.io/styleguide/tsguide.html|
|React|bulletproof-react|https://github.com/alan2207/bulletproof-react|
|Python|PEP8|https://peps.python.org/pep-0008/|
|SQL|Simon HolywellのSQL Style Guide|https://www.sqlstyle.guide/|
|SQL|SQLアンチパターン|https://www.oreilly.co.jp/books/9784873115894/|
|AWS|AWS Well-Architected Framework|https://aws.amazon.com/jp/architecture/well-architected/?wa-lens-whitepapers.sort-by=item.additionalFields.sortDate&wa-lens-whitepapers.sort-order=desc&wa-guidance-whitepapers.sort-by=item.additionalFields.sortDate&wa-guidance-whitepapers.sort-order=desc|
|AWS|AWS Prescriptive Guidance|https://aws.amazon.com/jp/prescriptive-guidance/?apg-all-cards.sort-by=item.additionalFields.sortDate&apg-all-cards.sort-order=desc&awsf.apg-new-filter=*all&awsf.apg-content-type-filter=*all&awsf.apg-code-filter=*all&awsf.apg-category-filter=*all&awsf.apg-rtype-filter=*all&awsf.apg-isv-filter=*all&awsf.apg-product-filter=*all&awsf.apg-env-filter=*all|
|GCP|Google Cloud Security Foundations Guide|https://cloud.google.com/architecture/security-foundations?hl=ja|
|Azure|Microsoft Cloud Adoption Framework for Azure|https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/|
|Docker|Building best practices|https://docs.docker.com/build/building/best-practices/|
|プロンプトエンジニアリング|DAIR.AIのPrompt Engineering Guide|https://www.promptingguide.ai/|
|リファクタリング|ThoughtWorks社のRefactoring Catalog|https://martinfowler.com/books/refactoring.html|
|テスト|Vladimir KhorikovのUnit Testing(邦訳:[単体テストの考え方/使い方](https://amzn.asia/d/fVt3XB3))|https://www.oreilly.com/library/view/unit-testing-principles/9781617296277/|
|全般|公式ドキュメント|存在するのであれば文言だけでも入力すべき|
|全般|Googleスタイルガイド|いろいろあります|

## 具体例

次のコードのリファクタリングをChatGPT(GPT-4o)に指示

```ruby

def fizzbuzz
  i = 1
  while i <= 100
    if i % 3 == 0 && i % 5 == 0
      puts "FizzBuzz"
    elsif i % 3 == 0
      puts "Fizz"
    elsif i % 5 == 0
      puts "Buzz"
    else
      puts i
    end
    i = i + 1
  end
end

```

### 指定なし

![スクリーンショット 2024-12-04 1.32.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638565/1baea0b9-d382-95fe-700c-a934a47c766f.png)

![スクリーンショット 2024-12-04 1.32.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638565/ae88ac88-1805-3f7d-1e2a-fafcdc787d16.png)

### スタイルガイドとリファクタリングカタログを指定

![スクリーンショット 2024-12-04 1.32.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638565/799748b3-cbd4-c507-84c5-72986ed94cc3.png)

![スクリーンショット 2024-12-04 1.32.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638565/cd6f9277-3aa6-5239-c944-3152c688f5a1.png)

![スクリーンショット 2024-12-04 1.33.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638565/7723e2f3-d0b3-43dc-9481-1311d1a6376d.png)

リファクタリングの指摘は妥当です
Rubyスタイルガイドの`Favor each over while`は私が見たところ存在しませんでした。（リンクはクリック不可） 

## 反省

新規作成する際にスタイルガイドを指定することは効果的となる可能性がありますが、
人間が作成したコードの修正ではコーディング規約の設定やCIによる自動化を優先した方が良さそうです。

また、本書内でコーディングにおいてはプロンプトは流動的との記述もありました。

> 開発現場では、創造性を要する一度きりのタスクが多いのが特徴です。（中略）タスクの多様性と一回性を考えると、完璧なプロンプトを作る必要はありません。むしろ、即興で使い捨てのプロンプトを生み出し、AIとの対話を通じて出力を調整する能力が重視されます。（P.14 「1.3.3　エンジニアリングタスクの多くは一点もの」）

全てのケースで賄えるようにするのではなく、
場面に応じて最適なプロンプトを入力し、
高速なトライ&エラーを続けていきたいと思います

## Espanso

スタイルガイドやベストプラクティスを毎回入力することが手間になるため、
補助ツールを探していたところ、Espansoというツールを見つけました。

https://espanso.org/

https://techracho.bpsinc.jp/hachi8833/2023_12_07/137108

動作が高速で使いやすく、かつyamlファイルでメンテナンスが簡単にできるため、
今回のケース以外でも使用したいと思います。