emahiro/b.log

日々の勉強の記録とか育児の記録とか。

Claude Code に入門して衝撃を受けた

Overview

巷で大流行の Claude Code ですが、6/5 のアップデートで MAX プランに加入せずとも Pro プランである程度(Opus は使えないけど)使えるようになったので試してみて、そして衝撃を受けました。

今まで Copilot だ! Cursor だ!モデルは何だ!などとあちこち浮気しながら色々使っていましたが、もう Claude Code だけでいいと思うに至りました。

Claude Code の良さ

そもそもなんですが、自分は現在よく使われている Agent については過渡期のインターフェースだと思っていて、便利だから使ってるけど使っていての違和感というものを感じていました。

Claude Code の体験の良さ、スッと自分の開発シーケンスに入ってくるこの感覚をいまいちうまく言語化できないんだけど、もともと Github Copilot にしろ Cursor にしろ、チャットUIでプロンプトのやり取りをするというあのフォーマットは過渡期の産物でもっと開発体験に直接作用するゲームチェンジャーが出てくるかもなと直感的に思ってたから、自然と受容できてる、というのはありそうな気がしている。

emahiro (@emahiro.bsky.social) 2025-06-19T11:51:57.228Z
bsky.app

正直チャットでいちいち指示するのもめんどくさいし、プロンプトの結果として出てきたコマンド等をいちいちターミナルにコピペ作業するのも手間だと思っていました。Claude Code はターミナルにインテグレーションされたツールなので、そもそも結果のコマンド等を自動で実行してくれて出力を得ることができます。この手間がないだけでもだいぶマシです。

またこれは結構感覚的な表現ですがこの感覚はすごくわかるな〜と思いました。

なるほどなー。コード書いてもらうときのCursor/Copilotの饒舌さがきもかったんだけど、Claudeはエンジニア lingoをしゃべる感じだな。圧倒的に読みやすい。

Daisuke Maki (@lestrrat.bsky.social) 2025-06-19T13:20:47.592Z
bsky.app

自分と同じ土俵に経ってる、とも言うべき感覚に近いです。

極めて感覚的話をしてますが、道具である以上この「使い勝手の良さ」というのは本当に重要だなとも思います。

どういうことをしてみたのか?

とりあえず個人プロジェクトに全て CLAUDE.md を作成し、プロジェクトの概要等を全部 Claude で管理できるようにしました。そのうえで自分の持っているポートフォリオサイトである emahiro.dev で以下のことをやりました。

  1. Firebase -> Cloudflare への移行
  2. monorepo 化 (& pnpm の導入)
  3. OGP 画像生成への CloudFlare Workers の導入
  4. Firebase の依存コードの削除

どれもやろうやろうと思っていて全然時間がなくて手を付けられていなかった内容ですが、Claude Code ぶん回して2日程度で全て完了してしまいました。その間ほとんどコードレビューや差分のチェック(トークンが漏れてないか?などの最低限のレビューはした)をせずとも、動くコードとインフラの設定が出来上がってしまい、本当に衝撃を受けました(驚き屋は好きじゃないですが、驚かざるを得ませんでした)

2日後に自分のポートフォリオサイトを構成してるコードの9割は全て Claude に書いてもらったものに置き換わってしまったので、もはや「コーディングそのものは人間の仕事ではなくなった」というのは結構真実に近い話だと思います。

まとめ

Github Copilot が出た以来の衝撃を受けた Claude Code について、その衝撃の大きさにとにかく筆を進めてしました。

今までの Agent とは一線を画すぶっ壊れブキ的なレベルのものであり、AIに淘汰されると入ってもすぐにはソフトウェアエンジニアの仕事もなくならないだろう、、、と高を括っていた前提が瓦解し、自分の中でもそもそものものづくりの仕方の根底が変わるな〜という直感が大きくなってきました。
ものづくりの仕方についてはまた別のエントリで考えてることをつらつらまとめようと思います。

追記

ただこのエントリを書いてる最中に Google が Gemini CLI を出してきて、rate limit はあるものの Gemini 2.5 pro を無料でかなりの量分回せる環境を Google 様が提供してくれたので Claude 解約しました笑

github.com

追記2 (2025/06/26)

やっぱり Claude 再契約しました(1ヶ月分無駄にしましたw)

Gemini CLI の Rate Limit が思ったより早く来てしまい、Gemini 2.5 の場合Pro -> Flash で許容できないアプトプットの劣化を引き起こすので、Google 側の提供環境が落ち着いたり、Pro プランや Ultra プランとの連携で上限の枠が広がるなどの対応が出てくるまでは個人ユースであれば Claude Code でいこうと思います。掌返し大事。

apple/container を触ってみた

Overview

www.apple.com

WWDC 2025 で発表された apple/container を触ってみました。

github.com

How to use

以下にすべて書いてますのでここに書いてある通りにして実際にコンテナを立ち上げることができました。

再起動後に container system start をしないといけなかったりするのはちょっとめんどいですが。

感想

まず Mac を使うにあたって Docker なしでコンテナを立ち上げることができる、というのは嬉しいポイントでした。
Docker がエンタープライズ向けに有料化したり、動きが色々ある中でそもそもコンテナを立ち上げるのに何かをインストールする、みたいなことをしたくないな、と思うようになっていたので、Mac で特に何も意識せずに謹製ツールでコンテナの操作をできるというのは開発者としていい点だと感じました。

ただ、まだ出来立てホヤホヤのツールでもあるので、docker compose 互換じゃなくて手元の docker compose で立ち上げてるコンテナ群で作ってる local 環境をすぐ移行とかはできないですね。

issue も上がってますし、かなりホットな話題なので早晩対応されそうです。

github.com

すぐに乗り換えるとかはないですが、普段使ってる orbstack とかもいらなくなりそう。必要なツールは少ないほうがいいのでいいアップデートでした。

35歳になった

昨日 5/26 日で 35 歳になった。
そして世間で言うアラフォーというやつについに足を突っ込んだ。

今月第二子が生まれていて、プライベートはものすごくてんやわんやしているので、自分がまた1つ歳を重ねたという実感は実はあまりない。
35歳になったらキャリアの棚卸しとか、これからやりたいこととかちゃんと考えるか〜とこの5年間は考えていたけど、そんな余裕は完全になくなった。

