tech
技術記事
-
生成AIと作るリアルタイム音声ビジュアライザー (修正編)
はじめに 前回(生成AIと作るリアルタイム音声ビジュアライザー (実装編))では、
実際にCodexにプロンプトを渡して、実機で動作するアプリを作成出来ましたが、
スペクトラムバーの表示に納得行かない部分が発生しました。 今回の記事ではその原因を元に、対応方法を考えCodexに依頼して修正していきます。 前回まとめた原因 FFT(高速フーリエ変換:Fast Fourier Transform)の出力は、
そのまま使用すると非常に変動が大きく、フレームごとに値が大きく上下します。 マイク入力では、 マイク自体のノイズ 空調音 微小な環境音 などもすべて数値として現れるため、
そのまま表示するとスペクトラムが過敏に反応してしまうことがあります。 多くの実装では次のような処理が行われているので、同様の処理をCodexに依頼して修正していきます。 値の平滑化(Smoothing) 微小ノイズの除去(Noise Floor) 表示用の正規化(Normalization) Codexに安定化を依頼する それではCodexに対して表示の安定化を依頼するプロンプトを作成していきます。 ここで重要なのは、AIに対して「全面的な書き直し」を依頼しないことです。 今回のコードはすでに、 マイク入力の取得 FFT解析 SwiftUIによる表示 といった基本構造は正しく動作しています。 そのため、コードをすべて作り直すのではなく、 平滑化の追加 ノイズの抑制 正規化の改善 といった 局所的な修正のみを依頼する方針にします。 AIに修正を依頼する際は、このように 変更範囲を明確に指定することが重要です。 もし「改善してください」とだけ書くと、AIが アーキテクチャを変更する ファイル構成を変える 不要な抽象化を追加する といった大きな変更を行ってしまうことがあります。 今回はそうした事態を避けるため、既存構造を維持したまま表示を安定化させるように依頼します。 修正を依頼したプロンプト 今回Codexには次のような指示を渡しました。 The app builds and runs correctly, and microphone input is being captured. However, the spectrum bars are too unstable and flicker heavily. Please improve the current implementation by: • increasing smoothing for the spectrum values • adding a simple noise floor threshold to suppress very small fluctuations • improving normalization so the bars are visually more stable • aggregating FFT bins into display bars more smoothly if needed Constraints: • keep the current architecture • do not rewrite the whole project • preserve SwiftUI + AVAudioEngine + Accelerate • keep the implementation simple and educational • show focused code changes only • briefly explain why each change improves visual stability 上記のプロンプトでは、次の点を意識しています。 現在の状態を明確に伝える ビルドは成功している 音声入力は取得できている という状態を明示しています。 これにより、AIが不要な部分を作り直す可能性を減らします。 修正内容を具体的に指定する 今回の問題に対して必要な処理は、主に次の3つです。 平滑化(Smoothing) ノイズ除去(Noise Floor) 正規化(Normalization) この3点を明確に指定することで、AIが意図した方向に修正を行いやすくなります。 変更範囲を制限する 特に重要なのが次の部分です。 keep the current architecture do not rewrite the whole project AIに対してこの制約を入れておかないと、既存コードを大きく変更してしまうことがあります。
今回は 安定化だけを行うことが目的なので、アーキテクチャは維持するように指示しています。 修正後の動作確認 Codexによる修正を適用したあと、再度ビルドと動作確認を行いました。 結果として、ビルドは引き続き成功し、アプリの基本機能も問題なく動作しています。 ビルド結果:BUILD SUCCEEDED アプリ起動:正常 マイク入力:正常に取得 スペクトラム表示:安定化 修正前の状態では、スペクトラムバーがフレームごとに激しく揺れてしまい、
無音に近い状態でも細かい変動が発生していました。 しかし今回の修正によって、 バーの動きが滑らかになった 無音時の微小な揺れがほぼ消えた 音量の変化に対する反応が自然になった といった改善が確認できました。 特に効果が大きかったのは、次の処理です。 上昇・下降で異なる係数を使う時間的平滑化 ノイズフロアによる微小入力の抑制 動的正規化によるスケールの安定化 FFTビンの平均化と空間的平滑化 これらの処理により、
スペクトラム表示はリアルタイム音声ビジュアライザーとして十分に安定した挙動になりました。 初回生成のコードでも基本機能は成立していましたが、
今回の調整によって 実際に見やすいスペクトラム表示 に近づいた形になります。 しかし、自分の環境ではまだ雑音が入っているのか左側のバーが常に動いているため
更に修正を加えます。 追加調整:環境ノイズへの対策 前節の修正により、スペクトラム表示はかなり安定しました。
バーの動きも滑らかになり、無音時の微小な揺れも大幅に減っています。 しかし実際にアプリを動かしてみると、
完全な無音状態でもわずかにバーが反応することが確認できました。 これはバグというより、音声入力を扱うアプリではよくある現象です。 マイク入力には、 マイク自体のノイズ 空調やPCファンなどの環境音 A/D変換時の量子化ノイズ などが含まれるため、完全なゼロ値になることはほとんどありません。 そのため、FFT解析を行うと
人間には聞こえないレベルのノイズでもスペクトラムに現れることがあります。 今回の実装でも、ノイズフロアを導入していましたが、
実機環境ではまだわずかな変動が残っていました。 そこで追加の対策として、 ノイズフロアを少し引き上げる 低レベル入力をより強く抑制する という調整を行いました。 ノイズフロアの調整 修正前は次の値を使用していました。 noiseFloorDb = -62 この値をやや高めに設定することで、環境ノイズの影響をさらに抑えることができます。 例えば次のように調整します。 noiseFloorDb = -25 この変更により、 小さすぎる入力はスペクトラムに表示されない 無音時のバーの揺れがほぼ消える という効果が得られました。 実装で重要なポイント 音声ビジュアライザーでは、解析結果の正確さよりも視覚的な安定性が重要になる場合があります。 そのため多くの実装では、 ノイズフロア 平滑化 正規化 バンド平均化 といった処理を組み合わせて、見やすいスペクトラム表示を作っています。 追加調整:ノイズフロア変更による副作用 前節では環境ノイズの影響を減らすためにノイズフロアを引き上げました。
実機環境でテストした結果、ノイズフロアを -12 dB に設定すると、
ほとんどの環境ノイズを抑えることができました。 この変更により次の改善が確認できました。 無音状態でのバーの揺れがほぼ消える PCファンや空調などの微小ノイズを拾わない スペクトラム表示がより安定する 音声解析では、FFTによって音声を周波数成分に分解しますが、
マイク入力には必ず微小な環境ノイズが含まれます。
これらのノイズは周波数領域でも小さな揺らぎとして現れるため、
可視化では微小なバーの動きとして表示されることがあります。 このような問題を防ぐため、一定以下のレベルを無視する ノイズフロア処理 を導入しました。 発生した問題 しかし、この調整には副作用がありました。 ノイズフロアを高く設定したことで、スペクトラム表示に次の変化が現れました。 バーが全体的に高い位置に集中する 周波数ごとの差が小さくなる スペクトラムの形状が分かりにくくなる つまり、ノイズは抑えられたものの、
スペクトラムのダイナミックレンジが圧縮されてしまった状態です。 今回の実装では、FFT結果をデシベル値へ変換し、
その値を一定の範囲で正規化してバーの高さへ変換しています。 ノイズフロアを大きく変更すると、 最小値が上がる 正規化範囲が狭くなる 全体の値が上側へ寄る という現象が発生します。 その結果、スペクトラムバーが 高い位置でまとまる表示 になってしまいました。 対応方針 この問題を解決するため、次の調整を行うことにしました。 正規化レンジの再調整 ノイズフロア適用後のスケーリング改善 スペクトラム分布を自然にする補正 つまり ノイズは抑える スペクトラムの形状は維持する というバランスを取る形です。 Codexへの修正依頼 この調整はアルゴリズムの細かい部分に関係するため、
既存のコード構造を維持したまま 局所的な修正 をCodexへ依頼しました。 実際に渡したプロンプトは次の通りです。 The app runs correctly and the noise floor adjustment successfully suppresses ambient noise. However, after setting the noise floor to -12 dB, the spectrum bars tend to cluster at high positions and the spectral shape becomes less distinguishable. Please improve the normalization and scaling so that: - the bars use a wider dynamic range - spectral differences between frequency bands remain visible - the spectrum does not collapse into a narrow high-level band Constraints: - keep the current architecture - preserve SwiftUI + AVAudioEngine + Accelerate - do not rewrite the project - adjust normalization or scaling logic only - keep the implementation simple and suitable for educational purposes Briefly explain the reasoning behind the changes. AIとの反復改善 今回のケースは、AIを使った開発の特徴がよく表れている例です。 初回生成では 音声入力 FFT解析 スペクトラム表示 といった基本機能は問題なく実装されていました。 しかし実際にアプリを動かしてみると、 ノイズ抑制 正規化のバランス 視覚的な分かりやすさ といった 体験品質に関わる部分は、細かな調整が必要でした。 そのため今回の開発では AIが土台を生成する
↓
実機で挙動を確認する
↓
問題を整理する
↓
AIに局所的修正を依頼する という反復プロセスで改善を進めています。 まとめ 今回は SwiftUI・AVAudioEngine・Accelerate を使った
リアルタイム音声ビジュアライザーのサンプルアプリを、Codexと協力して作成しました。 開発の流れを振り返ると、次のようなステップで進んでいます。 SwiftUIプロジェクトを作成 マイク権限を設定 Codexに実装を依頼 初回生成コードをビルドして動作確認 スペクトラム表示の不安定さを修正 ノイズフロアを導入して環境ノイズを抑制 正規化やスケーリングを調整して表示品質を改善 初回生成の段階でも、Codexは 音声入力の取得 FFTによる周波数解析 SwiftUIによるスペクトラム表示 といった基本機能を正しく実装していました。 しかし実際にアプリを動かしてみると、 バーの揺れ 環境ノイズの影響 正規化による表示バランス など、動作品質に関する細かな問題が見えてきます。 今回の開発では、 AIが土台を生成する
↓
人間が実機で挙動を確認する
↓
問題点を整理する
↓
AIに局所的な修正を依頼する という 反復的な開発プロセスで改善を進めました。 これは実際の開発でもよく見られるスタイルで、
AIを「自動コード生成ツール」として使うというよりも、 設計や問題分析を人間が行い、実装の補助をAIに任せる という役割分担で作業を進めるものです。 昨今、すべてをAIAgentに任せて最終製品を作れるという記事は増えていますが、
結局の所、最終的な製品の調整は人間が担う事になります。 その時、どういった制限をプロンプトにいれながら進めれば破綻しないのか、
といった部分の理解の一助になれば幸いです。 参考記事 生成AIと作るリアルタイム音声ビジュアライザー (準備編)
生成AIと作るリアルタイム音声ビジュアライザー (実装編) -
生成AIと作るリアルタイム音声ビジュアライザー (実装編)
はじめに 前回(生成AIと作るリアルタイム音声ビジュアライザー (準備編))では、
実装を行うための環境構築を行いました。
この記事では、実際にCodexに渡したプロンプトの説明を行いつつ、
実際に生成されたコードを動かし、修正を行っていきます。 Codexに渡すプロンプト ここからは、実際に Codexへどのような指示を出したか を整理していきます。 今回のようにAIを使用して作成するアプリでは、最初のプロンプト設計がかなり重要です。
理由は、AIに対して曖昧な依頼をすると、 不要に複雑な構成になる UIKitベースの実装が混ざる FFTまわりが雑になる 動いても記事にしづらいコードになる といった問題が起きやすいためです。
そのため今回は、最初から役割と制約を明示したプロンプト を使用します。
おまけ:
実際の開発や継続的なメンテナンスにおいてはAGENTS.mdに主要なルールを記載し、
プロジェクト特有のルールを mdファイルとして配下のディレクトリに設置するなどします。
興味があればハーネスエンジニアリング(Harness Engineering)で調べてみてください。
(この言葉は元々違う分野で一般的に使用される言葉でしたが、
2026年段階で主にAIAgent系の記事で頻出するようになってきています。) 今回のプロンプトで意識したこと 今回Codexに依頼するにあたって、特に意識したポイントは次の通りです。 「まず動くもの」を優先する 最初から理想的な設計を求めるのではなく、
まずは 小さくても動くサンプル を作ることを優先します。 音声処理まわりは、設計をきれいにしようとすると一気に複雑になりやすいため、
初回はあくまで マイク入力が取れる スペクトラムが表示される SwiftUIで動く という最低限の成立を目標にします。 過剰な抽象化を避ける AIは放っておくと、 Protocol Manager Coordinator Utility層 のようなものを増やしがちです。 もちろん実務では有効な場合もありますが、今回の記事の目的は 学習用サンプルを作ること です。 そのため、 ファイル数は少なめ 責務は分かれている ただし過剰設計はしない というバランスを狙います。 SwiftUI / AVAudioEngine / Accelerate を明示する 今回の技術スタックは最初から決めています。 UIは SwiftUI 音声入力は AVAudioEngine 解析は Accelerate / vDSP このあたりを曖昧にすると、AIが別の実装方式を混ぜてくることがあります。 特に音声系では、 AVAudioRecorder AudioKit風の構成 UIKitベースのView 必要以上に複雑なDSP処理 などに寄ってしまう可能性があるため、使う技術は明確に指定しておきます。 記事向けの読みやすさを重視する 今回作りたいのは「製品コード」ではなく、
技術記事の中で解説しやすいサンプルコード です。 そのため、プロンプトの中でも 小さい構成にする 読みやすい命名にする コメントを適度に入れる デバッグしやすい構造にする といった点を明示しています。 実際に渡したプロンプト 以下のような意図を踏まえたうえで、Codexには次のような依頼を行いました。
(プロンプトは英語に翻訳したうえで投入しています) Create a small but working iOS sample app using SwiftUI that visualizes live microphone input in real time. Goal: - Build a technical sample app for a blog article - Keep the code easy to read and easy to debug - Prioritize a simple working implementation over advanced architecture Tech requirements: - SwiftUI for UI - AVAudioEngine for microphone capture - Accelerate / vDSP for FFT or frequency-domain magnitude analysis - iOS 17+ - Swift - No third-party libraries - No UIKit App behavior: - Request microphone permission - Capture live microphone input - Analyze the input continuously - Display a real-time spectrum visualizer using vertical bars - Use a reasonable number of bars such as 32 or 48 - Normalize the values so the bars look visually stable - Add light smoothing to reduce flicker Architecture: - AudioAnalyzer: ObservableObject responsible for AVAudioEngine setup, audio tap, FFT, normalization, smoothing, and publishing spectrum data - SpectrumBarView: SwiftUI view that renders the bar graph - ContentView: owns AudioAnalyzer with @StateObject and starts/stops audio analysis - App entry point Implementation constraints: - Keep the project intentionally small - Avoid unnecessary protocols, managers, coordinators, or excessive abstraction - Prefer beginner-friendly naming - Add concise comments around important learning points - Publish UI updates on the main thread - Avoid expensive work on the main thread when possible - Keep the code structured for a technical article Deliverables: 1. Full source code for all files 2. File structure 3. Notes for Info.plist microphone permission key 4. Short explanation of key implementation decisions 5. Mention likely pitfalls Important: - The output must be real compilable Swift code - Do not use placeholder pseudocode - Do not over-engineer - Make the first version easy to iterate on after bugs are found このプロンプトで狙ったこと このプロンプトでは、単に「音声ビジュアライザーを作って」と依頼するのではなく、
次の点を最初から固定しています。 SwiftUIで作る AVAudioEngineを使う FFTはAccelerate系で行う 表示はバーグラフ形式にする 32〜48本程度の見やすい本数にする 正規化と平滑化を入れる 小さく読みやすい構成にする 特に重要なのは、最初から「小さく・動く・読みやすい」ことを優先している点です。 音声処理のような題材では、AIに自由度を与えすぎると
「一見すごそうに見えるが、実際には直しにくいコード」が出てくることがあります。 今回は技術記事化も前提にしているため、
完成度よりもまず 反復しやすさ を重視しました。 ここでのゴール この段階でのゴールは、完成品を一発で得ることではありません。 まず動く最初の版を出してもらう Xcodeでビルドする エラーや不具合を確認する 必要な修正を再度依頼する という流れを前提にしています。 今回のCodexの使い方は 一発生成型ではなく、反復改善型の使い方 です。 この方が実際の開発にも近く、記事としても再現しやすい構成になります。 実際になげてみる しばらく待ってみると以下のように ファイルが生成されます 更に実機でデバッグ実行してみる 特にエラーが起きることもなく以下のような画面が表示されます。 出力されたアプリの状況 何も手を加える事なく起動し、音声も取れていますが、常に左側のバーが高い状態のため、
ノイズをそのまま出力してる状態の様に見えます。 今の状態をまとめると ビルドOK 起動OK マイク入力OK ただし表示が期待どおりでない。 なので、ビルドエラーなどの対処はありませんでしたが、修正したい部分があったので、
「表示安定化」 を考えた上で修正を行っていきます。 考えられる原因 この現象の原因は、FFT(高速フーリエ変換:Fast Fourier Transform)結果の扱い方にありそうです。 FFTの出力は、そのまま使用すると非常に変動が大きく、
フレームごとに値が大きく上下します。 特にマイク入力では、 マイク自体のノイズ 空調音 微小な環境音 などもすべて数値として現れます。 そのため、FFTの値をそのまま表示するとスペクトラムが過敏に反応してしまうことがあります。 音声ビジュアライザーでは、解析の正確さだけでなく視覚的な安定性も重要になります。 そのため多くの実装では次のような処理が行われます。 値の平滑化(Smoothing) 微小ノイズの除去(Noise Floor) 表示用の正規化(Normalization) ここまでのまとめ 実際にAIに生成してもらったコードで、基本的な機能は実装できていましたが、
表示に不満が発生し、何が原因なのかを考えました。 この原因となる部分に関しては、
世間にあるアプリを見ても各社さまざまな調整がされており差が発生している部分であり、
こういった部分が人間が考慮したうえで調整を行う必要があります。 次回はこの問題をCodexに依頼することで修正していきます。 参考記事 生成AIと作るリアルタイム音声ビジュアライザー (準備編) -
生成AIと作るリアルタイム音声ビジュアライザー (準備編)
はじめに CoreAudioまわりのサンプルは、理解しようとすると少しハードルが高い領域です。
今回は題材として リアルタイム音声ビジュアライザー を選び、AIコーディングツール Codex を使って SwiftUI ベースのサンプルアプリを作ってみます。 この記事では、 SwiftUI AVAudioEngine Accelerate (FFT) Codex を使いながら、AIとペアプロする形でサンプルアプリを完成させていく過程をまとめます。 なお、最初から完成コードを出すのではなく、 AIに実装を依頼する ビルドエラーや挙動の問題を修正する 最終的に動くサンプルへ育てていく という流れで進めます。 今回はまず Codexに指示を出す前の準備までを扱います。 作るアプリ 今回作るアプリはシンプルです。 マイク入力の音をリアルタイムで解析し、周波数スペクトラムを表示するアプリです。 次のような構造で動作します。 Microphone
↓
AVAudioEngine
↓
Audio Buffer
↓
FFT(Accelerate / vDSP)
↓
Spectrum Data
↓
SwiftUI View 表示は以下のようなイメージになります。 █ ▇ ▅ ▃ ▄ ▆ █ ▇ ▅ ▃ ▄ ▆ █ なぜSwiftUIを使うのか 今回は UIKit ではなく SwiftUI を使用します。 理由は主に2つです。 UIコードを短くできる 音声ビジュアライザーの主役は 音声処理(Audio Processing) です。
UIKitを使うと、どうしても次のような実装が必要になります。 AutoLayout CALayer drawRect View更新管理 結果として UIコードの比率が大きくなり、本筋の音声処理から離れてしまうことを避けるためです。 SwiftUIなら、スペクトラム表示も非常にシンプルに書けます。 例えば、HStack の中で Rectangle を並べるだけでバー表示のベースを作ることができます。 HStack で横方向に配置 ForEach でスペクトラムデータをループ Rectangle でバーを描画 このように 少ないコード量でリアルタイムグラフの基礎が作れるため、今回はSwiftUIを使用します。 AI生成コードとの相性が良い 今回の記事では AIを使用して音声処理アプリを実装する をテーマにしています。 SwiftUIは宣言的UI(Declarative UI)のため、 UIKit AutoLayout CALayer操作 などと比較して AIが生成するコードの成功率が高い傾向があります。 特に次の点で相性が良いと感じています。 View構造がシンプル 状態管理が明確 UI更新がデータバインディング中心 UIKitの場合、AIが生成したコードでは次のような問題が起きることがあります。 AutoLayout制約が崩れる View更新のタイミングが不適切 CALayer描画処理が複雑になる 一方SwiftUIでは、UIの更新は基本的に 状態の変化によって自動的に反映されます。 そのため、 データ(スペクトラム配列)を更新する SwiftUIが自動で画面を更新する というシンプルな構造になります。 今回のサンプルでも、 マイク入力を取得する FFTでスペクトラムデータを作る 配列を更新する SwiftUIがグラフを再描画する という 非常に素直なデータフローを作ることができます。 結果として、AIが生成したコードをそのまま動かせる確率が高くなるため、
手動による修正や追加実装のコストを下げる事にも有用です。 プロジェクト作成 まずは XcodeでSwiftUIプロジェクトを作成します。 メニューから次を選択します。 File → New Project → App プロジェクト設定は以下のようにします。 Product Name : LiveAudioVisualizer Interface : SwiftUI Language : Swift Deployment : iOS 17+ プロジェクトを作成すると、最小構成のSwiftUIアプリが生成されます。 LiveAudioVisualizer ├ LiveAudioVisualizerApp.swift └ ContentView.swift この段階では、まだ音声処理のコードは存在していません。 マイク権限の設定 iOSでマイクを使用するアプリでは、
Info.plistに使用理由を記述する必要があります。 この設定が無い場合、アプリはマイクにアクセスできません。 SwiftUIテンプレートの場合、Info.plist がファイルとして見えないことがあります。
その場合は Target設定のInfoタブから追加します。 TARGETS → LiveAudioVisualizer → Info 追加するキーはこちらです。 Privacy - Microphone Usage Description 値は例えば次のようにします。 Microphone access is required for audio visualization. この文章は、ユーザーが初めてマイクアクセスを許可する際に表示されるメッセージになります。 まとめ 今回は、リアルタイム音声ビジュアライザーを作るための 準備段階として、 SwiftUIを採用した理由 Xcodeでのプロジェクト作成 マイク権限の設定 までを行いました。 この段階ではまだアプリとしての機能はほとんどありませんが、
音声入力を扱うiOSアプリの土台は整った状態になります。 次のステップでは、いよいよ AI(今回はCodex)に実装を依頼します。 具体的には、 マイク入力の取得(AVAudioEngine) 音声データの解析(Accelerate / FFT) スペクトラムデータの生成 SwiftUIでのリアルタイム表示 といった部分を、AIと協業する形で実装していきます。 また、AIが生成したコードは必ずしもそのまま動くとは限らないため、 ビルドエラーの修正 動作の調整 表示の安定化 といった作業も含めて、実際の開発フローに近い形で進めていきます。 次回は、Codexに渡した 実際のプロンプト と、
そこから生成されたコードを見ながら、実装を進めていきます。 -
Tomcat が2週間でフリーズする問題を解決した話
はじめに Spring Boot + Spring Data JPA で構築したバッチ処理が、テストフェーズ(ロングランテスト)で約2週間稼働させると Tomcat がフリーズするという問題に遭遇しました。 調査した結果、IN 句を使ったクエリが原因でメモリを圧迫していることがわかり、Hibernate の設定を1つ追加することで改善しました。同じような問題で困っている方の参考になればと思います。 環境 項目バージョン / 構成Java8Spring Boot2.7.4Spring Data JPA2.7.3サーバーAWS EC2 (Amazon Linux 2)AP サーバーTomcatDBAWS Aurora MySQL 発生した問題 症状 バッチ処理を開発環境で稼働させていると、約2週間で Tomcat がフリーズする フリーズ後はバッチ処理が動かなくなる Tomcat を再起動すると復旧するが、また2週間程度で同じ現象が発生 症状をもとにした仮説 徐々にメモリリークしていき、最終的にヒープメモリが枯渇してフリーズしたものと考えられました。 試したこと メモリリークが原因という仮説を立てたものの、具体的なメモリリーク発生個所の特定がなかなかできませんでした。 処理の見直し:不要なオブジェクトを保持していないか、ループ内でのオブジェクト生成を減らせないかなど確認 EC2 のスペック変更:メモリを増やして様子を見たが、フリーズするまでの時間が延びただけで根本解決にはならず GC のチューニング:ヒープサイズやGCの設定を調整したが改善せず いろいろ試しても解決しなかったため、ウェブ検索で情報を探しました。「Spring Boot メモリリーク」「Tomcat フリーズ 原因」など検索キーワードを変えながら調べ続けて、ようやく IN 句のパラメータ数が原因になりうるという情報にたどり着きました。 原因 調査の結果、IN 句を含むクエリの種類が多すぎることが原因でした。 何が起きていたか バッチ処理で Spring Data JPA の findByIdIn() のようなメソッドを使っていました。 // 例:IN句のサイズが毎回異なる List<Entity> result1 = repository.findByIdIn(List.of(1, 2, 3)); // 3個 List<Entity> result2 = repository.findByIdIn(List.of(1, 2, 3, 4)); // 4個 List<Entity> result3 = repository.findByIdIn(List.of(1, 2, 3, 4, 5)); // 5個 このとき、IN 句に渡すリストのサイズが毎回異なると、サイズごとに別の SQL 文として扱われます。 -- 3個の場合 SELECT * FROM entity WHERE id IN (?, ?, ?) -- 4個の場合 SELECT * FROM entity WHERE id IN (?, ?, ?, ?) -- 5個の場合 SELECT * FROM entity WHERE id IN (?, ?, ?, ?, ?) Hibernate はクエリごとにパース結果をメモリ上に保持します。IN 句のサイズが 1〜1000 まで変動するような処理だと、1000種類のクエリがメモリに溜まっていくことになります。 今回のバッチ処理では IN 句に渡す件数がバラバラだったため、これが積み重なってメモリを圧迫していました。 解決策 in_clause_parameter_padding を有効にする Hibernate には、IN 句のパラメータ数を揃えてくれるオプションがあります。 application.properties に追加 spring.jpa.properties.hibernate.query.in_clause_parameter_padding=true このオプションの動き IN 句のパラメータ数を、次の切りのいい数に揃えてくれます。 実際のパラメータ数揃えた後1〜223〜445〜889〜161617〜3232 たとえば、3件渡すと4件用の SQL になり、5件渡すと8件用の SQL になります。足りない分は同じ値で埋めてくれます。 このようにすることで、パラメータ数がバラバラでも生成される SQL の種類が限定され、メモリの消費を抑えられます。 結果 この設定を追加した後、2週間以上稼働させても Tomcat がフリーズしなくなりました。 コードの修正は不要で、設定ファイルに1行追加するだけで解決できたのは助かりました。 注意点 このオプションは Hibernate 5.2.18 以降で使えます 足りないパラメータは同じ値で埋めてくれるので、SQL のログを見ると少し違和感があるかもしれません 適用前後でクエリの実行結果が変わることはありません まとめ Spring Data JPA で IN 句を使う処理が多いと、クエリの種類が増えてメモリを圧迫することがあります in_clause_parameter_padding=true を設定すると、クエリの種類を減らせます 設定1行で改善できるので、似たような症状が出たら試してみてください 参考 https://www.baeldung.com/java-hibernate-in-clause-padding https://vladmihalcea.com/improve-statement-caching-efficiency-in-clause-parameter-padding/
-
Claude Code を初めて使って C# WebAPI を 0 から 100 まで構築した話
はじめに Claude Code を使って、C# の WebAPI をイチから構築しました。初めての利用だったので試行錯誤もありましたが、最終的には想像以上のスピードで実装が完了しました。 その過程で感じたこと、うまくいったこと、つまずいたことをまとめておきます。 前提条件 今回の開発にあたって、私自身の状況を書いておきます。 普段は Java を使っていて、C# はほぼ触ったことがない C# での WebAPI 実装経験がない(Java での WebAPI は十分に経験あり) C# にどんなライブラリがあるかも知らない もし自分でイチから実装しようとしていたら、
まず C# の基本文法から学び、
ASP.NET Core の仕組みを理解し、
Entity Framework Core などのライブラリの使い方を調べ…
と、かなりの学習コストがかかっていたはずです。 今回は Claude Code にほぼすべてを任せる形で進めたため、この学習コストをほとんどスキップできました。
もちろん生成されたコードを理解する必要はありますが、ゼロから学ぶのと動くコードを読みながら学ぶのでは、効率が全く違いました。 最初につまずいたこと リミットにすぐ到達 Claude Code の扱いに慣れていなかったため、最初は抽象的な指示を出してしまうことが多かったです。 // 悪い例 「いい感じに API を作って」 「DB 周りをよしなにやって」 このような指示だと Claude Code が何度も確認や提案を繰り返すため、あっという間にリミットに達してしまい、5時間間隔のリセットまで使えない状態が何度かありました。 具体的に何をしてほしいかを明確に伝えること=プロンプトの書き方=が大事だと学びました。 実装の進め方 以下の流れで実装を進めました。 1. Excel の DB 定義書を読み込ませる まず Claude Code に Excel 形式の DB 定義書を読み込ませました。 Claude Code は読み込み用の Python プログラムを自分で作成し、定義書の内容を解析してくれました。ただ、完璧ではありませんでした。 背景色で「無効」を表現している箇所が読み取れない セル結合があると構造がうまく解釈されない こういった部分は人間の手で補足・調整が必要でした。Excel の読み込みはそこまでスムーズではなかったです。 2. API Blueprint で作成された API 仕様書を読み込ませる API 仕様書はチームメンバーが API Blueprint 形式で作成していました。 仕様書には API ごとに DB のどのテーブルを使うかが記載されていたので、Claude Code はこれを参照しながらスムーズに実装を進めてくれました。 3. 仕様書・定義書に基づいて実装 DB 定義書と API 仕様書の両方を読み込ませた状態で、実装を指示しました。 ○○ API を実装して。 DB 定義書の △△ テーブルを使って、API 仕様書の通りに作って。 このように具体的に指示すると、期待通りのコードを生成してくれました。 うまくいったこと CLAUDE.md の活用 事前に CLAUDE.md に C# のベーシックなコーディング規約を記載しておきました。 命名規則 ディレクトリ構成 基本的なコーディングスタイル これにより、生成されるコードが最初から規約に沿った形になり、後からの修正が少なくて済みました。 DB アクセス方式の切り替え 当初、Claude Code は古い方式で DB とのやり取りを実装していました。新しい方式に切り替えたいと指示したところ、スムーズに対応してくれました。 DB アクセスを Entity Framework Core を使った方式に変更して。 既存の実装をすべて書き換えて。 Docker 環境の構築 DB コンテナやローカル実行環境の構築も、こちらの要望を伝えるだけで Claude Code がすべて用意してくれました。 docker-compose.yml の作成 初期データ投入用のスクリプト ローカル実行用の設定ファイル リファクタリング 実装が一通り完了した後、リファクタリングも依頼しました。 実装内容を確認して、処理の共通化や最適化を行って。 指示した通りに、重複コードの共通化や不要な処理の削除を行ってくれました。 仕様変更への対応 開発中は度重なる仕様変更がありましたが、以下のような簡単なプロンプトで対応してくれました。 ○○ API の △△ の処理を □□ に修正して。 修正後は、処理分岐パターンを網羅したテストを実施して。 人間では到底追いつけないスピードで実装してくれました。 人間がやったこと Claude Code に実装を任せることで、人間は以下の作業に時間をかけることができました。 コードレビュー:生成されたコードが仕様通りか、セキュリティ上の問題がないかを確認 テスト:実際に動かして期待通りの動作をするかを検証 仕様の判断:曖昧な部分の仕様を決定し、Claude Code に伝える 実装作業そのものはほぼ Claude Code に任せ、人間は確認と判断に集中する形になりました。 感じたこと 今回初めて 0 から 100 まで Claude Code に作業してもらいました。 率直に言って、もう人間がプログラミングする機会は劇的に減っていくだろうと感じました。
近い将来、コードを書くこと自体がなくなるかもしれません。 便利でとても楽ではあるのですが、正直なところ少し寂しい気持ちもあります。
プログラミングが好きで始めた仕事なので、複雑な気持ちになりました。 ただ、だからこそ「何を作るか」「どう設計するか」「品質をどう担保するか」という上流の部分が、これまで以上に重要になってくるのだと思います。 まとめ Claude Code を使えば、WebAPI の実装を大幅に効率化できます 抽象的な指示ではなく、具体的に伝えることが大事 CLAUDE.md に規約を書いておくとスムーズ Excel の読み込みなど、完璧ではない部分もある 人間はコードレビューとテスト、仕様判断に集中できる プログラミングの在り方が変わっていくことを実感しました