Cursorで30日間コーディングしてみた——実際に効果のあった方法
100回は見たTypeScriptエラーの赤い波線を見つめながら、ネストされたジェネリクスでのOmitの正確な構文が思い出せない——そんな感覚をご存知ですか?3ヶ月前の私がまさにそうでした。Cursorを使い始めてから、複雑なプロジェクトではもう普通のVS Codeには戻れません。
でも、こういうことです:Cursorは魔法ではありません。最初の1週間は、高級オートコンプリートのように扱って、ゴミのような結果しか得られませんでした。30日間の意図的な練習の後、実際に時間を節約できるパターンと、時間を無駄にするパターンがわかりました。
重要なセットアップ
まず、基本を正しくしましょう。私はmacOSでCursor 0.45.xを実行していますが、同じ原則がWindows/Linuxにも適用されます。インストール後、ほとんどのチュートリアルがスキップする2つの設定をすぐに変更しました:
インライン提案の「自動補完」を無効化(設定 > エディター > Cursor > 補完:オフ)。常に表示されるゴーストテキストが、キー入力ごとに迷いを生んでいました。代わりに、必要なときだけ
Ctrl+Kでインライン生成をトリガーします。「編集を適用」モードを有効化(Cmd+Shift+P > 「Cursor: 編集を適用の切り替え」)。これにより、Cursorが差分を表示するだけでなく、コードを直接変更できるようになります。大幅な時間短縮になります。
80/20の法則:実際に使う2つのコマンド
30日後、Cursorの使用は日常業務の80%をカバーする2つのコマンドに絞られました:
1. Cmd+K:「このブロックを修正」コマンド
これが基本中の基本です。コードブロックを選択し、Cmd+Kを押して、Cursorに何をすべきか指示します。以下は、私が構築しているReactプロジェクトの実際の例です:
// 私が書いたこの混乱を選択:
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秒で生成したもの:
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スクリプトをデバッグしていました:
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を使用した型付きバージョンを提供しました:
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は要求しない限り、型なしのコードをデフォルトで生成します。
ワークフローを変えたパターン
新しい機能に対して私が今行っていること:
- 関数を説明するコメントを書く(実装ではなく)
- コメントをハイライトして
Cmd+Kを押す - 生成されたコードを注意深くレビュー——必ず少なくとも1つのエッジケースを見逃している
- フォローアップのプロンプトで反復:「ネットワーク障害のエラー処理を追加」や「空の配列を処理するようにする」など
最近のプロジェクトの例:
// このコメントを書いた:
// ユーザーデータを取得し、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を押しましょう。未来の自分が感謝するはずです。