気力と体力をほぼ全て育児に持っていかれた30代前半で、これは多分40になるまで続くと思うし、終わることはないと思う。

とりあえず健康でいれればなんでもいいや。

自分なりの Obsidian "with" Cursor (LLM) を始めてみた

Overview

Obisidian と Cursor を組み合わせてインプットのワークフローを構築するのが最近流行っていて、気になっていたので自分なりにこのインプットワークフローを組んでみて、その感想について記載します。

背景

実を言うと自分はあまりこういった効率UP系のコンテンツを残すことは少ないんですが、昨今 Obsidian in Cursor の話をあまりによく目にして、実際に触らず食わず嫌いも良くないので自分なりのメモワークフローというものを組みながら、何ができてなんでこんなに流行っているのか?ということを考えてみました。

なお、以下の記事は目を通して参考にしてみました。

note.com

note.com

結論

先に結論だけ書いておきます。現時点で自分のワークフローは以下になりました。

  • Daily Notes に日々の記録を書き、LLM でブログ形式でまとめてもらう。
  • Thino を使って生煮えの思考を Daily Note に記録して LLM でブログ形式でまとめてもらう。
  • Web Clipper で気になるページをクリップし、LLM に要約してもらう。気になるものは Thino 経由で保存する。

このワークフローを支えているのは、今のところ以下の plugin (core 2 つ、community 2 つ)です。

まだまだ発展途上なので使いながらブラッシュアップしていこうと思います。

そもそもなぜこんなに Obsidian と Cursor が流行っているのか

※ これは単なる自分の考察です。

Obsidian と Cursor を連携したインプットの効率化ハックがこれほどにまで流行るのは以下の理由があるのではないかなと思います。

  1. Web Clipper で ローカル に欲しい情報を md 形式で保存できる。
  2. ローカルに保存してあるので、Editor に同梱されている Agent (LLM) で要約やコンテンツの作成が簡単にできること。
  3. Obsidian 内部で知識を "うまく" 繋げて個人 wiki を作ることが用意であること

この中だと特に1の ローカルストレージに markdown 形式で置けること が非常に大きいのかなと思っていて、というのも今までも Web Clipper のようなツールは Notion なり Google Docs なりで提供されていて、自分なりの後で読むリストを作ることはできていました。

但し、Notion や Google Docs といったコラボレーション SaaS を利用してる以上そのコンテンツやデータに対して直で LLM を噛ませるということができません。ツール側で提供してもらう(Gemini インテーグレーションなど)か、コンテンツをコピペして LLM に噛ませる、などひと手間が必要でした。また

これがローカルストレージ(自分の PC 上)にコンテンツを配置するのであれば、そのデータの持ち主は自分自身になりますし、ローカルストレージ上のデータであれば同じくローカルにあるエディタクライアント(VSCode や Cursor) に同梱されている Agent に簡単に食わせることができます。
今回の場合は Obsidian Valut を VSCode や Cursor で開けば、あとは Editor 上で保存したファイルを開いて Cursor Agent なり Copilot なりに問い合わせをすれば、今までより簡単にコンテンツの要約や考察、二次コンテンツの生成まで可能になります。

結局今まであれこれ作業していたことをワンストップでできてしまう便利さが先行して流行っているのかな、という仮説を立てました。

なお、3 については Obsidian のベターなメモ記法 (Zettelkastenなど?) がありますが、これが「いい!」と思ってる人は今のはやりの前から Obsidian を利用していたと思うので今回は割愛します。ちなみに少しずつメモって有機的なつながりを作っていく、というのは Thino で少し実践してるので自分もこのメモ記法には価値を感じています。

まぁ、ちょっとこういった流行りには冷笑的なポジションを取りがちなんですが、使ってみると思いの外便利だったので流行りには乗っていこうと思いました。

P.S

エントリのタイトルに "with" を使っているのは、これ別に Cursor じゃなくても成り立つな?と思ったので "With LLM" の意味を持たせるために Obsidian in ~ ではなく Obsidian with ~ にしました。

2児の父になった

GW 中の 5/2 に2人目が生まれ、2児の父になりました。

2年ぶりの新生児の育児ですが、1度経験してるにも関わらずやったことは全て忘れていて、かつ上の子はちょうどイヤイヤ期真っ最中なのもあってとにかくバタバタでカオスな毎日が続いています。

というわけで、明日から 6 月末まで育休で 1.5 ヶ月ほどお休みします。
ただ、娘を保育園に送っていった後の日中は割と暇なので、またリモートで雑談する時間とか作ろうかなと思っています。暇つぶしに付き合ってあげようという優しい方はぜひ連絡ください笑。

育児がんばるぞい。

Cursor から Copilot に戻っている話

Overview

タイトルの通りなのですが、AI Coding ツールとして Cursor を利用してきましたが最近 Copilot の利用に戻っています。

なぜ戻ったか?

最大の理由は VSCode との親和性と Copilot がものすごい速度で Cursor (や Windsurf) などの AI エージェント内蔵エディタの機能をキャッチアップして機能差が減ってきていることです。

特にプロンプト入力周りの補助機能や MCP と連携したツールを実行するときの UX が Copilot の方が今は充実しています。

また最大のボトルネックだった Agent Mode 時の UX がちょうど GPT4.1 が登場したこともあり、精度はさておき大量の入力にも対応できるようになって Coding Agent の体験も改善したのも追い風になりました。

github.blog

実際コードを書くだけであればもう GPT4.1 だけ使っていればいいかな、という感じがあります。状況によっては Gemini 2.5 pro や o3 を利用することもありますが、自分はほとんど GPT 4.1 を利用しています。

実はこのエントリを書くまで Copilot に戻った最大の理由は VSCode のみが GitHub拡張機能をサポートしており、Cursor からは無理で、VSCodeからしGitHub の permlink を発行できないと思っていたのですが、Cursor にもこの GitHub の拡張をインストールできたので、同じことを Cursor でもできました笑. ただ後述もしますが、この拡張機能が Cursor でサポートされ続けるかは若干あやしい気がしています。

Cursor への不満と今後への不安

