以前はClaude Code, Codexを使っていたが、今はGoogleに屈してずっとAntigravityを使っている。これは非常に楽で、僕はプログラマとしての死を感じながらも、コードのコミット量だけは増えた。しかし、コードはもう全然読んですらいない。
プラクティスというほどではないが、Tips程度に、個人的にやりながら「ここはこうしたほうがよさそうだ」と思ったことをメモしていく。
作っているものの事例
まず僕がどんなものをつくっているか。僕は実用主義なので、使わないものは作らない。見ればわかるが、極めてニッチなものしかないと思う。
- 仮想通貨の自動トレード
- 自分の資産がリアルに動く。これをAIに書かせて実行できる人は本職でもあまり多くないだろう。一番真剣になれる。真剣になりたいなら命を差し出せ。まぁ命を重すぎるかもしれないから、資本主義社会の命とも言える資産を差し出せ。それができれば本物だ。
- 昔CLIで自作していたロジックを移植してGUIにした感じ。儲かっているかはご想像にお任せ。
- Stable Diffusionサーバ向けプロンプト・キュー管理
- SDでAIイラストを作るための、プロンプト作成支援、編集、LoRAなどの管理、SDに投げるキューの管理など。以前はCLIで自作していたが、AIが一日でGUIにしてくれました。
- AIイラストのビューア
- 非常にシンプルなビューア。わざわざ専用のビューアを作ったのは、「警告なし削除」「フォルダベース」「Webアプリ」を満たすアプリが意外となかったため。AIイラストの精査も兼ねているので警告なし削除が重要だった。また、メタデータの閲覧などもしたかった
- WordPressの記事をNoteに転載する
- APIがないので、Playwrightを起動して無理やりコピペしていく。WordPressの特殊なブロック、またNoteにはない記法(Mermaidとか)に対応する。下書き保存まで。投稿もやろうと思えば自動でできるが、そこは自分でやる
- WordPressのブログ管理
- アイキャッチ画像の生成や、テーマ「SWELL」の簡易PV機能を使い、dailyやmonthlyの差分計算をしてランキング生成、などをしている
- シングルボードコンピュータの操作Web UI
- 非常に特殊だが、RedPitayaという計測機器のスイスアーミーナイフとかいう謎の謳い文句のシングルボードコンピュータ(FPGA搭載)を使っており、コイツをssh越しに操作して物理的に信号を送信・受信したりデータ収集する操作部分をつくった。なおAIにFPGAのコード書かせたら無能の模様
他、作ったけど使わなかったものは更新していない。上記のものはすべて実際に使い続けており、メンテナンスでアップデートを続けている。
大前提
AIは嘘をつく
AI「できました!(できてない)」AI「完璧です!(できてない)」AI「最高にモダンな仕上がりです(クソ)」
AIは嘘をつく。嘘しかつかない。AIに反論できなければならない。
AIはサボる
AI「やりました!(やってない)」AI「あ、それ必要だったんですね!やっておきます!(やってない)」AI「現在稼働中です!(稼働してない)」
AIはサボる。こちらで本当に実行しているのかどうかを見極めなければいけない。
AIはすべてをぶっ壊す
AI「データベース修正しておきました!(完全にまっさら)」AI「……(何も言ってないがデータベースをぶっ壊している)」
AIはカジュアルにすべてを破壊する。破壊されることを常に想定しておかなければならない。
データがすべて
改めて思ったことは、データがすべてだということだ。データさえあればなんとかなる。
もちろんコンバータのような処理・フィルタに特化したアプリもある。しかしその場合でも、設定ファイルなどは存在するだろう。なによりコード自体が既にデータだ。
コード管理は必ず利用し、常に戻せるようにする
エンジニアならばもはや当たり前だが、これからAIでプログラムを始めようという人でも、まずコード管理のやり方は覚えるべきだ。mainブランチ一本打法でいいから、コード管理は必ずする。コード管理はなんでもいいが、LAN内にセルフホストしたGitea/Forgejoを使う人が99%だという噂を風の便りに聞いたことがある。残りの1%はGitLabらしい。
早い段階でバックアップ/復元の仕組みを整える
最初のアプリケーションの骨格を作ったら、早い段階でバックアップの機構をつくる。AIにカジュアルにデータを破壊されてもいつでも戻せるようにする。これはものによっては数分単位でのバックアップと長期的な日単位のバックアップの両方を稼働するような仕組みが必要になることもある(たとえば僕の仮想通貨自動トレードアプリなんかはそうしている)。
作ったらそれで終わりではなく、復元までできることを確認する。復元に必要なすべてのファイルが保存されることを確認する。
コンテナを使うと、コンテナ内のデータをホストマシンにどうバインドするか、またそれを最終的にどう保全するか、考えどころになる。バックアップは基本の3-2-1バックアップ戦略にもとづく。
データベースはSQLiteでよい
僕は自作のアプリではファイルベースを好んだが、それはUNIXのツールとの相性がよく、管理しやすかったからだ。しかしファイルベースには人間が気をつけるべき制約がどうしても増える。かといってデータベース用のコンテナつくるのも大仰だし…。
というところで、SQLiteはちょうどいい。単一ファイルで管理ができるため、先のバックアップとも相性が良い。AIとRDBのACIDは非常に相性がいい。人間がやるとめんどくさいけどAIはめんどくさがらないところがマッチしている。
データベースは自分でも確認する
常にそうしろとは言わないが、データベースの中身は自分でも見るようにする。最初の一回は問題ないのだが、データベース設計に変更が必要になったり、またマイグレーションが発生したときなど、データがおかしくなっていたり、また「フロントエンドで整えてバックエンドは放置」というゴミみたいなことをしていることがある。
AIの嘘を見抜くポイントの一つがデータベース。データは嘘をつかない。データは直接自分でみるほうがいい。
また、データベース設計も、仕様の変更が重なると、以前の仕様に引きずられて冗長になっていたりすることがある。「このデータベース設計はおかしい」という指摘も時には必要になる。
指示を出すうえでの考えどころ、決めどころ
人間と同じで、基本的には自由にやらせたほうがいい。ただここというところは縛る必要がある。具体的には、「自分が使うところ」は縛る必要がある。
言語やライブラリは基本的に任せる
技術的な仕様はできるだけAIに自由にやらせたほうがいい。たとえばAIイラストのビューアでは、Go言語 + htmxを指定したのだが、htmxがマイナーだからか、なんだかhtmxを使っている意味があまりないようなコードになることが多く、結果ひたすら汚くなってしまった感。
まだ「自分でコードみなきゃ」みたいな気持ちがあったので、色々指定してしまったが、結論的にはAIの自由にやらせたがほういい。
機能ではなくユースケースで指示する
なんの機能を追加するかではなく、何がしたいのかを明確にして指示する。結果として、機能レベルの指示になることもあるし、ならないこともある。
これは自分のためにもなっていて、機能ベースで考え始めると、自分しか使わないアプリで自分が使わない機能を作り込んだり、無意味な整備に時間と電気を浪費するようになってしまう。
指示は適当でいいが、決め所は明確にやる
指示は基本的にざっくりでいい。変にあれこれ言うと妙に引っ張られて、変な設計をし始める。
ただし、決め所はちゃんと言ったほうがいい。たとえば僕の事例だと仮想通貨のトレードアプリの、注文・利確のロジック、これは明確に規定した。「絶対にミスれない戦いがそこにある」と思ったらここは完全な言語化と構造化を自らやること。
逆に言うとそれ以外は適当でいい。
ビルド・デプロイは統一する
ビルド、デプロイの方法は統一する。でないと「AIが勝手に起動したプロセス」と「Makefile経由のプロセス」などが縦横無尽にマシン上をかけぬけて、競合しポートを奪い合い意味不明なことになりがち。またMakefileが黒魔術書になりがち。
また、複数アプリをつくっていると、それぞれビルド・デプロイが違うとめんどくせーので、ちゃんと統一したほうがいい。
コンテナ使うかはケースバイケース
ビルドが重たくなるが、OS間の移植性はもちろん、先のAIがなんか知らんがいっぱいプロセス立ち上げて競合問題もあるので、基本的にコンテナを使ったほうがいいと思う。少なくともMacのlaunchd使ってやると、launchd経由と直接起動がぶち当たる事案が何度も発生する。
ただ、やりづらいものもある。また、安定性を考えるならネイティブのほうがいいかもしれないし、またヘッドレスではなくブラウザ操作するようなアプリなんかもコンテナはやりづらい。全体のバックアップも少し難しくなる。
僕の場合だと、仮想通貨のトレードアプリと、WordPressからNoteの転載プログラムは、コンテナを使っていない。
CI/CDはやる
やってない(糞)。
でもやったほうがいい。まだやってないのは、ちょっと家の環境が作りきれていないから。もうちょっとしたらできるので、そしたらやる。
クラウド使えばいい?FF7の話?🤔懐かしいね。
バージョン番号とCHANGELOGをつける
独りでやってると超絶めんどくさいからやらないがちだけど、AIはめんどくさがらずにやってくれるので、バージョン番号と更新履歴をつける。
なにしろ指示するだけなので、「今何をしているのか、これまで何をしてきたか」を忘れがちなんだわ。特に複数アプリ並行でつくってると常に「今なにしてるんだっけ?」になる。
というか、バージョン番号上げないとマジで開発している気にならない。
テストポイントをつくる
テストポイントというか、エラー起きた時に自分で「ここおかしい」って言えるポイントをつくる。AIの「できました!!(できてない)」に明確な反論をできなければいけない。
ログでもいいし、ブラウザ操作ならブレークポイントをつくるでもいい。Webアプリだとデバッグコンソールに何表示させるかにもなる。
WebアプリならいっそWebUI上にメッセージ出力させるとかも、やってみるとエラーメッセージをさくっとコピペできて便利だった。
自分が読めるREADME.mdにする
コードは読まなくてもREADME.mdだけは読む。ここは本当に自分が読めるものにする。プロジェクトの目的、アーキテクチャの全体像、なんの機能があるか、ビルド・デプロイの方法なんかを明確にする。アーキテクチャはMermaidでちゃんと絵にするのが大事。データフローが完全に理解できる形にしよう。
(当面)難しいことはやらない
身も蓋もないが、AIプログラミングにおいて一番重要なことは「難しいことをやらない」だと思う。つまりAIプログラミングでは自室にフィットする棚を作るべきなのであって、安直に家やビルを作ろうとするな、という話だ。そもそも自室にほしいのは棚であって家を突き抜けるビルじゃないはずだ。何がやりたいのかを真剣に考えることが大事。でも何がやりたいのかなんてやってみて初めてわかることだから、とにかくやってみることも大事。
認証・クレデンシャルという地雷
「パスワード」という言葉が出てきたらこれは地雷。取り扱える自信がないなら取り扱ってはいけない。そしてこれができないのであれば、インターネット公開(たとえ自分専用でも)をしてはいけない。逆にいえば、インターネットにあげないのであればかなりハードルが下がる。
それでもAIにクレデンシャルそのまんま読ませないように、とかはあるのだが、ここは厳密にはどうしても最後「信頼するしかない」みたいな面は出てくるように思う。サードパーティでトークンとかないようなやつと連携する、みたいなのになったらそうならざるを得ないんじゃないか。ローカルLLMでやれりゃいいんだが、現状ローカルLLMと商用LLMの差は歴然としているからなぁ。
小さくつくる
境界を超えると急激にAIプログラミングの難度が上がる。
僕の事例で一番わかりやすいのは、シングルボードコンピュータの操作Web UIだ。これは最終的には明確にハードウェアレベルの操作をすることになるのだが、どうもここが絡むとバグりやすい。というか、最終的に自分でオシロスコープをみて確認する必要があり、こうなるとAIにできることは限定的になる。まぁそれでも、Web UIを爆速で作れるだけでめっちゃありがたいんだが。
認証やらが難しくなる理由の一つでもある。境界を超えるんだよな。
フロントエンドもバックエンドも境界だし、この両方を操作するやつはちょっとした改修でもミスが発生しやすい。
これを根本的に防ぐには、なるべく小さく、複数の境界をまたがないようにするほうがいい。たとえば僕がブログ管理の名目で2つのアプリにわかれているのはそういうことでもある。
非機能は割り切る
非機能については必要十分が何かを考えて割り切る。可用性?スケーラビリティ?俺が使いたいときに使えるだけ動けばいいんだ。セキュリティ?公開範囲はLAN内だ。守りを固めるなら玄関に鍵をかけるのが第一だ。
なのでいわゆるSaaS作るぞみたいなのは想定外となる。データベースはSQLiteでいいと言ったが、スケーラビリティだのなんだのいい始めたらそういうわけにもいかない。だが冷静に考えてそんなものいるか?Twitterを作る気なのか?世界征服したいのか?もう2010年代は終わったんだ。夢から覚めろ。全員で同じこの世の宝を探すのはもうやめよう。Think different。汗をかけ。
AIはいつまで使えるかわからない
ある日突然AIが使えない、超高額になる、規制される、は全然ありえる。AIで電気使いすぎて市民は電気使えませんwみたいなコメディすらありえる。そうなってもいいようにする。ローカルLLMでいけるか、いや、もはやAIなしでもメンテできるか。そういう視点は必要。
使える間にたっぷり使おう。
本質は入出力と保存
いろいろ言ってきたが、結局のところやっていることは以下を意識することである。
- 入力はなにか
- 出力はなにか
- どんな処理をするか
- 一時的なデータ、ファイルはなにか
- 永続的なデータ、ファイルはなにか
結局システムなんて全部x->h(x)->yなんだから。
そのうえで、それぞれについて「誰が」「いつ」「どうやって」使えるか、言い換えればアクセスできるかを考えると、自然とそれがセキュリティを考えることになる。
所感
考え方的に、UNIXの思想みたいなんが相性いいのかなと思う。まぁ僕がそういうの好きだけってのもあるけど。逆にデカいサービス作るぞみたいなのはどうなんかね。個人的には、そもそもそんなサービスいる?という気持ちがある。皆がそれぞれ、自分にとって必要なものを作ればいいんじゃないかねぇ。
とりあえず記事を書いて思ったのは、僕は根本的にAIを信用してないんだなと思った。振り返ってプロンプトエンジニアリング的な観点がほぼゼロ。まぁそりゃそうだ。だって何が起きるのかわからんし。どうせすぐ変わるし。ブラックボックスだし、血の通った人間でもない。信用の根拠がない。しかし確かにアウトプットが出てくる。わけのわからん存在だ。わけわからんが、血はないのだから責任はスルーされて自分にかかる。当たり前だ。
巷ではAIの暴走が話題になっているが、AIの暴走に打ち破られるような設計をするほうが悪い。あるいはその覚悟がないのが悪い。別に悪いのが誰だろうとどうでもいいが、困るのは自分だ。
まだまだ色々と考えどころがあるなと思う。実際に使っていきながら、プラクティスになるよう自分なりに積み上げていきたい。
<関連記事>


コメント