<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>PWA on Off-Grid</title><link>https://offgrid.taikiito.com/tags/pwa/</link><description>Recent content in PWA on Off-Grid</description><generator>Hugo</generator><language>ja-JP</language><lastBuildDate>Mon, 05 Oct 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://offgrid.taikiito.com/tags/pwa/index.xml" rel="self" type="application/rss+xml"/><item><title>AIにアプリを書かせて6週間、効いた習慣と効かなかったやり方</title><link>https://offgrid.taikiito.com/guides/building-with-an-ai-agent/</link><pubDate>Mon, 05 Oct 2026 00:00:00 +0000</pubDate><guid>https://offgrid.taikiito.com/guides/building-with-an-ai-agent/</guid><description>プログラムを書けない自分が、AIのコーディングエージェントに指示するだけで毎日使うチャット＋カレンダーのアプリを作り、6週間運用した記録。同じ不具合を9回踏んだ話、直したものが端末に届いていなかった話、スクショを実測しないと色も丸みも合わない話。効いた習慣を5つに絞って書いた。</description><content:encoded><![CDATA[<p>自分はプログラムを書けない。それでも、スマートフォンのブラウザで動くチャット＋カレンダーのアプリを作って、6週間ほど毎日使っている。コードは全部AIのコーディングエージェント(指示を出すと実際にファイルを書き換えて動かすAI)に書かせた。</p>
<p>利用者は自分と、自分以外にもう1人、実際に毎日使っている利用者の2人だけ。この1人が実機で不具合を見つけて報告してくるので、6週間のあいだ「作る」より「直す」のほうがはるかに多かった。そこで身についた習慣を5つだけ書く。どれも、外した回数の記録があるものに限った。</p>
<h2 id="前提">前提</h2>
<p>スマートフォンのホーム画面に置いて全画面で使う形式(PWA)のアプリで、iPhoneとAndroidの両方から使っている。置き場所は自分の借りているサーバーで、土台は<a href="/guides/self-hosting-basics/">自分の「サーバー」を持つとはどういうことか</a>に書いた構成とほぼ同じ。自分がやるのは、不具合の報告を受け取り、エージェントに状況を伝え、出てきた直しを実機で確かめること。コードは読めるが書けない。</p>
<h2 id="1-推測で直すのをやめ端末が実際に報告していることを出す捨て用のページを作る">1. 推測で直すのをやめ、端末が実際に報告していることを出す「捨て用のページ」を作る</h2>
<p>一番高くついたのは、日本語入力の変換候補の帯が消える不具合だった。ひらがなを打ってもキーボードの上に出るはずの候補バーが出ない、または打っている途中で消える。<strong>同じ症状を、数日かけて9回踏んだ。原因は毎回違っていた。</strong> 正確に言うと、同じ作りで動かしている自作アプリが2つあり、9回はその両方にまたがっている。同じ型の作りには同じ型の地雷が埋まる、ということでもある。</p>
<ol>
<li>画面のスクロール位置を0に引き戻す1行。変換を始めるとiOSがページを少しスクロールさせる。それを律儀に戻していたので、組み立て中のiOSが変換を打ち切っていた。</li>
<li>入力のたびに入力欄の高さを測り直す処理。<strong>iOSのIME(日本語入力の仕組み)は、組み立て中に入力欄の寸法を書き換えられると組み立てを打ち切る</strong>。</li>
<li>自分宛ての通知バナー。相手の発言が届いたときに通知を出していたが、<strong>自分がアプリを開いて返信を打っている最中にも出ていた</strong>。</li>
<li>自分が保険として足した自動リロード。「新しい版を配ったら画面を読み込み直す」仕掛けが、打っている最中でも容赦なく走っていた。つまり<strong>直しを配るたびに、自分で同じ症状を起こしていた</strong>。</li>
<li>「いま変換中か」の旗を時間切れで降ろす保険。「人が3秒も1文字も触らずに組み立て続けることはない」という前提だったが、<strong>人は言い回しを考えて平気で3秒以上止まる</strong>。止まった瞬間に旗が降り、高さが書き換えられて候補が消えた。1〜4回目を防ぐために足した保険が、1〜4回目と同じ事故を起こしていた。</li>
<li>入力欄に付けていた「自動スペル修正を切る」属性。iOSではこれが<strong>キーボード上の予測候補バーそのものを消す</strong>。日本語の変換候補はそのバーに出るので、英語の下線を消すついでに道連れにしていた。</li>
</ol>
<p>🔴 <strong>9回のうち7回は「ありそうな犯人」を潰していただけだった。</strong> 毎回それらしい原因が見つかり、毎回直って、毎回また同じ報告が来た。</p>
<p>決着したのは、直すのをやめて<strong>実況を出す仕掛け</strong>を入れてからだった。画面の左上に最後の十数行を出して、「組み立てが始まった」「入力が来た」「高さ調整を見送った」「表示領域の高さが変わった」を1行ずつ流す。これのスクショを1枚もらっただけで、<strong>自分のコードは変換中に画面を一切書き換えていない</strong>ことが確定し、残っていた仮説が全部消えた。</p>
<p>さらに<strong>捨て用のページ</strong>を別に作った。入力欄が1つあるだけで、JavaScriptを一切かけず、属性の組み合わせを6通り切り替えられるページ。実機で6通り全部試して全部で候補が出た。これで「入力欄の属性」「固定の箱」「OSの予測変換の設定」「ホーム画面アプリであること自体」が全部シロだと分かり、残りは本番のコードだけに絞れた。</p>
<p>この手で学んだこと。</p>
<ul>
<li><strong>調べる口は、症状が出る環境の中から開けられるようにする。</strong> 最初の実況はURLの末尾に印を付けて開く方式だったが、症状が出るのはホーム画面アプリで、そこにURL欄はない。報告をもらって初めて「一生使えない仕掛け」だと気づき、設定画面に切り替えを置き直した。</li>
<li>🔴 <strong>捨て用ページで測った数字を、本番の数字より優先してはいけない。</strong> 入力欄の下に空ける余白をその実測値に合わせたら、本番では逆に60pxの空白が出た。同じ端末・同じホーム画面アプリでも、ページによって数字が違った。捨て用のページが有効なのは「条件の切り分け」までで、寸法の絶対値は本番でしか測れない。</li>
<li><strong>断続的な不具合は「再現を待つ」のではなく「再現したときに証拠が残っている」状態を先に作る。</strong> 流れる実況だけでは、引き金が症状の数分前にあると永久に捕まらない。重要な行だけを別枠に最大6件、端末側に保存して読み込み直しても消えないようにした。</li>
</ul>
<h2 id="2-同じ報告が3回続いたら最初の2回は症状に当てていたということ">2. 同じ報告が3回続いたら、最初の2回は症状に当てていたということ</h2>
<p>同じ症状は、同じ不具合の証拠ではない。これを9回ぶん支払って覚えた。前回の直しに似せて今回も直す、というのが一番高くつく癖だった。他にも同じ型で踏んでいる。</p>
<ul>
<li><strong>本文が文の途中から始まる</strong>: 同じ訴えを4回受けた。4回とも同じ箇所を直したが、3回は「中身の継ぎ方」を見ていて、4回目にようやく「その処理が誰のために走っているのか」が原因だと分かった。</li>
<li><strong>吹き出しの「しっぽ」の形</strong>: 市販アプリに寄せるのに3回作り直した。1回目は目分量、2回目は寸法を比で揃える、3回目でようやく「寸法ではなく形そのものが違う」と分かった。寸法の話をしているあいだは、何度直しても近づかない。</li>
</ul>
<p><strong>同じ報告が3回来たら、3回目の直しを書く前に「1回目と2回目はなぜ外れたのか」を先に書く。</strong> 書けないなら、まだ症状に当てている。</p>
<h2 id="3-直したものが端末に届いていないは直っていないと見分けがつかない">3. 「直したものが端末に届いていない」は「直っていない」と見分けがつかない</h2>
<p>原因の種類が違うのに、画面上はまったく同じに見える。3往復むだにして気づいた。</p>
<p>🔴 <strong>iOSのホーム画面アプリは、閉じて開き直すだけではページを読み込み直さない。</strong> 何時間も前の状態を握ったままなので、サーバー側のファイルを直し、サーバーが正しく新しいものを配っていても、相手の画面は一切変わらない。「なおらないよ?」が3回続いたときに配信物を直接取って確かめたら、配っているものは正しかった。</p>
<p>やったこと。サーバーに「いまの版」を返すだけの口を足し、画面側は起動時にそれを控えて、他のアプリから戻ってきたときに照合し、違っていたら読み込み直す。そして<strong>画面に版の文字列を出し、次に報告をもらったら何よりも先にその文字列を読む</strong>。あわせて端末側から「起動した(版はこれ、ホーム画面アプリかタブか、通知の許可はどうか)」を1行だけサーバーへ送るようにした(会話の本文は送らない)。</p>
<p><strong>見分け方として一番効いたのは、もらったスクショが前回とピクセル単位で同じかどうか。</strong> 同じならまず「届いていない」を疑う。コードを3通り書き直す前にこれを確かめる。</p>
<p>さらに厄介な形も踏んだ。画面は最新なのに、裏で動いている配信役(Service Worker)だけが取り残されて<strong>6版も古いまま</strong>だったことがある。古い配信役は新しい形の通知を受け取れないので、通知が消えないという別の症状に化けていた。<strong>「効いている」だけでは足りず、「何版が効いているか」を答えさせないと気づけない。</strong></p>
<h2 id="4-日付つきで試したことと外れた理由を残す">4. 日付つきで、試したことと外れた理由を残す</h2>
<p>6週間経つと、これが同じ輪を歩き直さない唯一の歯止めになる。やったこと・やめたこと・なぜ外れたかを、日付つきで1ファイルに積み上げている。具体的に効いた場面を2つ。</p>
<p><strong>タブの切り替えアニメーションを機能ごと撤去した。</strong> 画面下にタブを足して、切り替えに横滑りの動きを付けた。その直後に「画面上のなんのボタンも反応しなくなった」と報告が来た。動かない原因を追うのではなく、動いていた時点のファイルに戻し、安全な2件だけを入れ直して、アニメーションは仕掛けごと削除した。<strong>直すより消すほうが安い機能がある</strong>という判断を記録に残しておくと、後でまた同じ思いつきが出たときに止められる。</p>
<p><strong>下タブの導入をまるごと巻き戻した。</strong> 別の日、下タブを入れた版でアプリが完全に操作不能になった。部分的な修正を試さず、導入前のファイルへ丸ごと戻した。失ったのは下タブ・独立した設定画面・カレンダーの月週日の切り替え・起動時の表示先の4つで、全部もう一度作り直した。<strong>巻き戻しで何を失ったかを書いておく</strong>と、作り直しの順番がそのまま手順表になる。次は「タブバーだけ入れて実機で確認」「設定画面」「カレンダー」の3段に分け、1段ごとに実機で確かめた。</p>
<p>記録が無ければ成立しない言い方がある。<strong>「それはもう試した。こういう理由で外れた」</strong>。</p>
<ul>
<li>「変換中は触らない」というガードを、<strong>呼び出し側だけに書いて2回再発させた</strong>。記録を読み返して「2回とも呼び出し側だけ直している」と分かり、以後は<strong>触る処理そのものに1つ残らず書く</strong>ことにした。呼び口は後から増えるので、入口で止めても漏れる。</li>
<li>入力欄の下に空ける余白を、2日のあいだに4回も定数で反転させていた。記録を並べたら「実機のスクショ2枚が食い違っているのは、どちらかが嘘なのではなく、場合分けの軸がまだ見つかっていない」と気づけた。</li>
<li>🔴 <strong>過去の自分の結論が間違っていることがある。</strong> 「この寸法は常に引かれる」と書いた結論が、別の環境では成立していなかった。日付を必ず付けているのは、どの結論が新しいかを後から判定するため。</li>
</ul>
<h2 id="5-エージェントは画面を見られない詰まるのは説明の側">5. エージェントは画面を見られない。詰まるのは説明の側</h2>
<p>エージェントはコードを読めるが、自分のスマートフォンに何が映っているかは見えない。だから自分の説明が唯一の入力になる。そしてこちらは非エンジニアなので、言葉で正確に言えない。<strong>この落差が、6週間でいちばん多く時間を食った。</strong></p>
<p>スクショを添えて初めて診断できた不具合がいくつもある。</p>
<ul>
<li><strong>タイルが潰れる件</strong>: 「縞に見える」という言葉のままでは2手外れたが、スクショで「正方形が帯になっている」と分かって真因が決まった。</li>
<li><strong>送信済みのチェックマークが消えた件</strong>: 吹き出しに「しっぽ」を足したら、重ねて貼った小片が<strong>チェックマークをまるごと塗り潰していた</strong>。時刻も右端が覆われていたが、色が同じなので画面を見ても気づけなかった。原因は「位置を指定した要素は、同じ親の文字より上に描かれる」というだけの話。スクショを拡大して初めて確定した。</li>
<li><strong>カレンダーの縦線と幅が合わない件</strong>: 3回かかった。1回目と2回目はCSSを読んで「理屈の上では揃うはず」と判断し、揃わない前提そのものを疑わなかった。3回目にスクショの画素を1行ぶん走査し、帯の幅が列のちょうど76%だと測って、その数字で該当箇所に一発で当たった。</li>
</ul>
<p>そしてもう1つ。<strong>市販アプリの見た目に寄せるなら、スクショは「参考にする」のではなく、画像編集ソフトで「測る」。</strong></p>
<ul>
<li>吹き出しの色をスクショの画素から直接読んだら、公称されている色と<strong>実際の画素が微妙に違っていた</strong>。目で選んだ色では一致しない。</li>
<li>角の丸みは目分量で<strong>3回外した</strong>。「全然だめだ」と言われてようやくスクショを測り、<code>角丸 ÷ 文字の大きさ = 1.63</code>、<code>角丸 ÷ 2行の吹き出しの高さ = 0.436</code>という比を出した。自分のアプリの文字サイズと行間からその比を満たす値を計算したら一発で合った。</li>
<li>青も<strong>3回外した</strong>。濃すぎる・薄すぎるを行き来したあとスクショから採った値に替えたが、その副作用で<strong>未読と既読のチェックマークが見分けられなくなった</strong>(地を薄くしたので白78%と白の差が消えた)。色で状態を表しているなら、地の色を変えたら差も作り直す必要がある。</li>
<li>しっぽの形は、最終的に<strong>スクショの輪郭を1画素ずつ読み取ってそのまま図形として写し取った</strong>。向こうの形は角丸と小片の組み合わせではなく、右辺が内へ寄りながら下へ垂れる一続きの曲線だった。</li>
</ul>
<p>エージェントに渡す材料の優先順位はこうなった。<strong>実機のスクショ &gt; 実機の実況ログ &gt; 実データ(保存されている記録そのもの) &gt; 自分の言葉。</strong> 自分の言葉が一番弱い。</p>
<h2 id="これで解決しないこと">これで解決しないこと</h2>
<ul>
<li><strong>答えが正しいかどうかを自分で判定できる必要は、まったく減らない。</strong> エージェントは「直りました」と報告してくる。6週間で何十回も、机上では直っていて実機では直っていなかった。最後に実機で確かめるのも「これは直った/これはまだだ」を判断するのも自分。受け取る側に判定能力がないと、同じ輪をもっと速く回るだけになる。</li>
<li><strong>分かっていないものが溜まっていく。</strong> 自分のアプリには、自分が原理を説明できない処理が入っている。説明を求めれば返ってくるが、6週間ぶんを全部覚えているわけではない。壊れたときに「ここは触るな」と言えない箇所がある、という事実は消えていない。</li>
<li><strong>説明できない症状は、直せない症状のままになる。</strong> 「なんとなく動きが変」は、スクショも実況も実データも出せないので結局手が付かない。9回目の変換候補の件も、まだ真因には届いていない。<strong>残っているのは「本番のコードのどこか」という範囲だけで、名前は付いていない。</strong></li>
</ul>
<p><strong>更新履歴</strong> — 2026-10-05: 初版</p>
]]></content:encoded></item></channel></rss>