Claude との親和性が極めて高く、様々なモデルへの対応も即時に対応される Cursor の良さももちろんありますし、昨今 Cursor を使った様々な業務フローの改善 Tips 等も共有されていて、 Cursor は極めて汎用性の高いツールだなと思っていますが、自分は殆どコーディングにしか使っていないので今時点で Cursor でも Copilot でもどちらでも良い、というタイプになります。

また、Cursor のプレミアムリクエストを使っても度々 o3 や Gemini 2.5 pro といったプレミアムモデルへのリクエストが失敗することがあり、ユーザー数が爆発的に増えた結果諸々の使い勝手が若干悪くなってるなと感じてて、Cursor そのものへペインが少なからず溜まっていたこともあります。(Auto モードという選択肢もありますが、手動でモデルを指定する回数を減らしたいという意図とは裏腹に、プレミアムモデルへのリクエスト失敗が多いことから、モデルの利用キャパシティが逼迫気味なのかな?と邪推したりもしています)

最後に、これは本当にただの当てずっぽうの予想なのですが、VSCode の持ち主である Microsoft 側からの締め出しリスクということが懸念されます。

実際に C/C++ の拡張がブロックされてる事例もありますし(これはそもそものライセンスの問題らしいですが)

github.com

Cursor も Windsurf も OSS としての VSCode へのフリーライドに依存している点は正直気になっています。プロダクトの安定提供という観点で見るとどうしても大元を握っている企業が有利で、この場合Microsoftのさじ加減一つで状況が変わってしまう、みたいな点でどうしても信頼しきれない自分がいます。まぁMicrosoft側に立つとOSSで提供しているとはいえ、投資してきたコストにそのままフリー・ライドしている状況をどこまで許しておくのか、とも思いますし、Cursor に慣れきったところで VSCode が提供している拡張機能の利用ができなくなるといったことが起きないとも限らないので、ある程度機能差がなくなった現時点で Copilot に帰ってきた、という感じです。

戻ったところで使用感は自分の利用用途においてはそこまで変わらないんですが、ただやはり Copilot の Agent Mode の遅さは気になります。Copilot が遅いというよりは Cursor が速すぎるのでは?とも思っていますが笑

歴史的にもいろんなツールが生まれつつも GitHub が提供してるツールに収斂してしまった(CircleCI とか TravisCI とか結局 GitHub Actions になってしまった)流れもあり、今回も GitHub を持ってるMicrosoftのツールが最終的にはエコシステムを飲み込んでしまうのではないかな?と思っており、ある程度 AI Coding (Vibe Coding) というものに慣れたところで Copilot (純正 VSCode) 回帰してますが、まぁ色々あってまた他のツールに手を出す可能性もあります。ただ VSCode 自体もAgent Mode の速度は課題に感じているようで、今後 VSCode 側で この Agent Mode の速度の改善に取り組む ことが予定されていてCursor に使用感が近づく可能性もあります。 こういったところは使用感含めて試していきたいと思います。

FastMCP を触ってみる

サマリ

Mastra に続いて簡単に MCP サーバーを立てることができる FastMCP を触ってみました。

github.com

こちらも TypeScript で記述可能でした。

実装

書いたコードは以下に置いています。

github.com

今回は Gemini の API Key を使った Gemini wrapper を作りました。正直これだけのコードで MCP 作れちゃうのはだいぶ楽でした。

これを Claude の Desktop アプリで動かしています。

ドキュメント通りに実装したらほぼハマるところはありませんでした。

一点だけあったのは Mastra もそうだったのですが、MCP サーバーとして Local で node のランタイムを動かして動作させる場合、package は module として登録しないといけない というところです。

pacakge.json 内部では type: "module" で登録することで Claude や VSCode などの MCP クライアントから MCP サーバーとして認識させることができました。

感想

Mastra はエージェントを作るための重厚なフレームワークという印象があり、対象的に FastMCP はよりプレーンな薄いフレームワークといった感じです。
良い例えか微妙ですが Mastra は Rails で FastMCP は grape 、というようなウェブアプリのフレームワークの役割の違いを感じました。

Mastra に入門する

サマリ

Mastra とは

最近話題なので特に詳しくは書きませんが、自分は以下の記事を参考にしてました。

zenn.dev

自分は以下のスライドを見て初めて知りました。

speakerdeck.com

入門してみる

Scaffold する

npx create-mastra@latest すると scaffold なアプリが作成されます。
ドキュメントも丁寧ですし、作られたアプリ(お天気アプリ)の実装を見ると何をどこに書けばいいのか?ということはすぐに分かります。

面白なと思ったのは create mastra-app する過程で MCP の設定シーケンスがあることです。現時点では Cursor と Windsurf の設定のみがシーケンスにありますが、 npx コマンドを設定するだけで VSCode の設定もできます。

MCP 経由で Mastra の Example や Docs を参照でき、やりたいことをプロンプトで伝えるだけで、ドキュメントをベースに実装を提案してくれます。これはすべての言語、フレームワークで備わってほしい標準仕様になってほしいです。ドキュメントを読み漁るあの時間が限りなく短縮されますし、開発者体験として最高でした。

余談ですが、自分が普段開発に使ってる Go にも標準で入る話があるらしく、これはすごく嬉しい話。

github.com

なお自分は Scaffold したアプリを動かすのに Gemini を利用しています。Gemini だと簡単に API Key を発行できて管理も(自分的には)慣れた UI でできるのでこういうときにサクッと使えるのは GCP の良さだと感じます。

各種機能を使う

Mastra は API が生えていて、インターフェースは Swagger で提供されています。自分はまだ触っていないところなのでこの辺は触っていきたいと思います。API を提供してくれるから Scaffold なアプリの UI ではなく独自の Agent や、Slack のようなアプリとも連携できるわけなんですね。

また機能ではないですが Zod を使ったスキーマ定義をしてる部分も興味深かったのでこの辺も深堀りポイントかなと感じています。

MCP と連携する

MCP がサポートされているサービスに対して今回作成した Agent を連携してみました。
とりあえず自分はいちばん簡単な MCP との対話をできるような連携をしてみましたが、Stream という会話を継続させる中で MCP を使うインターフェースもあるみたいで、こちらも試してみる予定です。

手順は Using MCP in Your Code に書いてる通りの流れで試しました。サクッとできてすぐに動かせます。
MCP は認証込みのものを利用すると Client が Connection を確立できずに落ちるケースがあるので自分は mcp/time のような認証のいらない MCP で試しました。

