【書籍】コード×AIーソフトウェア開発者のための生成AI実践入門 学んだことをアウトプット

# 目的
本記事は、僕が「コード×AIーソフトウェア開発者のための生成AI実践入門」を読んで学んだことをアウトプットすることを目的としています。

https://amzn.asia/d/gyxtoge


# AIに対する基本理解

## プロンプトエンジニアリングのテクニックはあまり重要ではない
エンジニアの日常作業において、プロンプトテクニックは一般的に期待されているほど大きな効果は無い。
理由は、**エンジニアのタスクのほとんどは創造性を要する一度きりのものが多い。**

完璧なプロンプトを書こうとして、プロンプト作業に時間を費やすのは効率的とは言えない。
むしろ**即興で使い捨てのプロンプトをベースにAIとの対話を繰り返して出力を調整する**ほうが、早く望んだ出力結果を得られる可能性が高い。

一発で完璧な回答をAIに求めないこと。試行錯誤することが大事。

#### プロンプト改善のフィードバックプロセス
```mermaid
flowchart TD
    A[初期プロンプト] --> B[AIの出力]
    B --> C[人間が評価]
    C --> D[プロンプトの調整・改善]
    D --> B
```


## エンジニアの仕事は消えない
AIがどれほど進化しても、誤った情報を出力するリスクは必ず残る。
大事なのは、**ウソはウソであると見抜けるエンジニアになること**
**AIが生成したものを正しくレビューし、使用の可否を判断することが必要不可欠になる。**

つまり、エンジニアはこれからも基本的なプログラミング・設計スキルを磨き続ける必要がある。


# 汎用的なプロンプトスキル
## プロンプトでの条件指定は、箇条書きを指定する
箇条書きで指定することで、条件が具体的になり人間がプロンプトを修正するのが楽になる。

```txt:箇条書きで条件を指定するプロンプト例
以下の条件に基づいてコードを生成してください：
- プログラミング言語：Java  
- タスク：特定のファイルを読み込み、内容を加工して新しいファイルに保存するプログラムを作成  
- 入力形式：テキストファイル（例：UTF-8形式）  
- 出力形式：加工後のテキストファイル（例：各行を逆順に並べる）  
- 必要な要件：
  - ファイル操作に例外処理を含める
  - メソッドを使用して処理を分割する
  - コードはコメント付きで記述  
- 結果：使いやすくメンテナンス可能なコード
```

```txt:文章で条件を指定するプロンプト例
Javaを使用して、特定のテキストファイルを読み込み、その内容を加工した後、
新しいファイルとして保存するプログラムを作成してください。
加工処理としては、各行の文字を逆順に並べる操作を行います。
さらに、ファイル操作を行う際には適切な例外処理を加えてください。
プログラムは、メソッドを使用して処理を分割し、コードの可読性とメンテナンス性を向上させてください。
また、必要に応じてコメントを追加し、コードの意図を明確に示してください。
```

## プロンプトへの制約・禁止事項の指示は段階的に
最初のプロンプトで大量の制約・禁止事項を指定すると、**AIの創造性が制限される可能性がある**
そのため、最初のプロンプトでは制約・禁止事項は少なめに指定する。
AIの出力結果を見て、少しずつ条件を追加していくことがおすすめ。

## 約束を破るAIへの対策強化
AIに指示をしても、必ずそれが聞き入れられるとは限らない。
特に、大量の指示を渡したときなどは、AIが指示を無視することがある。
その場合は、**制約の強調や、言い回しの変更などでAIが制約を守るように促すのが効果的。**

### より具体的な制約を追加する
条件をより具体化する
```txt:プロンプト例
コンテンツが少ない場合でもフッタは浮かせず、ページの最下部に接するように配置してください
```

### 文字フォーマットで強調
マークダウンの太字表記等を活用する
```txt:プロンプト例
フッターは**浮かせず**、ページの最下部に固定してください。
```

