Cursorで効率的にコーディングする方法

codingbeginner

# Cursorで30日間コーディングしてみた——実際に効果のあった方法

100回は見たTypeScriptエラーの赤い波線を見つめながら、ネストされたジェネリクスでの`Omit`の正確な構文が思い出せない——そんな感覚をご存知ですか?3ヶ月前の私がまさにそうでした。Cursorを使い始めてから、複雑なプロジェクトではもう普通のVS Codeには戻れません。

でも、こういうことです:Cursorは魔法ではありません。最初の1週間は、高級オートコンプリートのように扱って、ゴミのような結果しか得られませんでした。30日間の意図的な練習の後、実際に時間を節約できるパターンと、時間を無駄にするパターンがわかりました。

## 重要なセットアップ

まず、基本を正しくしましょう。私はmacOSでCursor 0.45.xを実行していますが、同じ原則がWindows/Linuxにも適用されます。インストール後、ほとんどのチュートリアルがスキップする2つの設定をすぐに変更しました:

1. **インライン提案の「自動補完」を無効化**(設定 > エディター > Cursor > 補完:オフ)。常に表示されるゴーストテキストが、キー入力ごとに迷いを生んでいました。代わりに、必要なときだけ`Ctrl+K`でインライン生成をトリガーします。

2. **「編集を適用」モードを有効化**(Cmd+Shift+P > 「Cursor: 編集を適用の切り替え」)。これにより、Cursorが差分を表示するだけでなく、コードを直接変更できるようになります。大幅な時間短縮になります。

## 80/20の法則:実際に使う2つのコマンド

30日後、Cursorの使用は日常業務の80%をカバーする2つのコマンドに絞られました:

### 1. `Cmd+K`:「このブロックを修正」コマンド

これが基本中の基本です。コードブロックを選択し、`Cmd+K`を押して、Cursorに何をすべきか指示します。以下は、私が構築しているReactプロジェクトの実際の例です:

```typescript

// 私が書いたこの混乱を選択:

const handleSubmit = async (e) => {

e.preventDefault()

const data = new FormData(e.target)

const body = {}

for (let [key, val] of data.entries()) {

body[key] = val

}

// ...さらに50行の手動バリデーション...

}

```

「react-hook-formとzodバリデーションを使用してリファクタリングし、ローディング状態を処理し、エラーバウンダリを追加」と入力しました。

Cursorが4秒で生成したもの:

```typescript

const schema = z.object({

email: z.string().email(),

password: z.string().min(8),

})

type FormData = z.infer<typeof schema>

const { register, handleSubmit, formState: { errors, isSubmitting } } = useForm<FormData>({

resolver: zodResolver(schema)

})

const onSubmit: SubmitHandler<FormData> = async (data) => {

try {

setError(null)

await api.login(data)

toast.success('ログインしました!')

} catch (err) {

setError(err instanceof Error ? err.message : 'ログインに失敗しました')

}

}

```

**コツ**:使用したいライブラリとパターンを具体的に指定すること。「リファクタリング」だけでは汎用的なコードが生成されます。「react-hook-formとzodを使用してリファクタリング」と指定すると、実運用可能なコードが生成されます。

### 2. `Cmd+L`:「これを説明」コマンド

実はこれが最も強力な機能です。馴染みのないコードベースやレガシースパゲッティコードを扱うときに常に使用しています。

例:`__getattr__`を理解できない方法で使用しているPythonスクリプトをデバッグしていました:

```python

class ConfigProxy:

def __init__(self, config):

self._config = config

def __getattr__(self, name):

if name.startswith('_'):

return super().__getattr__(name)

return self._config.get(name, None)

```

これをハイライトして、「このパターンを説明し、Pyright用に適切に型ヒントを付ける方法を示してください」と質問しました。

Cursorの応答は驚くほど詳細で、プロキシパターンを説明し、`__getattr__`が欠落した属性で無限再帰を引き起こすことを指摘し、`Protocol`を使用した型付きバージョンを提供しました:

```python

from typing import Any, Protocol

class ConfigProtocol(Protocol):

def get(self, key: str, default: Any = None) -> Any: ...

class TypedConfigProxy:

def __init__(self, config: ConfigProtocol):

self._config = config

def __getattr__(self, name: str) -> Any:

if name.startswith('_'):

raise AttributeError(name)

return self._config.get(name, None)

```