使ってみての感想

ML や昨今の LLM のバックグラウンドに詳しくなくても実装できる

これは価値としては大きいと感じました。
自分も LLM、さらには Agent と呼ばれる流行りの技術に対してはあまり追っかけておらず素人なのですが、まずは Scaffold で作られるアプリケーションを眺めるだけでも、どういう実装なのか?とかどういう作りで行くべきなのか?といった流れが俯瞰できました。

ただ、作ってみて思ったのは LLM で非構造データを扱うことはできても、Agent が依存してるツール群(MCP やその他の実装、 APIなど)に渡す情報はある程度構造化されてる必要があって、入力値の検証や構造化といった前処理が大事になりそうだなという感じも見受けられました。

Typescript で統一できる

Typescript のエコシステムに乗っかっているので、プロジェクト全体の技術統一の観点からも良さそうだなと感じました。昨今技術スタックを Typescript に統一していく流れを感じていますが、そこにも乗っているように思います。

総じて体験は良い

と感じます。まだまだ触り始めで、自分で欲しいもののユースケースがわからないのですが、MCP が公開されてるサービズもあるのでいくつか組み合わせて Agent と呼ばれるものを作ってみようと思います。

またまた余談ですが、この提供されてる API をうまく組み合わせて(マッシュアップして)サービスを作る等には過去に通った道でもあり、時代や世界観が変わってもやってることはあまり変化ないなと感じました(笑)

github-mcp-server を試してみる

サマリ

GitHub MCP Server とは

github.blog

GitHub が公式に公開してくれた MCP 対応した remote server 。このエントリを書いてる時点では現在 preview

あと Go 製。リモートサーバーとしての提供を考えると docker でコンテナを立てたりせずに、バイナリポン置きで動作する Go はツール作るのには向いてる言語だなと思います。

試してみた

設定方法はほぼ https://github.com/github/github-mcp-server?tab=readme-ov-file#installation に書いてあるとおりで動きます。

docker をインストールしてるなら設定を追加するだけで動きます。 Github の PAT が必要なので事前に GitHub の設定で作成しておく必要はあります。

Go 製ということもあって、バイナリを go install github.com/github/github-mcp-server/cmd/github-mcp-server@latest でインストールできます。また VSCode では引数に stdio を設定することで PAT を設定ファイルに渡さなくてもよいと言うのは開発者ツールとしてはよく出来てるなと思います。

以下のような設定になります。

  "mcp": {
    "inputs": [
      {
        "description": "GitHub Personal Access Token",
        "id": "github_token",
        "password": true,
        "type": "promptString"
      }
    ],
    "servers": {
      "github": {
        "args": [
          "stdio"
        ],
        "command": "github-mcp-server",
        "env": {
          "GITHUB_PERSONAL_ACCESS_TOKEN": "${input:github_token}"
        }
      }
    }
  },

実際動かしてみましたが、 get_me で認証者の情報を取得できればほぼすべての tool は動きます。
ただ動かしてみたときにプロンプトが難しくて、手元のターミナルで git コマンド叩いちゃったりするなど、工夫が必要なところがありました。

使い所

git コマンドに馴染んでいたり、GitHub の操作に慣れているとそこまであって有用かと言われると難しいラインですが、一つ、Pull Request の一覧を取ってこれるので半期ごとの振り返り等で半年分の Pull Request を取ってきて要約させるとかそういう用途では有用だなと思いました。

Workflow の操作が MCP のツールとしてサポートされるとわざわざ GitHub Actions の結果見ずとも CI が落ちた理由とかわかってそういうユースケースでは便利になりそうだとという予感がありますが、そもそものインプットする情報量が多すぎる場合はまともに動かないことも今現在はあるのでまだまだ発展途上で各方面のエコシステムが揃うのが待ち遠しいです。

Cursor の @PR でセルフレビューをしている

Overview

Cursor Editor でプルリクエスト作成前に "セルフレビュー" をいれているのですが、これが思っていた以上に効果的だったので、このことについて書きます。

Cursor Editor の @PR エイリアスを利用したコードレビュー

Cursor Editor の @PR というエイリアスで master との差分のみを LLM の解析対象にいれることができます。
これを利用すると、一旦ある程度実装が終わったときに、その実装範囲を対象にした LLM によるコードレビューを入れることができます。

レビュー結果を出力して採用したければそのまま Accept をすれば変更すら自動化できます。

ルフレビューの効用

タイポの軽減

まずいちばんに感じたことはこれでした。
変数名だったりファイル名だったりといったところに潜む ありがちなタイポが劇的に減ります。

プルリクの Description の出力負荷経験

プルリクエストの Description を出力させることもできます。
「書かないといけないとわかっていてもやっぱりめんどくささを感じてしまう」ポイントだと思いますが、自分は極力そうならないようにと意識しつつも込み入った差分になるときは 「 @PR プルリクエストの Description を出力して」というプロンプトで、説明文を LLM に書いてもらっています。

レビュイーの負荷軽減

上記 2 点が改善されるだけで、そもそものプルリクエストのレビュー負荷が減ります。
また、差分においてコメントを残した方が良いポイントやテストケースの追加、より良い実装も提案してくれます。 時折、冗長すぎるコメントを残してしまうこともありますが。

ケアレスミスを軽減できる価値

自分はかなり注意力散漫なタイプで、人生でもケアレスミスに苦しんできたタイプでした。

プルリクエストもフィードバックを取り込むことに躍起になって前述したタイポなりコメント不足なり、テストケース不足といったことに悩まされて来たエンジニア人生でした。

直そうと思ってもやはり日々仕事してる中で事前の「見直し」といった作業が習慣化しなかったり、してもミスっていたりといったことが多くレビュイーに負担をかけ続けてきたなかで、このセルフレビューは個人的には画期的な発明だと感じます。自分と同じようなタイプの方にも刺さるんじゃないでしょうか。

Vibe Coding による出力は期待値のブレも一定ありますが、少なくともその出力において自分が述べている「ケアレスミス(人間的なミス)」はほぼ無いという安心感があります。

僕自身は LLM によるコーディング支援はものすごくありがたいと感じますし、自分がペインに思っていたところがバチッと現実の業務にも速攻で生きています。出力ガチャばかり注目されますが、現実の業務に生きるポイントというのはこういう(相対的に)地味なポイントなんだなと感じました。