### 文章の強調
形容詞や形容動詞などを使い文章の意図を明確にする
```txt:プロンプト例
フッターは**絶対に**浮かせず、ページの最下部に**間違いなく**固定してください
```

### 制約を繰り返す
同じことを二回言う
```txt:プロンプト例
フッターは浮かせず、ページの最下部に固定してください。**ページの最下部に固定してください！**
```

### 別の言い方で同じ制約を追加する
同じことを、違う言い回しで表現する
```txt:プロンプト例
フッターは浮かせず、ページの最下部に固定してください。
**つまり、フッターの下に空白スペースが現れないようにし、確実に最下部に設置するようにします。**
```

## 途中の推論ステップを明示的にAIに表現させる
プロンプトの中に、**ステップバイステップで考えて**と付け加えるだけでいい。

### ステップ・バイ・ステップ指定なしのAIの出力
:::note info
使用している言語モデルは、GPT-4o です
:::
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635936/120fb789-6102-4e74-d619-f41b8156f1a3.png)

### ステップ・バイ・ステップ指定ありのAIの出力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635936/e3903586-2dd7-0869-5338-9bf2e8e6891a.png)

# AIを用いたコーディングの考え方
## AIから提示された実装方法は常に疑う
大前提として、**AIが提示する情報は常に疑う姿勢を持つこと。**
AIは、数多くの実装方法の中から１つを選択して提案しているだけに過ぎない。
この考え方を前提として、AIを利用する。

## 質の良いコードを渡せば、AIのアウトプットするコードも良くなる
AIは模倣することが得意。
つまり質の良いコードを渡せば、AIもそれに倣う。
一方で質の悪いコードを書けば、AIもそれに真似てしまう可能性がある。
**AIが提案するコードの品質を向上させたければ、自分のコードの品質を高めることが必要不可欠**

## 一度に少量のコードをレビューする
人間の脳が一度に処理できる情報量には限りがある。
**一度にレビューする量が400行を超えると、欠陥を見つける能力が低下してしまう**

AIに大量のコードを渡しても、帰ってきたコードが大量だと
人間のレビュー時間も長くなり、チェックが追いつかなくなってしまう。
AIのコード出力を数行～数十行に収めることが大切です。

# AIを用いたコードの品質向上
## 体系的なリファクタリングの手法を適用させる方法
AIに対して、オープンクエスチョンで「どこをリファクタリングすればよいか？」聞いても
「コードの重複をなくす」、「コードの複雑さを減らす」等の一般的な回答しか得られない可能性がある。

その場合は、よく知られている「カタログ」や「リスト」を指定する。
本書では、Thoughtworks社 リファクタリングカタログ が例として紹介されている。

https://qiita.com/sho-naka/items/fd37c0cef35235b39b56

```txt:プロンプト例
以下のコードに対して、Thoughtworks社の**Refactoring Catalog**に基づいたリファクタリングを行います。
指摘とその解説を10個以上生成してください。
～以下略～
```

これらのカタログ、リストは複数存在する。
例
- Thoughtworks社 リファクタリングカタログ
- Smells to Refactorings Quick Reference Guide
- Refactoring to Patterns
- GoFのデザインパターン
- リーダブルコード（書籍）

これらのリストを参考にしながら、**何を改善したいのかを明確にする**ことが大切。

## BUDフレームワークを用いたコード最適化
BUDフレームワークとは、以下3つの観点からコードの問題を洗い出すためのフレームワーク
- Bottlenecks（ボトルネック）：パフォーマンス低下の問題を引き起こす箇所
- Unnecessary（不必要な処理）：冗長で省略可能な部分
- Duplicated（重複する処理）：同じ処理が複数回行われている箇所

```txt:プロンプト例
以下のコードに対して、BUDの観点から問題点を特定して下さい。
また、それぞれの問題点に対する具体的な改善案を提案してください。
```

