🤔

【SwiftUI】ワンオペ屋台から魔法の厨房へ:MVVMとは

に公開

【脱・ワンオペ】MVCの店長が「魔法の厨房(MVVM)」に救われるまで

なぜ、僕らのアプリはすぐにスパゲッティになるのか?

「あれ? 変数の数字は増えているのに、画面の表示が 0 のままだ……」

プログラミングを始めたばかりの頃、こんな経験はないだろうか。
原因は単純。
「変数を更新した後、ラベルの書き換え(text = ...)を忘れていたから」だ。

一つならまだいい。でも、機能が増えるとどうなるか。
「読み込み中はローディングを出して、成功したら消して、リストを表示して、あ、失敗した時はアラートを出して……」

気付けばコードは、「もし〇〇なら、××を表示しろ」という 大量の「命令」 で埋め尽くされている。どこか一箇所でも命令を書き忘れたら、アプリは動かないか、古い情報を表示し続ける。

これは例えるなら、「超・完璧主義のワンオペ店長」が支配するお店だ。

店長(あなた)は、厨房で料理を作りながら、ホールの状況を全て記憶し、「A卓に水! B卓は片付け! C卓へ料理運んで!」と、一瞬も休まず叫び続けなければならない。

これでは、客(機能)が増えた瞬間に店がパンクするのは当たり前だ。
もしあなたが、そんな「命令し続けること」に疲れ果てているなら、少しだけ店(アーキテクチャ)の改装の話を聞いてほしい。

これは、ワンオペで叫び続ける店長が、「魔法の仕組み」によって解放されるまでの物語だ。


1. 悲劇のワンオペ時代(MVC: Imperative)

UIKit時代のMVC、特にその実装が肥大化してしまった現場を思い出してみよう。
これは例えるなら、「伝説のスーパー店長(Controller)」が支配するワンオペ屋台だ。

店長(Controller)の仕事

厨房(Model)と客席(View)の間に立ち、全ての動きを命令する。

  1. 客が来る(Event)。
  2. 店長がシェフに「ハンバーグ作れ!」と叫ぶ。
  3. シェフがハンバーグを作る。
  4. ここが重要: 店長はハンバーグが出来たことを確認し、自分でホールスタッフに「おい!A卓にこれを運べ!」と命令しなければならない。

コードで書くと、こういうことだ。

// 典型的なMVCの悲劇
func updateView() {
    // 店長が全てを把握し、一つ一つ指示(代入)する
    titleLabel.text = user.name
    descriptionLabel.text = user.profile
    iconImageView.image = user.icon 
    // もしここで priceLabel.text の更新を書き忘れたら?
    // → 画面は古い価格のまま(バグ)
}

店が繁盛する(機能が増える)につれ、店長は「A卓に水!B卓は会計!C卓のハンバーグまだか!」と叫び続けることになる。
これが 「命令型(Imperative)」 の限界だ。店長の記憶力と体力が尽きた瞬間、店(アプリ)は崩壊する。


2. 革命的システムの導入(MVVM: Declarative)

SwiftUI時代のMVVMは、この店長をクビにすることから始まる。
代わりに導入されたのが、 「魔法の受け渡しカウンター(ViewModel)」と「監視カメラ(Binding)」 だ。

この新しい店(ハイテク定食屋)には、もう叫ぶ人はいない。

シェフの意識改革(ViewModel)

シェフ(ロジック担当)は、もう客席(View)のことなんて気にしない。
「今、客席がどうなっているか」を知る必要すらないのだ。

彼がやることはただ一つ。料理ができたら、決まった 「魔法のカウンター(@Published)」 に置くことだけ。

class OrderViewModel: ObservableObject {
    // これが「魔法のカウンター」
    @Published var currentDish: String = "準備中"

    func cook() {
        // シェフは料理を作ってカウンターに置くだけ。
        // 「客席に運べ」とは言わない。
        self.currentDish = "特製オムライス"
    }
}

ホールスタッフの自動化(View)

ホールスタッフ(View)も、誰かの指示を待ったりしない。
カウンターには「監視カメラ」が設置されており、 「カウンターに料理が置かれた瞬間、ホールのテーブルにも同じものが転送される」 という仕組み(データバインディング)が出来上がっている。

struct OrderView: View {
    // カウンターを監視する
    @StateObject var viewModel = OrderViewModel()

    var body: some View {
        // 料理が置かれたら、勝手に画面に出る
        // 「表示しろ」という命令は存在しない
        Text(viewModel.currentDish)
    }
}

これが 「宣言的(Declarative)」 な世界だ。
「シェフがカウンターの状態を変える」=「客席の見た目が変わる」。
そこにタイムラグも、命令の伝達ミスも、店長の過労も存在しない。直結しているのだ。


3. 制御を手放す勇気

MVCからMVVMへの移行、それは単なるコードの書き換えではない。
「全てをコントロールしたい」というエンジニアの強迫観念からの脱却だ。

かつての私たちは、すべての変数を監視し、すべてのタイミングで setText を呼ばなければ気が済まなかった。それは「安全設計」のつもりで、その実、自分自身(Controller)をボトルネックにする行為だったのだ。

MVVM + SwiftUIの世界では、私たちはシステムを信頼し、制御を手放すことになる。
「状態(State)」さえ正しく定義すれば、結果(View)は約束される。

このアーキテクチャが教えてくれるのは、「個々の役割(関心事の分離)を尊重し、過干渉をやめる」という、チーム開発においても、人生においても重要なスタンスなのかもしれない。

さあ、あなたのコードから、叫び続ける店長を解放してあげよう。
魔法のカウンターは、もう準備できている。

Discussion