AI Coding を始めた

Overview

最近話題の AI Coding *1を先月末から始めてみました。実際に使ってみて得られた気づきや、個人的に「これは考えを改めないとな」と感じたポイントがあったので、備忘録としてまとめておきます。

AI Coding については、すでにSNSを中心に多くの知見や導入事例が出回っているため、本記事では詳しくは触れません。

個人的には、以下のZennエントリとオライリーのブログ記事が非常に刺さりました。

zenn.dev
www.oreilly.com

AI Coding との付き合い

最初に AI Coding を体験したのは GitHub Copilot でした。本格的に使い始めたのは2年前で、Copilot がローンチされてから半年以上経っていた頃でした。

当時、すでに LLM を内蔵したエディターも存在していたようですが、巨人の肩に乗る感覚で Copilot をメインに利用していました。また、その頃は Devin のような自律型AI Coding Agentもまだ登場しておらず、「ソフトウェアエンジニアはすぐに廃業にはならないだろう」「コードを書く手段として LLM を使うのは一つの選択肢だけど、これが主流になるにはまだ時間がかかるのでは?」と感じていました。

今思えば完全に見誤っていました。僕にとって当時の LLM は「めちゃくちゃプログラミングに詳しいメンター」という位置づけで、やりたいことや実装の方針を伝えたうえで、各種ドキュメントや OSS のコードをベースに提案をもらったり、コードリーディングの伴走をしてもらうような使い方をしていました。

まさに「Copilot(副操縦士)」という役割で、VSCodeとの親和性も高く、自分にとっては生産性を十分に高めてくれる存在でした。

Cursor との出会い

正直、Copilot で満足していたこともあり、「新しいエディターの機能もいずれ Copilot に取り込まれるだろうし、急いで使わなくても良いかな」と思っていました。

そんな中、現職で Cursor のトライアルが始まり参加してみたところ、その感覚が完全に覆されました。

使用感については以下に投稿しています。

実際に触ってみて感じたのは、Cursor は明確に「AI ファースト」である、ということです。

エディター自体は VSCode のフォークなので、若干 UI や機能に差はありますが、GitHub 連携以外の設定はほぼ引き継げるため、VSCode ユーザーであれば違和感なく使えると思います。

VSCode と Copilot だけを使っている人は、ぜひ一度 Cursor や、もう一つの対抗馬である Windsurf のような AI ファーストエディターに触れてみてほしいです。

開発パラダイムの変化と生産性への影響

Copilot のない時代から Copilot を経て、Cursor のような AI First Editor を体験してきた中で、「実際どれくらい業務の生産性が上がったのか?」という点ですが、個人的には Copilot を導入したときの方がインパクトは大きかったと感じています。

Cursor を使った際の生産性向上は、劇的というよりは緩やかな印象です。
これは「0→1」と「1→10」の違いや、LLM に慣れてきたこともあると思いますが、そもそも開発スタイル自体を AI 時代に合わせてシフトしてきたことも要因です。

従来は「書きながら考える」スタイルだったのに対し、現在は DesignDoc や詳細設計を先にテキストで書き、それを Cursor に渡して実装を生成させる、という流れに変わりました。

このやり方では、人間は「書く人」ではなく「出力を調整する人」になります。そして、この手法では事前に関数名やシグネチャレベルの詳細まで設計に落とし込む必要があるため、その準備に時間がかかることで「生産性が劇的に上がった」という実感を得にくい、という仮説を持っています。

実際、現職の他のエンジニアからも似たような感想を聞いています。

ただ、このパラダイム変更の利点は「変更点が確実にドキュメントとして残る」点です。
Pull Request 作成時に丁寧な説明を書く文化がない環境では、PR の意図が不明確なまま進んでしまうことも多いと思います。AI に渡す前提として、差分の全体像を言語化することを強制されるこの手法は、そうしたペインを軽減するソリューションになり得ると感じています。

とはいえ、開発スタイルを大きく変えることになるため、万人にとってフィットするわけではないとも感じています。

プレーンテキストの価値

AI Coding を始めて最も実感しているのは、「プレーンテキストで残しておくことの価値」です。
この点については、t-wada さんのポストが的確に表現してくれていました。

ソフトウェアはテキストで記述された指示や設定に基づいて動作するものであり、現状がテキストで残っていることは LLM 時代において非常に有利な状態だと感じます。逆に、テキスト化されていない情報は、LLM にとってアクセス不能です。IaC 化されていないインフラは、その典型例かもしれません。

かつて「コードがドキュメント」という言説には否定的でしたが、今では「最新の状態を反映したコード」が最良のドキュメントである場面もあると認識が変わりました。

LLM の存在により、コードをドキュメントとして読むハードルが下がり、実装と仕様の接続がしやすくなったと感じています。

MCP に感じた未来

AI Coding において重要なのは、「AI に適切なコンテキストを与えること」だと実感しています。
チームのコーディング規約やガイドライン、開発フローや外部ドキュメントなど、AI に求める出力の質を左右する情報はすべて前提として渡さないといけません。

インターネットを眺めていると全てのドキュメントを markdown に変換して cursor のルールとして定義する、という方針を見かけることもあります。
これはソリューションの1つとしてはあり得ると思いますし、実際そうしてる組織もあると思います。
AI Coding の第一歩として全てのドキュメントを1箇所に集めるという方向性は同意しますが、自分はこの方向性がベターなのかと言われると、結局ルールが肥大化してメンテしきれなる未来が想像できるので少し疑問を持っています。

このルール管理の課題を踏まえたとき、Anthropic が提唱している Model Context ProtocolMCP)は非常に興味深いアプローチだと感じました。

www.anthropic.com
zenn.dev

MCP では、AI に渡すコンテキストを用途ごとに分離・管理しやすくすることで、ルールが肥大化せず、柔軟かつシンプルに保てるのではないかという仮説を持っています。
実際に社内でいくつかの MCP デモを見たとき、コンテキストを渡す手段、及び開発補助ツールとしての活用事例に可能性を感じました。
(※あくまで個人の感想です)

まとめ

AI Coding を通じて、自分の考えを整理してみました。
現職にはこうした取り組みに先進的なメンバーが多く、自分もそのおかげで新しい開発パラダイムをスムーズに学べており、本当にありがたい環境だと思っています。