## SOLDの観点を用いたコード最適化
SOLID原則はプログラミングやソフトウェア設計における5つの重要な原則の集合で、
コードを柔軟で保守しやすく、拡張可能なものにするための指針です。それぞれの頭文字を取って「SOLD」と呼ばれる。

### 1. Single Responsibility Principle（単一責任の原則）
- **定義**: クラスやモジュールは「1つのこと」だけを責任として持つべき
- **目的**: コードを変更する理由が1つだけになるように設計する
- **例**: ユーザー管理クラスはユーザーの情報を操作するだけに限定し、ログイン処理は別クラスに分ける

---

### 2. Open/Closed Principle（開放閉鎖の原則）
- **定義**: ソフトウェアは拡張に対して開かれ、変更に対して閉じられるべき
- **目的**: 既存のコードを修正することなく、新機能を追加可能にする
- **例**: 新しい機能を追加する際、既存のコードを直接変更せず、インターフェースを通じて追加する

---

### 3. Liskov Substitution Principle（リスコフの置換原則）
- **定義**: 派生クラスは、基底クラスとして置き換え可能でなければならない
- **目的**: サブクラスが基底クラスを完全に置き換えられるように設計する
- **例**: 動物クラスを基底クラスとした場合、犬クラスや猫クラスは動物としての振る舞いを保証する

---

### 4. Interface Segregation Principle（インターフェース分離の原則）
- **定義**: クライアント（利用側）が使用しないメソッドに依存しないように設計する
- **目的**: 大規模なインターフェースを分割し、特定の用途に特化させる
- **例**: 大きなインターフェースを分割し、特定の役割ごとに小さなインターフェースを作る

---

### 5. Dependency Inversion Principle（依存性逆転の原則）
- **定義**: 高レベルモジュールは低レベルモジュールに依存すべきではなく、抽象に依存すべき
- **目的**: 具体的な実装に依存せず、抽象に依存する設計を行うことで柔軟性を高める
- **例**: コンポーネント間の依存を減らすために依存性注入（DI）を使用


AIに対してSOLID原則に基づいた出力を指定することで、コードの品質向上に貢献できる
```txt:プロンプト例
SOLID原則の観点から、このプログラムにはどのような問題点がありますか？
どのように設計を変更すれば、このプログラムの拡張性を向上させることができますか？
```

# さいごに
本記事では、「コード×AIーソフトウェア開発者のための生成AI実践入門」で学んだことの一部だけを書き出してみました。
AIに関する書籍はたくさんありますが、プロンプトテクニックに焦点を当てたものが多い印象があります。
そんな中でも本書は、冒頭で**プロンプトテクニックは、重要ではない**と言い切っていたのが好印象でした。
プロンプトのような小手先のテクニックだけではなく、エンジニアがAIを活用するためのテクニックが体系的に書かれていると感じました。

本書では、最後の章でAIを組織的に活用することが大切 と語られていました。
正直、ここについてはまだ自分の中で疑問が残っています。
具体的には、[インナーソース](https://ja.wikipedia.org/wiki/%E3%82%A4%E3%83%B3%E3%83%8A%E3%83%BC%E3%82%BD%E3%83%BC%E3%82%B9)の考え方を組織に取り入れるべき。 と言われています。

つまり、組織内でソースコードを共有して知的財産としましょう ということです。

たしかに素晴らしい考え方ですが、実情として実現可能かどうかが少し疑問に残りました。
僕は客先へ派遣として勤務しているのですが、派遣の都合上、良くも悪くも**客先の開発環境に依存します**
そのため、配属ガチャ要素が含まれる印象を受けました。

とはいえ、今のAIの使い方は、日常業務の一部で扱う**道具**の枠に収まっており、非常にもったいないと考えているのも事実です。

もっとAIを中心に据えた開発体系になっていけば、きっと開発がもっと楽しくなっていくと信じています。

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