Claude Codeで新しい言語を学習する — テストで答え合わせし、ヒントだけ出させる
GoやRustの演習をClaude Codeで進めるとき、テストは書き換え禁止、答えは書かせず次の一歩のヒントだけ出させる構成を、CLAUDE.md・permissions・output styleで組みます。
Claude Codeに「この演習を解いて」と頼めば、数十秒でテストが全部通ります。仕事ならそれで正解ですが、GoやRustを身につけたい場面では、答えが先に出た時点で練習が終わってしまいます。
この記事の構成は3つの部品でできています。習得済みの言語との対応表をCLAUDE.mdに置く。演習のテストファイルをpermissions.denyで書き換え禁止にする。Claudeの話し方を「答えは書かず、次の一歩のヒントだけ」に変える。テストが通ったかどうかが答え合わせになるので、Claudeの採点は要りません。
3つの部品を、それぞれ別の機能に任せる
答えを書かせない仕組みを、プロンプト1本に詰め込むと崩れます。担当が違う3つの機能に分けると、どれか1つが外れても残りが支えます。
学習用の構成を支える3つの機能
CLAUDE.md: 前提知識
自分が何を知っていて、何を知らないかを渡します。習得済みの言語との対応表と、「答えを書かない」という方針を置く場所です。
output style: 話し方
Claudeの口調と応答の形式を、セッション全体で変えます。ヒントを1つずつ出す、という振る舞いはここに書きます。
permissions: 書き換えの禁止
テストファイルへの編集を、Claude Codeの側で止めます。Claudeが指示に従うかどうかに依存しません。
出力スタイルは、Claudeに従わせる指示です。「必ず起きる」「決して起きない」を保証するものではない、と説明されています。保証が要るのは権限の側で、ここにEditの拒否ルールを置きます。逆に、口調や段階的なヒントの出し方は拒否ルールでは表せないので、スタイルに任せます。
手順1: テスト付きの演習を手元に置く
答え合わせをテストに任せるので、教材にテストが付いている必要があります。Exercismはその条件を満たします。CLIで演習を取得すると、次のファイルが手元に落ちます。
- README.md: 何を作るかの説明
- HELP.md: テストの走らせ方と、詰まったときの案内
- HINTS.md: ヒント(演習によっては無い)
- テストファイル: 解答の正しさを確かめる
- スタブファイル: 実装の出発点
exercism download --exercise=hello-world --track=go
cd go/hello-world演習名とトラック名はExercismの各演習ページに載っているコマンドをそのまま使えます。テストの付属しない教材は、答え合わせの軸が無いので、この構成の対象外です。
Go用の案内には、少し意外な助言があります。テストのプログラムを先に開いて目を通す。「ずるに見えても読む」と書かれています。テスト関数の名前、テストデータ、コメントが、関数の形を教えてくれるからです。つまり禁止するのは編集であって、閲覧ではありません。拒否ルールはEditだけにして、Readは塞ぎません。
手順2: CLAUDE.mdに対応表と方針を置く
演習フォルダのCLAUDE.mdには、習得済みの言語を基準にした対応表を書きます。学習者の側の知識を渡すので、Claudeのヒントが「Goではこう」と一般論で返らず、自分の言語に引きつけて返ります。
次はTypeScriptを習得済みとして、Goを学ぶ場合の書き方の一例です。
# このフォルダの目的
TypeScriptは仕事で書ける。Goを練習している。演習はExercismで、
テストが通れば合格。
## TypeScriptとの対応(自分が引っかかった順に増やす)
| TypeScript | Go |
|---|---|
| try / catch | 戻り値のerrorを `if err != nil` で受ける |
| interface は明示的に implements | 必要なメソッドを持てば満たす |
| Array.map / filter | for ループで書くのが基本 |
## 方針
- 解答のコードは書かない。ヒントは1回に1つ
- テストファイルは編集しない(権限でも禁止している)
- 失敗しているテスト名と出力を先に読む対応表はCLAUDE.mdの役割そのものです。CLAUDE.mdはプロジェクトについてClaudeが知っておくべきことを置く場所で、出力スタイルに切り替えても読み込まれたままです。長さは1ファイルあたり200行未満が目安とされているので、表は引っかかった項目だけを足していく運用が向きます。
手順3: テストと、必要なら解答ファイルを編集禁止にする
演習フォルダの.claude/settings.jsonに拒否ルールを書きます。
{
"permissions": {
"deny": [
"Edit(**/*_test.go)"
]
}
}**/で始めると、どの階層のテストファイルにも一致します。ファイルへの書き込みはEditのルールで扱われるので、Write用の別ルールは要りません。Write(...)のパスルールは、書いても一致しないと説明されています。
Rustの演習なら、テストが置かれたパスをlsで確かめて同じ形で書きます。
{
"permissions": {
"deny": [
"Edit(**/tests/**)"
]
}
}解答ファイルまで塞ぐと、答えを書く経路が物理的になくなる
テストの保護は、答えを「ずるして通す」ことを防ぐ守りです。答えそのものを書かせない守りは、解答ファイルの拒否で作れます。
{
"permissions": {
"deny": [
"Edit(**/*_test.go)",
"Edit(/hello_world.go)"
]
}
}先頭が/のパスは、プロジェクト設定(.claude/settings.json)ならプロジェクトのルートが基準です。hello_world.goは例で、実際の名前は演習のスタブファイルに合わせます。この設定ならClaudeはヒントを言葉で返すだけで、解答ファイルを開いてコードを書き込めません。実装は自分のエディターで打ちます。厳しい設定ですが、「ついコードを書いてしまう」というスタイル側の揺れを、権限が上から押さえます。
使い分けは次のとおりです。
| 構成 | 守れるもの | 向く段階 |
|---|---|---|
| テストの拒否だけ | 守れるものテストを書き換えて合格させる抜け道 | 向く段階詰まったら少し見てもよい、ゆるい練習 |
| テスト + 解答ファイルの拒否 | 守れるもの答えのコードが書き込まれること自体 | 向く段階自力で書くことを練習の目的にする段階 |
手順4: 「ヒントだけ」の出力スタイルを作る
組み込みのLearningスタイルは、ほぼ実装を進めたうえで、設計判断のある数行をTODO(human)として自分に任せる作りです。仕組みの詳細はlearning output styleプラグインの解説にあります。演習では、課題全体が自分の担当なので、「答えは書かない、次の一歩だけ示す」というスタイルを自作するほうが目的に合います。
出力スタイルはMarkdownファイル1枚です。プロジェクト用は.claude/output-styles/に置きます。
---
name: Hint only
description: 答えのコードを書かず、次の一歩のヒントだけ返す
keep-coding-instructions: true
---
あなたは新しい言語を練習している人のコーチです。
- 解答に当たるコードは書かない。関数の本体、条件式、完成形の断片も出さない
- 返すのは、次に試す一歩のヒント1つだけ。複数案を並べない
- ヒントの強さは段階にする。聞き直されたら1段階だけ具体的にする
1. 失敗しているテストのどこを読むか
2. 関係する言語の概念名(例: 戻り値のerror、borrow)
3. 習得済みの言語との対応(CLAUDE.mdの表を使う)
- 書いたコードを見せられたら、動くかどうかではなく、次に直す1点だけを指摘するkeep-coding-instructions: trueは、Claude Codeが持つソフトウェア開発の指示を残したままスタイルを足すための設定です。省くと、その指示が外れます。コードを読んでテストを回す動きは残したいので、ここはtrueにします。
切り替えは/output-styleコマンドです。名前は大文字小文字を区別せずに指定できます。
/output-style Hint onlyターミナルでは、起動中にスタイルのファイルを作成・編集したときはClaude Codeの再起動が必要です。選んだスタイルは.claude/settings.local.jsonに保存されます。outputStyleを設定ファイルに直接書くなら、値は大文字小文字を区別するので、nameと同じ綴りにします。
サブエージェントはスタイルの影響を受けません。調査をサブエージェントに任せると、ヒント専用の口調が外れた答えが返ってくることがあるので、練習中は委譲を使わないと口調が揃います。
手順5: 失敗を自分で読み、詰まったらヒントを1段ずつもらう
準備ができたら、テストを回して、失敗の出力を自分で読むところから始めます。Go用の案内にも、何も書く前にgo testを走らせて、エラーメッセージから出発点を探すよう書かれています。
1つの失敗テストを通すまでの流れ
- 1
自分でテストを走らせる
go testを実行し、出力の失敗メッセージを読みます。スタブのままだとコンパイルエラーで全体が止まるので、次の手順でまず型を合わせます。 - 2
関数の形だけ先に合わせる
スタブで戻り値の型に合わせて、まずコンパイルを通します。失敗が「型が違う」から「値が違う」に変わります。
- 3
詰まったら失敗出力ごとClaudeに渡す
「このテストの何を読めばいいか」と聞きます。段階1のヒントが返ります。
- 4
自分のエディターで1か所だけ直す
ヒントを手がかりに自分で書きます。直したら
go test -run <テスト名>で、そのテストだけを再実行できます。
Claudeに渡すプロンプトは、答えを求めない形にします。
go testの出力を貼ります。TestHelloNoName が落ちています。
答えは書かず、次に読む場所のヒントを1つだけください。それでも分からなければ「もう1段階具体的に」と頼みます。段階的に絞るのは、一度に全部教えてもらうと、読んで写すだけの作業になるからです。
落とし穴: 設定が合っていても詰まる3か所
落とし穴
Rustでは#[ignore]を外す作業が必要になる
ExercismのRust演習は、最初のテストだけが有効で、残りには#[ignore]が付いています。次のテストに進むときに、自分で外す決まりです。テストファイルを拒否しておくとClaudeは外せません。ただし止まるのはClaude Codeの編集ツールだけなので、#[ignore]は自分のエディターで1つずつ外せます。
落とし穴
スタイルは指示にすぎず、コードを書いてしまうことがある
出力スタイルが与えるのは、従うべき指示で、強制ではありません。「ヒントだけ」と書いてあっても、質問の仕方によっては完成形が返ってくることがあります。気づいたら解答ファイルの拒否ルール(手順3)を足します。
落とし穴
Bash経由の書き込みは拒否ルールで止まらないことがある
Editの拒否ルールが対象にするのは、組み込みのファイルツールと、sedやteeのようにClaude Codeが認識するコマンド、リダイレクトの宛先です。PythonやNodeのスクリプトがファイルを開いて書き換える経路は止められません。テストの改ざんまで確実に防ぐなら、サンドボックスを有効にします。
どの構成を選ぶか
| 目的 | 構成 | 補足 |
|---|---|---|
| 仕事の合間に新言語で小さなツールを作る | 構成組み込みのLearningスタイル | 補足設計判断の数行を自分で書き、残りはClaudeが進める |
| 演習で言語の文法と型を体に入れる | 構成Hint only + テストのdeny | 補足答え合わせはテスト任せ |
| 手を動かす量を最大にしたい | 構成Hint only + テスト・解答ファイルのdeny | 補足コードを書く経路を権限で閉じる |
テストの設計そのものを学びたい場合は、テーブル駆動テストの書き方を扱うGoのテーブル駆動テストの記事が続きになります。Rustでコンパイルエラーに詰まったときは、borrow checkerエラーの直し方で、エラーの読み方を補えます。
まとめ
答えを書かせない仕組みの要は、ヒントの出し方より、書き込みの経路をどこで閉じるかにあります。テストの拒否は答え合わせの信頼性を守り、解答ファイルの拒否は自力で書く量を守ります。スタイルは、その上に口調と段階を載せる層です。まずテストの拒否から入れて、ヒントだけでは我慢できなくなった日に解答ファイルを足すと、練習の強さを自分で調整できます。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。