AI Coding は、開発の常識を根底から変えていく技術だと思います。
個人的には、Go や Google App Engine に出会ったとき以来の衝撃でした。最初は「乗るしかないこのビッグウェーブに!」くらいのノリでしたが、今では「やっておかないとヤバい」くらいの危機感すらあります。

こうした変化をリアルタイムで体験できるのは、自分のキャリアにとって幸運なことだと感じています。

ただし、しんどさもあるのが現実です。
「ソフトウェアエンジニア廃業論」については懐疑的ですが、仕事の中心が「書くこと」から「指示すること」にシフトした今、ある意味では仕事がしんどくなったとも言えます。

ベンダーマネジメントで行っていた「指示出し」を、今はコード実装にも求められている──そんな感覚があります。
これは実際にネット上でも同様の意見を多く見かけます。


それでも、AI Coding は不可逆なパラダイムシフトです。
だからこそ、自分も「やっていかないとな」と思っています。

*1:このブログを書いている時点では「Vibe(雰囲気)Coding」と呼ぶのが正確らしいです

現職で6年目を迎えた

今日で現職6年目を迎えた。 (アルバイト期間を含めているので厳密には今月中旬が正式な6年目ではある)

5年目を迎えたときのブログを書いたが、あっという間に1年経ってしまった。

ema-hiro.hatenablog.com

現在進行系で最長在籍記録を更新中である。毎年思ってるがよく辞めずに続いているな〜と思う。ちなみに去年のブログを読むと自分は「次」を考えるつもりだったらしいが、結局1ミリもそんなこと考えていなかった。

在籍し続けている理由はいくつかあると思うが、現職は働きやすさと業務の難易度のバランスが非常に良く、わかりやすく言えば「飽きない」環境を提供し続けてもらっていると思う。
居続ける理由は人それぞれだと思うけど、自分はトータルで見て「飽きない」ということが在籍し続ける動機として大きいことは間違いなさそうである。(もちろん頑張ろうと思える待遇も出してもらってる)

自分のキャリア、いつ、どこで、どういうことが起こるかわからないので、離れるときがいつ来ても良いように準備はしてるが、今のところその気配はない。
それどころかちゃんと評価されて今年は Promotion もして頂けた。責任は(多少)増えたが、一方で外資で Promotion を経験する、というのは自分の中で1つの大きな目標としていたところでもあるので、達成できてホッとしている。

自分として掲げていた目標をクリアはしたが、まだしばらくは面白い仕事が続きそうのと、今年も大きな変化のある年なのでもうしばらくは在籍してると思う。

節目の記録なのにエモいことは全くと言っていいほど書けなかった。まぁまた1年ゆるゆると頑張っていく。

Go 1.24 から導入された json の IsZero に触れてみる

Overview

Go 1.24 から encoding/json に入った IsZero のインターフェースについて実際に触ってみて挙動を調べてみました。

IsZero とは?

When marshaling, a struct field with the new omitzero option in the struct field tag will be omitted if its value is zero. If the field type has an IsZero() bool method, that will be used to determine whether the value is zero. Otherwise, the value is zero if it is the zero value for its type. The omitzero field tag is clearer and less error-prone than omitempty when the intent is to omit zero values. In particular, unlike omitempty, omitzero omits zero-valued time.Time values, which is a common source of friction. If both omitempty and omitzero are specified, the field will be omitted if the value is either empty or zero (or both).

tip.golang.org

リリースノートを参考にすると今まで time.Time に入っていた IsZero メソッドを生やしたカスタムフィールドに対して json タグで omitzero を付与することでいわゆる「ゼロ値」の振る舞いを json.Marshal, Unmarshal の中で制御することができるようになるようです。

サンプル実装

まず標準の time.Time を渡してみます。

// You can edit this code!
// Click here and start typing.
package main

import (
    "encoding/json"
    "fmt"
    "time"
)

type X struct {
    A time.Time `json:"a,omitzero"`
}

func main() {
    x := X{}
    b, _ := json.Marshal(x)
    fmt.Printf("%v", string(b))
}

ref: https://go.dev/play/p/nkBKMnKym7i

この出力以下のようになります。

{}

続いてカスタム型に IsZero メソッドを生やしてみます。

// You can edit this code!
// Click here and start typing.
package main

import (
    "encoding/json"
    "fmt"
    "time"
)

type X struct {
    A time.Time `json:"a,omitzero"`
    B Y         `json:"b,omitzero"`
}

type Y struct {
    UserID int
}

func (y Y) IsZero() bool {
    fmt.Println("aaaa")
    return true
}

func main() {
    x := X{}
    b, _ := json.Marshal(x)
    fmt.Printf("%v", string(b))
}

ref: https://go.dev/play/p/sDVeZEzEZlm

この出力は以下のようになります。

aaaa
{}

これは IsZero メソッドの返り値が true (= つまりどんな値をとっても omitzero で消える) なので出力結果は空になります。

ただ少しコードを変更してみます。

// You can edit this code!
// Click here and start typing.
package main

import (
    "encoding/json"
    "fmt"
    "time"
)

type X struct {
    A time.Time `json:"a,omitzero"`
    B Y         `json:"b,omitzero"`
}

type Y struct {
    UserID int
}

func (y Y) IsZero() bool {
    return y.UserID == 0
}

func main() {
    x := X{
        B: Y{
            UserID: 1,
        },
    }
    b, _ := json.Marshal(x)
    fmt.Printf("%v", string(b))
}

ref: https://go.dev/play/p/roo_uNbSGKI

この出力は以下のようになります。

{"b":{"UserID":1}}

Y の中にある UserID が 0 のときは omitzero で消えるようにしてるので、0 以外を指定したときには omitzero の対象になりません。

振る舞いとユースケース

この omitzero (IsZero メソッド)の導入により、今まで json の key から消すには json で Unmarshal するフィールドの定義を参照型にする必要があり、これが意図しない nilpo の温床になっていたり、クライアントアプリから見るとあるはずの key がない、と言ってフロントのエンバグに繋がることもありましたが、今回 の omitzero の導入で「どういうときにゼロとするか?」という仕様を決めることができるようになると思いました。Go の実装としても不要な参照型を排除することで nilpo を踏む可能性を少なくできますし、より堅牢なプログラムを書けるようになりそうです。

