ANTIGRAVITY LABEN
ブログ一覧

まだ存在しない端末のために設計する — 新しい画面サイズに慌てなくなるまで

Antigravity個人開発iOS設計思想画面サイズ保守性

新しい iPhone の画面サイズに対応する作業が回ってきたとき、以前の私は決まって小さく身構えていました。「またあのファイルとあのファイルを開いて、数字を足していくのか」と。

ところが先日、同じ状況になったのに、その身構えがほとんどありませんでした。作業そのものは増えたはずなのに、気持ちのうえでは静かでした。理由をたどっていくと、半年ほど前に下したひとつの地味な判断に行き当たりました。今日はその話を書いておきたいと思います。

以前は、新機種が出るたびに小さく身構えていました

私は 2013 年から個人でスマートフォンアプリを作り続けていて、いまは Beautiful HD Wallpapers や Ukiyo-e Wallpapers を含む 4 本の iOS アプリを運営しています。累計のダウンロードは 5,000 万を超えました。壁紙アプリという性質上、画面いっぱいに画像を敷き詰める処理が中心で、端末ごとの解像度やセーフエリアの違いがそのまま見た目に響きます。

問題は、その「端末ごとの違い」を吸収するコードが、長い年月の中であちこちに散らばっていたことでした。あるビューでは画面の高さを直接見て分岐し、別のビューでは角丸の有無で判定し、また別の場所では機種名そのものを文字列で比較していました。どれも、その場では一番手早い書き方でした。

新しい iPhone が出るたびに、私はそれらの分岐を一つずつ探し出しては、新しい条件を継ぎ足していました。見落とせば、特定の端末でだけ余白がずれたり、画像の端が切れたりします。作業が憂鬱だったのは、量よりも「どこに分岐が隠れているか分からない」という不安のほうでした。

「分岐を1か所に集める」という、地味だけれど効いた判断

転機になったのは、4 本のアプリの SDK をまとめて更新していた時期でした。ついでに、散らばった端末分岐をすべて一つの定数ファイルに集めてしまおうと決めたのです。特別な発想ではありません。ただ「同じ種類の判断は、同じ場所に置く」というだけのことです。

Before は、こんなコードが何箇所にも散っていました。

// 画面の高さを直接見て、ビューごとに分岐していた
let bottomInset: CGFloat
if UIScreen.main.bounds.height >= 956 {
    bottomInset = 34   // 大きな端末
} else if UIScreen.main.bounds.height >= 844 {
    bottomInset = 28
} else {
    bottomInset = 0    // ホームボタンのある端末
}

After は、判断の根拠を一つの場所に移しました。

// DeviceMetrics.swift — 端末ごとの違いはここだけが知っている
enum DeviceMetrics {
    /// セーフエリア下端の余白。新しい画面サイズが増えても、追記はこの一覧だけで済む
    static var bottomInset: CGFloat {
        switch UIScreen.main.bounds.height {
        case 956...: return 34
        case 844..<956: return 28
        default: return 0
        }
    }
}
 
// 呼び出し側は「なぜその数字か」を気にしなくてよくなる
view.layoutMargins.bottom = DeviceMetrics.bottomInset

この移行作業で Antigravity に任せたのは、「UIScreen.main.bounds を参照している箇所をすべて洗い出す」という探索の部分でした。人間がやると見落とすこの作業を、エージェントはコードベース全体から正確に拾い上げてくれます。新機種対応そのものの細かい実例は Antigravity で新 iPhone の解像度対応を乗り越えた話 にまとめてありますので、実装の詳細に関心がある方はそちらを併せて読んでいただければと思います。

エージェントは「探す」のが得意で、「決める」のは私の仕事

この作業を通して、はっきり線引きできたことがあります。エージェントは「どこに何が散らばっているか」を探すのが驚くほど得意です。一方で、「それらをどんな形にまとめるか」という抽象の設計は、まだ私が引き受けるべき領域だと感じました。

たとえば、端末分岐を「高さ」でまとめるのか、「世代」でまとめるのか、それとも「セーフエリアの実測値」に寄せるのか。これは正解が一つではなく、アプリの性格や将来の方向性によって変わります。Antigravity に候補を出してもらうことはできますが、最終的にどれを選ぶかは、自分がそのアプリをどう育てたいかという話になります。コードの不具合をエージェントと一緒に追う流れについては Antigravity AI デバッグ活用ガイド でも触れていますが、探すところまでは任せて、決めるところは握る、という呼吸が私にはしっくりきています。

まだ見ぬ端末を、設計の中に含めておく

定数ファイルに分岐を集めてから、ひとつ静かな変化がありました。新しい画面サイズが「未知の脅威」ではなく、「既知の一覧に一行足すだけのもの」に変わったのです。

私の祖父は二人とも宮大工でした。幼い頃に見ていたのは、まだ建っていない建物のために、寸法をていねいに整えていく姿でした。手を動かすこと自体が一種の信心のようでもありました。いまになって思うのは、あの作業は「これから来るもの」を見越して余白を残しておく仕事だったのだ、ということです。

ソフトウェアでも同じことが言えるのかもしれません。次にどんな端末が出るかは分かりません。けれど「端末ごとに違う値が一つ増える」という変化の形は予測できます。だとすれば、その変化を受け止める場所を一か所だけ用意しておけば、未知の端末さえも設計の中にあらかじめ含めておけることになります。SDK 更新の際にまとめて整える話は Firebase Apple SDK の CocoaPods から SPM への移行で詰まった3つのポイント にも書きましたが、保守のしやすさは、こういう小さな一か所主義の積み重ねで決まっていく気がしています。

次に新しい画面サイズが来たら

もしいま、新機種対応のたびに憂鬱を感じている方がいたら、まずは一番散らばっている分岐を一つだけ選んで、それを一か所に集めるところから始めてみてください。すべてを一気に整理する必要はありません。最も頻繁に触る端末分岐が一つ片付くだけで、次の新機種が来たときの気持ちが変わるはずです。

私自身、まだ整理しきれていないコードを抱えています。それでも、変化を前提にした小さな置き場所を一つずつ増やしていくことが、長く個人開発を続けるための地味で確かな足場になると感じています。最後までお読みいただき、ありがとうございました。