初学者に向けたトレーニング作成：自作からGPT活用まで

# はじめに
この記事はモチベーションクラウドシリーズアドベントカレンダー2023の記事になります。

https://qiita.com/advent-calendar/2023/lmi


# 初学者に向けたトレーニングをたくさんつくりたい
リンクアンドモチベーションでエンジニアをしておりますl_keiです。
最近、新卒メンバーがPJTに参画しました。そのオンボーディングの一環として、書籍や研修、ペアプロのカリキュラムを実施していました。しかし、実業務に着手する前に、実際に手を動かす経験を積み重ねて欲しく、**既存のカリキュラムに加えて「多くの問題を解く」という体験を用意することにしました。**

この目的のために、各領域で練習問題を用意できるよう取り組みました。

# 1. 自分で作る（SQLノック）
まず、自分たちで問題を作成しました。基本的なSQLからスタートし、徐々に複雑なクエリの作成にチャレンジする内容で、合計20つのSQL練習問題を自作しました。

**このアプローチにより、新卒メンバーはSQLの書き方を学びながら、実際のデータベース構造にも慣れることができました。**

練習環境としては、開発環境にRedashとデータベースを設置し、実際の開発データを使用して問題を解いてもらいました。

## 問題例
以下は、作成した問題の一例です。
| 項番 | 問題文(抽出するデータ) | 使用テーブル、ヒント | 回答 |
|--:|:--|:--|:--|
| 例 | 企業一覧<br>登録企業のID, 企業名, ユーザー数 | ○○テーブル | {https:// 回答RedashのURL} |

問題を作成するのには多少時間がかかりますが、自作成することで、技術的な側面だけでなく、自社アプリの設計に関する理解も深めるような問題を作成することができました。

# 2. GPTを利用して作成する（Linuxコマンドノック）
新卒メンバーがCLI操作に対する苦手意識を克服できるよう、Linuxコマンドの学習を取り入れることにしました。特に、各コマンドに関する問題を豊富に用意するため、GPTの活用を決めました。

問題作成をするに当たり、
技術評論社から出版されている**書籍「ゼロからわかる Linuxコマンド200本ノック（技術評論社）」の著者ひらまつ しょうたろうさんがGPTによる問題作成を紹介していらっしゃったので、参考にさせていただきました。**
https://hiramatsuu.com/archives/1278

ブログでご紹介頂いているプロンプトをベースに、以下のような改善を加えてプロンプトと問題を作成しました。

:::note info
修正内容
* 問題と回答に加えて、ヒントや解説を用意。
* さらに、問題を解くための環境準備方法についても説明を加えました。
:::

以下に、実際に使用したプロンプトと、それによって生成された問題の例を共有します。

## 使用プロンプト

```
# 命令概要
Linuxコマンドの演習問題を30問作成してください。ただし以下の条件すべてを満たすものとします。

・すべての問題の解答は、Bashに入力して実際に動作する
・すべての解答は具体的な１行のコマンドラインになるものとする
・問題文には具体的なファイル名やディレクトリ名を含める
・問題文には具体的なコマンドの名前は含めない
・1 ~ 10の10段階の難易度（数字が大きいほど難しい）があるとして、難易度1~3の問題だけを作成する
・出題の範囲は、実務で誰もが使う最頻出のコマンドだけ
・問題文だけを作成する

# 出力
・出力はテーブルの状態で返却してください
・出力行のフォーマットは「問題番号 | 問題文 | ヒント | 解答 | 解説」
・問題は30問用意してください
・対象者は開発の初学者です
　　・"ヒント"では問題を解く上でのヒントを記載してください
　　・"解説"では、解答内容の解説やポイント、使用する上での注意などを記載してください
・今回の問題を解く上でのファイルやディレクトリの準備が必要だったら、別途具体的にわかりやすく記載して用意させてください。
　　・既存のファイルに影響しないような、今回用のファイル名、ディレクトリ名にしてください
　　・作業は、今回用意したディレクトリ内で実施させてください。
・cdコマンドに関する問題から始めてってください

では始めてください。
```

## 実際
### 事前準備について

<details>
<summary><font color="Red">作成した事前準備(押下で開く)</font></summary><div>

まず、この問題を解くために必要な準備を行います。以下の手順に従って、必要なファイルやディレクトリを作成してください。
```bash
cd
mkdir practice_linux_commands
cd practice_linux_commands
echo "Hello, World!" > hello.txt
mkdir dir1
mkdir dir2
echo "apple" > dir1/fruits.txt
echo "banana" > dir2/fruits.txt
```
上記の手順により、```practice_linux_commands``` ディレクトリを作成し、その中に ```hello.txt``` ファイル、```dir1``` と ```dir2``` というディレクトリ、そしてそれぞれのディレクトリ内に ```fruits.txt``` というファイルを作成します。
</div>
</details>




### 問題
<details>
<summary><font color="Red">作成した問題(押下で開く)</font></summary><div>

* 事前準備で用意したファイルのみを操作するよう、十分に気をつけてコマンド実行しましょう。
* 新卒のメンバーは取り組む前に、環境や注意点について先輩にアドバイスを求めてください。
* 焦ることなく、しっかりと理解を深めることを優先してください。
    * 答えを参照しつつ、必要であれば周りに相談することも推奨します。

| 問題番号 | 問題文 | ヒント | 解答 | 解説 |
|--:|:--|:--|:--|:--|
| 1 | `practice_linux_commands` に移動してください。 | 移動するコマンドを使ってみましょう。 | `cd practice_linux_commands` | cd コマンドはディレクトリ間を移動するためのコマンドです。 |
| 2 | 現在のディレクトリの中身を表示してください。 | ディレクトリの中身を確認するコマンドを使ってみましょう。 | `ls` | ls コマンドはディレクトリの内容を表示するコマンドです。 |
| 3 | `hello.txt` の中身を表示してください。 | ファイルの中身を確認するコマンドを使ってみましょう。 | `cat hello.txt` | cat コマンドはファイルの内容を表示するコマンドです。 |
| 4 | `dir1` に移動してください。 | cd コマンドを再度使用してみましょう。 | `cd dir1` | - |
| 5 | 現在のディレクトリを確認してください。 | どのディレクトリにいるかを確認するコマンドを使ってみましょう。 | `pwd` | pwd コマンドは現在のディレクトリのフルパスを表示するコマンドです。 |
| 6 | 一つ上のディレクトリに移動してください。 | 一つ上のディレクトリに移動する方法を思い出してみましょう。 | `cd ..` | .. は一つ上のディレクトリを指します。 |
| 7 | `dir1` と `dir2` の中身を一度に表示してください。 | ワイルドカードを使ってみましょう。 | `ls dir*` | ワイルドカード * は任意の文字列にマッチします。 |
| 8 | `dir1` の `fruits.txt` と `dir2` の `fruits.txt` の中身を一度に表示してください。 | ワイルドカードと前の問題の答えを組み合わせてみましょう。 | `cat dir*/fruits.txt` | - |
| 9 | `practice_linux_commands` ディレクトリ内の全てのテキストファイルから "Hello" という文字列を含む行を検索してください。 | grep コマンドを使い、再帰的に検索するオプションを利用してみましょう。 | `grep -r "Hello" *` | grep -r は再帰的にディレクトリ内のファイルを検索します。 |
| 10 | `dir1` と `dir2` の両ディレクトリ内の fruits.txt から "apple" という文字列を含む行を検索してください。 | 複数のディレクトリやファイルを指定して grep を実行することができます。 | `grep "apple" dir1/fruits.txt dir2/fruits.txt` | 指定したファイル内から "apple" という文字列を検索します。 |
| 11 | `practice_linux_commands` ディレクトリ内の hello.txt という名前のファイルを探してください。 | find コマンドを使用し、ファイル名のオプションを利用して検索してみましょう。 | `find . -name "hello.txt"` | find コマンドは、指定した条件に一致するファイルやディレクトリを検索します。 |
| 12 | `practice_linux_commands` ディレクトリ内の fruits.txt という名前のファイルを全て探してください。 | find コマンドを使用し、再帰的にディレクトリ内を検索するオプションを利用してみましょう。 | `find . -name "fruits.txt"` | find コマンドは指定したディレクトリ内から、指定した名前のファイルやディレクトリを検索します。 |
| 13 | `hello.txt` を `greeting.txt` に名前変更してください。 | ファイルやディレクトリの名前を変更するコマンドを使用してみましょう。 | `mv hello.txt greeting.txt` | mv コマンドはファイルやディレクトリの名前を変更、または移動するためのコマンドです。 |
| 14 | `dir1` と `dir2` を `folders` というディレクトリに移動してください。 | 新しいディレクトリを作成し、それを使用して移動させる方法を考えてみましょう。 | `mkdir folders && mv dir1 dir2 folders/` | mkdir コマンドでディレクトリを作成し、mv コマンドで移動します。 && は前のコマンドが成功した場合に次のコマンドを実行します。 |
| 15 | `greeting.txt` を削除してください。<br/><br/>**※ 削除は危険なコマンドです。答えを見ながら注意して実行してください** |  ファイルやディレクトリを削除するコマンドを使ってみましょう。 |  `rm greeting.txt` |  rm コマンドはファイルを削除するコマンドです。注意して使用してください。 |
| 16 |  `folders` ディレクトリを削除してください。<br/><br/>**※ 削除は危険なコマンドです。答えを見ながら注意して実行してください** |  ディレクトリを削除する際には、中身も考慮する必要があります。 | `rm -r folders` |  rm -r はディレクトリを再帰的に削除するオプションです。 |
| 17 | 現在のディレクトリに空の `empty.txt` ファイルを作成してください。 | タッチするコマンドを使ってみましょう。 | `touch empty.txt` | touch コマンドは新しい空のファイルを作成するコマンドです。 |
| 18 | 現在のディレクトリのファイルやディレクトリの詳細情報を表示してください。 | 詳細を表示するオプションを使ってみましょう。 | `ls -l` | ls -l は詳細表示オプションです。 |
| 19 | `empty.txt` のファイルサイズを表示してください。 | ファイルのプロパティを確認するコマンドを使ってみましょう。 | `du -h empty.txt` | du コマンドはファイルやディレクトリのサイズを表示するコマンドです。-h オプションで読みやすいフォーマットで表示します。 |
| 20 | 現在の日付と時刻を表示してください。 | 日付を表示するコマンドを使ってみましょう。 | `date` | date コマンドは現在の日付と時刻を表示するコマンドです。 |
| 21 | 現在のディレクトリの使用容量を表示してください。 | ディレクトリのサイズを確認するコマンドを使用してみましょう。 | `du -sh .` | . は現在のディレクトリを指します。 |
| 22 | 現在のディレクトリをzipファイルとして圧縮してください。 | 圧縮のためのコマンドと、現在のディレクトリを指す記号を使ってみましょう。 | `zip -r practice.zip .` | zip コマンドはファイルやディレクトリをzipフォーマットで圧縮するコマンドです。-r オプションはディレクトリを再帰的に圧縮するためのものです。 |
| 23 | `practice.zip` を解凍してください。 | zipファイルを解凍するコマンドを使ってみましょう。 | `unzip practice.zip` | unzip コマンドはzipファイルを解凍するコマンドです。 |
| 24 | `empty.txt` に "This is not empty." というテキストを追加してください。 | ファイルにテキストを追加するコマンドを使用してみましょう。 | `echo "This is not empty." > empty.txt` | echo コマンドはテキストを出力するコマンドです。> はリダイレクトを意味し、ファイルにテキストを書き込む際に使用します。 |
| 25 | 現在のディレクトリに `docs` というディレクトリを作成してください。 | ディレクトリを作成するコマンドを使ってみましょう。 | `mkdir docs` | - |
| 26 | `empty.txt` を `docs` ディレクトリにコピーしてください。 | ファイルをコピーするコマンドを使用してみましょう。 | `cp empty.txt docs/` | cp コマンドはファイルやディレクトリをコピーするコマンドです。 |
| 27 | `docs` ディレクトリに移動せず、`docs` 内の `empty.txt` の中身を表示してください。 | パスを指定してファイルの中身を確認する方法を思い出してみましょう。 | `cat docs/empty.txt` | - |
| 28 | 現在のディレクトリに `backup` というディレクトリを作成し、`docs` ディレクトリをその中にコピーしてください。 | ディレクトリをコピーする際のオプションを使用してみましょう。 | `mkdir backup && cp -r docs backup/` | cp -r はディレクトリを再帰的にコピーするオプションです。 |
| 29 | `backup` ディレクトリ内の `docs` ディレクトリ名を `documents` に変更してください。 | ディレクトリの名前を変更する方法を思い出してみましょう。 | `mv backup/docs backup/documents` | - |
| 30 | 現在のディレクトリにある全ての txt ファイルを表示してください。 | ワイルドカードを使用して、特定の拡張子を持つファイルを探す方法を思い出してみましょう。 | `ls *.txt` | - |
| 31 | `empty.txt` のファイル権限を読み書きのみに変更してください。<br/>※ アクセス権の操作は慎重に行いましょう。答えを見ながら注意して実行してください  | ファイルの権限を変更するコマンドと、読み書きの権限を指す数字を使ってみましょう。  | `chmod 600 empty.txt` | chmod コマンドはファイルやディレクトリの権限を変更するコマンドです。600は所有者のみ読み書き可能、他のユーザはすべてのアクセスを禁止する権限を表します。 |
| 32 | 現在のディレクトリのファイルとディレクトリの数を数えてください。 | ワイルドカードとパイプ、そして数を数えるコマンドを使用してみましょう。 | `ls \| wc -l` | ls でディレクトリの一覧を表示します。\| はパイプと呼ばれ、左側のコマンド の出力を右側のコマンドへと入力として渡します。<br/>wc コマンドはテキストの行数、単語数、バイト数を数えるコマンドで、-l オプションを使うことで行数のみを表示します。 |
| 33 | `empty.txt` に "This is a second line." というテキストを追加せずに上書きしてください。 | リダイレクトの方法を思い出してみましょう。 | `echo "This is a second line." > empty.txt` | > はリダイレクトを意味し、ファイルにテキストを上書きする際に使用します。 |
| 34 | `empty.txt` から "This is a second line." というテキストを削除してください。 | 一時ファイルを使用して、特定の行を除外する方法を使ってみましょう。 | `grep -v "This is a second line." empty.txt > temp.txt && mv temp.txt empty.txt` | grep -v は指定したパターンと一致しない行を出力するオプションです。 |
| 35 | 現在のシェルセッションを終了します。 | シェルセッションを終了するコマンドを探してください。 | `exit` | `exit` コマンドは現在のシェルセッションを終了します。 |

</div>
</details>

# まとめ
書籍や研修、ペアプロと並行して、"問題を解く"というカリキュラムを用意しようと模索し、自作とGPT作成それぞれで問題を作成して展開することができました。

**自作したカリキュラムでは、新たに参加するプロジェクトのアプリケーション設計を理解できるよう、 特定のドメインに特化した内容を組み込むことができました。**

**また、GPTを用いた問題作成では、従来よりも効率的に質の高い問題を作成することができました**。

実際の業務や機能開発においても、GPTの活用は効率と品質の向上に大きく貢献しています。今後も **「これはGPTで解決できないだろうか？」** という視点を持ち続け、その可能性を探求していこうと思います。