また別のユースケースとしては、A/B テストや本番と開発環境(テスト環境等)で特定のフィールドを入れる、入れないを IsZero の中で制御し、クライアントの振る舞いを変更するといったことも実装の深いところではなく、JSON を作るより上層(Converter や View といったレイヤー)で行うことができて不要な依存を深いところに埋め込まなくて済む、といったことも考えられそうです。

まとめ

最初は今更 encoding/json におけるゼロ値の取り扱いを再定義することのメリットは何なのか、ぱっとわかりませんでしたが、実際に実装してみると少しわかりました。使っていきたいと思います。

actions/setup-go で Go のバージョンを指定する

もともと GitHub Actions で Go のバージョンを指定するときは matrix 構文を使って go のバージョンを渡していた*1が、今は actions/setup-go で指定できるようになっていたことを知らなかった。

zenn.dev

Go は下位バージョンとの互換性を保っていてくれるのもあって、大体新しい Go のバージョンが出ると最新に上げてしまうし、それで動いてしまうことも多いので、常に go-version で最新を指定しておけば良さそう。

追記: 自分でもわすていたのですが、過去に全く同じ内容を備忘録として残していました(笑)

ema-hiro.hatenablog.com

*1:Goは下位2version をサポート対象としてるので 2 version 分の Go のバージョンチェックが出来るのは便利は便利

『マネジメントは嫌いですけど』を読んだ

Overview

『マネジメントは嫌いですけど』を読んだのでその備忘録です。
自分はピープルマネジメントに関わる業務をしてるわけではないですが、プロジェクトマネジメントには主たる業務として担当しているので、その勉強も兼ねて読んだのですが、ピープルマネジメントの話よりも後半にあった お金にまつわる組織力 の話が非常に興味深く勉強になったのでその観点について自分の考えてることも含めてつらつらとまとめてみます。

キャリアパスから組織を考える

エンジニアの貢献を評価してもらうのは難しい。

前提として一般的な MBO(Management By Objects) を評価に採用してる企業を念頭に書かれていますが、MBO の評価には以下のような傾向があります。

  • MBO による評価においては、エンジニアの貢献(技術力を上げる、少しずつ改善する、悪い出来事が起こるのを未然に防ぐ)というものが評価されづらい。
  • MBO による評価においてはエンジニアの貢献(何も起きないということにどれだけの労力を割いているか)に価値があるかを評価する術を持たない。

これは実際に仕事をしていても評価のタイミングでたしかにこの傾向はあると感じることは多いです。

報酬は経済が決めている

評価に報いるのは「報酬」です。
ただ、この報酬を決める原資に目を向けると、営利企業に所属してる以上は企業が外部から得ている収益(売上)がそれにあたります。

優秀な社員への報酬が安すぎると見られる場面でも、所属してる企業の得ている収益という原資を超えて報酬を出すことはできません。
これはある程度社会人を経験すると、給料の多寡というものは、その人のスキルではなくその企業の売上(更に行ってしまえば仕事をしている市場)によって決まる、というのは特に不思議なことではないです。
このあたりはインターネット上で良く「椅子取りゲーム」と揶揄されたりするので最近では一般的な考え方として浸透してると感じてますが、本人の努力とは無縁に(ゼロではないにしろ)報酬額が決まるというのはいかにも資本主義経*1だなと感じます。

また別の文脈で、この原資から報酬をどう差配するのかはファイナンスの責任範囲になる、というのも組織の構造があります。
この構造を元にすると、技術者の技術的な貢献に対する配分の枠をある程度確保するには、ファイナンスに技術を分かる人(言ってしまえばエンジニア出身者)をアサインしていると、技術的な貢献に対しての報酬はレバレッジの効いたものもなる可能性があります。
ただ、自分もそうですが、そういった企業に所属したことはありませんし、資本主義というゲームの中では例え技術的な背景のある人がなったとしても難しいのではないかなと思います。そういった技術者の貢献が正当化される世界線というものは自分もあまりイメージができません。あるのかもしれませんが、少なくとも例外的な存在ないなるんじゃないかと思います。

組織の中のお金の理屈

プロジェクトにまつわる「お金」には2種類あり、CAPEX(Capital Expenditure) と OPEX (Operating Expenditure) があり、自分が勉強になったのは OPEX の取り扱いでした。

都度発注ではなく年間の概算で予算を立てる

これは身近なインフラチームが毎年やっているので馴染みがありましたが、

  • 年間を通した予算調達にすることでのオペレーションコストの削減(都度発注にすると毎回調達のオペレーションコストがかかる)
  • 発注をまとめることで購買価格を下げる作用がある。
  • 予算管理をしてる部門は、年間予算で動くので進め方ともアラインしている。
  • 予算は資産と利益を見通すために必要で、都度発注のような不確実なものは避けられる。

というメリットがあります。

こういった予算を決めるためのメリットと言ったものはその立場にならないと触れられない観点であり、会社の名kでどうしてそう動いているのか?ということがわかるとお金にまつわる解像度が一段上がりますし、自分が交渉するときに知識として持っておいて損はない内容だと思います。

削減する方向ではなく、伸びていく方向に目を向ける

個人的にはこれはコミュニケーションテクニックの類だと思いましたが、「XXX な金額を YYY 円(%) 削減 」という伝え方でなく「同じ金額で ZZZ 倍の性能を手に入れる」という伝え方で評価するというものです。
削った予算は返ってこない or もっと削れるというリクエストに繋がるので、同じ予算を使って効用がどれくらいあったか?という伝え方にするというのは目からウロコでした。実際の仕事でも使っていきたいポイントです。
この伝え方を知っていると「100万円かかるものが50万円になりました」ではなく「100万円で200万円分の効果がありました」となります。確かに自分が予算の差配を握っている立場であれば、どちらも同じくらい勝ちがあると思いますし、何より現場からすると予算が削られないメリットを享受することができて一石二鳥感があるなと思いました。

維持する予算は新しく何かを作る予算より確保しづらい