**コツ**:型付き言語を使用している場合は、常に「型ヒント」または「適切な型付け」を要求すること。Cursorは要求しない限り、型なしのコードをデフォルトで生成します。

## ワークフローを変えたパターン

新しい機能に対して私が今行っていること:

1. **関数を説明するコメントを書く**(実装ではなく)

2. **コメントをハイライト**して`Cmd+K`を押す

3. **生成されたコードを注意深くレビュー**——必ず少なくとも1つのエッジケースを見逃している

4. **フォローアップのプロンプトで反復**:「ネットワーク障害のエラー処理を追加」や「空の配列を処理するようにする」など

最近のプロジェクトの例:

```typescript

// このコメントを書いた:

// ユーザーデータを取得し、5分間キャッシュし、

// stale-while-revalidateパターンを処理する関数

// Cursorが生成したもの(3回の反復後):

const userCache = new Map<string, { data: User; timestamp: number }>()

const CACHE_TTL = 5 * 60 * 1000

async function getUser(id: string): Promise<User> {

const cached = userCache.get(id)

const isStale = cached && Date.now() - cached.timestamp > CACHE_TTL

if (cached && !isStale) {

return cached.data

}

// Stale-while-revalidate:古いデータを即座に返し、バックグラウンドで更新

if (cached && isStale) {

fetchUser(id).then(data => {

userCache.set(id, { data, timestamp: Date.now() })

})

return cached.data

}

const user = await fetchUser(id)

userCache.set(id, { data: user, timestamp: Date.now() })

return user

}

```

## Cursorが失敗する箇所(そして代わりにすべきこと)

3つの大きな問題点に直面しました:

**1. APIを幻覚することがある。** Cursorが、使用しているReactバージョンに存在しない依存配列を持つ`useMemo`フックを使用したコードを生成したことがあります。**修正**:常に生成されたコードを実際の依存関係のドキュメントと照合すること。

**2. 大規模なリファクタリングが苦手。** 5つのファイルにわたって「このReduxストアをZustandに変換」するよう依頼したところ、一貫性のないインポートと欠落したステートスライスの混乱が生じました。**修正**:リファクタリングは1ファイルずつ、ターゲットパターンについて明示的な指示とともに行うこと。

**3. プロジェクト固有の規約に苦戦する。** 私のチームはデータベースカラムに`snake_case`、TypeScriptに`camelCase`を使用しています。Cursorは一貫してどこでも`camelCase`を生成します。**修正**:プロジェクトのルートに`.cursorrules`ファイルを作成し、規約を追加する:

```

# .cursorrules

- TypeScript変数にはcamelCaseを使用

- データベースカラム名にはsnake_caseを使用

- .then()よりもasync/awaitを優先

- エラー処理:常に型付きエラーでtry/catchを使用

```

## 本当の生産性向上の秘訣

最大の時間節約はコード生成ではなく、**デバッグ支援**です。不可解なエラーメッセージが表示されたとき、それをCursorのチャット(`Cmd+L`)に関連コードブロックとともにコピーします。これで以下のような場合に何時間も節約できました:

- **TypeScript型エラー**:「型'X'は型'Y'に割り当て可能ではありません」→ Cursorが型の不一致を説明し、修正を提案

- **Reactレンダリング問題**:「最大更新深度を超えました」→ CursorがuseEffectの依存関係の無限ループを特定

- **API統合バグ**:「undefinedのプロパティを読み取れません」→ Cursorが非同期コードを追跡してnull参照を見つける

## 次のステップ

Cursorのすべての機能を一度に使おうとしないでください。以下が7日間の計画です:

**1〜2日目**:インラインコード生成に`Cmd+K`のみを使用。チャット、説明、コンポーザーは使わない。

**3〜4日目**:デバッグと馴染みのないコードの説明に`Cmd+L`を追加。まだコンポーザーは使わない。

**5〜7日目**:プロジェクトに`.cursorrules`を追加し、複数ファイル編集にコンポーザーを試す。

7日後には、実際に効果のあるパターンの筋肉記憶が身についているでしょう。そして、避けられない幻覚や悪いリファクタリングに遭遇したとき、Cursorを信頼すべき時と自分でコードを書くべき時が正確にわかるようになります。

さあ、避けていたファイルを開き、最も醜い関数をハイライトして、`Cmd+K`を押しましょう。未来の自分が感謝するはずです。