一度成果が確定したものを維持するコストというのは、予算策定部門から毎年削減してほしいと要求が来ます。これも身近でこのコミュニケーションを見てるのでわかりますし、業務で予算の削減系のタスクをしたことがあるのでよくわかります。
サービスを維持するのに必要な予算なのに、そんな簡単に削られる分けないだろうと思いつつ、そもそも維持コストはそのまんま固定費として計上される事が多く、固定費はまんま削減対象となるというのはわかりやすい帰結だなとは思いました。固定費を削れば会社の売上に対する損益分岐点を手前に持ってくることが出来るので、会社としてその意思決定になるのはしょうがないことでもあるというのは理解できます。

ただ、削減のゴールは究極的には「ゼロにする」ことで、それは廃止(サービス終了)と同義です。
サービス終了する気はないが、コストは限界までゼロにする、というのは結構身勝手なファイナンスの要求だなと思ったりもしますし、これまた現場レベルで考えると当然の考えかなとも思います。

ただこれまたテクニックだなと思ったのですが、この削減を回避するために、「新しく作り直すことで付加価値を見せて、維持する予算も取る」ハックが存在するというのは納得感がありました。自分自身そうしたやりとりは何度か目にしたことがありますし、知らず知らずのうちにやっていた記憶もありました。

承認の負荷の意味とリジェクトの基準

Pull Request などがわかりやすいですが、技術職は日常的に「承認を得る」活動をしています。
そしてこの承認にはいくつかの基準があります。

同じようにマネジメントにも「承認」の活動がありますが、現場仕事とはまた違った「重さ」が存在します。それは当然でマネジメントサイドの承認には関連するステークホルダーが多いので、その承認をされるかされないかで社内外問わず影響を受ける人の数が違うということが挙げられます。

ただ、承認されるものは否認されるものもあり、本書にもありますが、承認ばかりされるよりもきちんと否認されることが文化として整理してることのほうが価値があるということは自分としても確かに、、、と感じるところはあります。
否認にはそもそも承認以上のコストが掛かるものですし、疎まれもします。
ただし、否認するならするでその基準が必要だと最近考えています。個人に属人化したブラックボックスな基準で否認されても、された側はどうして否認されたのかわかりませんし、それがそのままネガティブな感情に結びつくことは想像に難くありません。

組織として承認と否認の基準を明確にし公開しておくと、リクエストしたりプロポーズする側はその基準を学び、その基準を満たすための準備をします。結果として意思決定のレベルは平準化されるので、この基準を作るという行為は、組織全体のレベルアップにもつながると思いました。

予算の仕組みを知る

正直のこの部分が一番本書で勉強になったポイントかも知れません。

予算は会社を守るためのツール

予算には以下の役割があります。

  • なんの根拠もなく会社の資産を使い込みすぎないガードレール
  • 他の部門(財務や経理)とのコミュニケーションツール

特に財務や経理と行った部門は「会社として生き残るためのお金を確保する」のが仕事なのでこの部門とやり取りするのに予算に関する知識が必要になります。

時間を買えるならお金はかけたほうがいい

楽をするためにお金をかけることは割けるべきですが、お金をかける効用が「時間を節約すること」であるならそれはお金をかけたほうがいい場面が多いです。
なぜなら時間は常に有限なので、時間を短縮できるというのは長い目で見たときに一番いいお金の使い方になるからです。
目先の費用削減等に目を向けがちですが、削減した結果将来的に時間というコストを負うかどうか?は現場で持っておいて損はない観点だなと思います。

資金繰りの話

現場仕事で資金繰りのことを考える機会というのはほとんど存在しないと思いますが、資金繰りは非常に大事です。
※ 資金繰り = 期日までに支払いの原資を調達できること。

資金繰りにおいては「とにかく現金を確保すること」「黒字の信用がなければお金は借りられない」という原則があります。

前者は家計の運営等やっているとわかるポイントかなと思いますし、このために「先払い」をやめて「後払い」を選択する等お金周りのテクニックが存在します(ローンはこう考えると非常に良い仕組みだなと思います。)
後者は自分で事業を立ち上げる、もしくは経営陣に入る、ということをしない限りはほとんど意識することはないと思います。僕もそうです。

一方で巷には黒字を割ける事による節税ハック等が流布していたり、そもそも成長を価値としておくスタートアップ等は赤字であることを許容して成長に投資し続けることが正義だったりもします。
どちらの世界を取るかは企業、ひいては経営者の色の世界なのもしれませんが、経営者でない自分としては黒字にする、及び黒字の幅が大きくと株式市場から評価されない、ということをとある経由でまざまざと痛感しており、つい最近アンラーニングした観点でもありました。
黒字にしないと評価の土俵にも登れない、という世界があり、それが非常に身近なところにあると実感したときに、会社の経営状態(特に B/S や P/L) を見て解釈できるスキルというは必要になるんだなと思いました。
同時に、このルールを知っていると今まで理不尽だなと思っていた制約が別の観点(資本主義の世界等々)では合理的な価値基準なんだなと再認識するきっかけもくれました。

その意味ではこの章におけるお金にまつわる組織力学の走りに触れ、街道度を上げることができたことは自分にとって非常に勝ちがありました。

まとめ

冒頭にも記載しましたが、マネジメントの本かと思いきや組織とお金の話まで及んでおり、かつ自分が最近仕事のやりづらかを感じていたポイントの多くでその背景や前提を言語化してくれていた書籍なので本当に勉強になりましたし、自分の中の解像度が少し上がったような気がします。仕事にはお金がつきものなのでお金に関する知識というのはまだまだつけていきたいと思います。

『マネジメントは嫌いですけど』を読んだ。マネジメントの本かと思ってたけど後半のお金にまつわる組織力学の話がとても勉強になった。 予算管理、資産管理、この辺が多少なり業務に関わってきてたので、実感を持って読めたし、今まで提案がリジェクトされた背景も垣間見ることができた。 組織に関するお金の解像度は少し上がったし、そもそもお金の話をするときは普段現場で使ってるものとは異なるプロトコルで会話する必要がある。『Tidy First?』でもお金(これはオプション取引の話だったけど)の話があったので、今まで考えてこなかった観点を少しは固められたかな?と思うなど。

emahiro (@emahiro.bsky.social) 2025-01-19T02:58:25.575Z
bsky.app

*1:ちょうど マイケルサンデル教授の記事 がバズっていてまさしくこの話だなと思ったりもしました。トピックとして出ている職業は技術職のそれとは違いますが