開発中のアプリをMVVMからMVCに戻した理由

史翔新氏:先ほど紹介に預かりました史と申します。ふだんの勉強会では、loveeとか、星野さんと呼ばれているので、お気軽にどれでも好きな呼び方でお願いします。

というわけで、「なぜうちのチームは開発中のアプリをMVVMからMVCに戻したのか」というタイトルで発表させていただきます。

まず簡単に自己紹介をします。

いま、ゆめみという会社でiOSの開発者をやっております。一番好きな言語はSwiftです。TwitterとQiitaでは@loveeの名前でやっておりまして、GitHubではel-hoshinoというアカウントでやってます。

そして、先週末、新潟の苗場スキー場というところで人生初のスノボをきめてきました。何回だかわからないぐらいいっぱい転んだので、いまだに関節が痛いです(笑)。筋肉じゃなくて関節です。

というわけで、タイトルに1回戻ります。

MVVMからMVCに「戻した」。どういうことだろう?

いま開発しているアプリのスペックを簡単に説明します。

名前は公表できないんですけど、株だとか、仮想通貨だとか、そういう金融系のアプリです。当然ながらレートというものを扱いまして、これはリアルタイムで変動しているので、それをリアルタイムで画面に表示したいというようなアプリです。

そして、iOSとAndroid両方に対応しています。もちろんiOSとAndroidでそれぞれ違うチームが開発しておりまして、僕が担当しているのはiOSのほうです。

この金融系のアプリは、実際の本体というか、具体的なビジネスロジックというのは外部のサービスに依存しておりまして、それらのAPIはすべて自社内ではなく外部のサーバーのバックエンドAPIに依存しています。ここが伏線です。

そして、開発期間は受入テストを含めて6ヶ月しかないという……、「本当に金融系のアプリの開発として半年間だけでいいの?」というレベルです。「もうちょっとテスト期間が長いほうがいいんじゃないか?」という感じです。

MVVMで開発しはじめた経緯

というわけで、開発当初はこのような会話がありました。

うちのPMさんが、「今度のアプリ、リアルタイムのレート変動表示をしなきゃいけないですし、Androidの場合は実質MVVMというAndroid Architecture Componentsというものを使うから、iOSもそれに合わせて、RxSwiftを使ったデータバインディングがあるMVVMでやってみたらどう?」と言われまして。

僕は、「うーん……。どっちかっていうと、僕はMVCのほうが慣れているので、MVCのほうが無難なんじゃないかな」と。そうしたら、僕と一緒に開発をしているチームメンバーの人たちが、「いやいや、最近MVVMのほうがトレンドっぽいので、私たちもMVVMをやりたいですよ」と言われて。

(会場笑)

「うーん、なるほど。みんながそう言うんでしたら、MVVMで作ってみますか。」

(会場笑)

そうしたら「というわけで、MVVMもRxSwiftもそんなに詳しくないので、ご鞭撻お願いします。よろしくお願いします!」って言われて、「おい、マジか!」と。

(会場笑)

という感じです。そして、そのタイムラインがこんな感じになっています。

まず6月、一番頭ですね、開発が開始します。そこでMVVMという設計を使うことを決定しました。そして、8月の末ぐらいにサーバのAPIがすべてそろう、というスケジュールになっています。それで、11月から結合テストに入って、12月で受入テストに入って、最後、12月末に配信開始という予定でした、が、残念ながらこれはすべて理想に過ぎませんでした。

(会場笑)

現実はどういうふうになっているかというと、僕が登壇している現在の時点では、まだサーバーのAPIが動いてないものが一部あります。

(会場笑)

そして今年はいろいろ大きな事件があったおかげで、今年のだいたい7月ぐらいに法改正の見込みがあるということで、そこでもともとあった画面仕様の一部変更が余儀なくされました。

そして8月、本来だったらサーバAPIがすべてそろっているはずという期間に入って、実際にサーバに叩いたレスポンスが、仕様書に書いてあるものと違うということが発覚しました。

そしていろいろあって、「やっぱりMVVMはけっこうつらいよな」ということで、10月末ぐらいに、「原則MVCに戻そう」と方向転換を決定しました。ちなみに、どうでもいいことを言いますと、実はこれはすでに僕が2回目の「MVCに戻そうぜ」と言い出したときです。

1回目は7月の中旬ぐらいに画面仕様の変更っていうことが決まった時点で、僕はすでに「MVVMだと変更量が多いので、MVCにしない?」と言って、「いや、もうMVVMでやってきたんだから、やっぱりこのままMVVMで継続しよう」ということだったんですけれども……、お笑い話になっています。

そして、いつまでもズルズルと開発を終えないわけにもいかないので、とりあえず今年(2018年)の12月末にいったん開発を終了させる予定と決まっています。

MVVM×RxSwiftでの開発をやってみて

というわけで、じゃあなぜ僕が「MVCに方向転換をしよう」と言い出したかというと、実際にMVVM×RxSwiftで開発してみた感想として、……ここではネガティブな感想だけを集めています。

ポジティブな感想ももちろんありますけども、ここではいったん割愛します。

まずViewControllerとViewModelには大量の重複定義があります。これによって初期の実装コストが高くなりますし、7月中旬にあった画面の仕様変更に対しての修正コストもかなり高くなっています。画面の仕様が変更になったということは、つまりViewControllerだけではなくて、ViewModelのほうにもどうしても修正が必要になってきます。

そしてもう1つは、RxSwiftの双方バインディングとかいろんなOperatorだとか、そういうのが初心者にとってはすごく鬼門になっています。慣れてない人にとって習得コストが高いですし、そのせいでプルリクに対する僕の差し戻しもけっこう多くなって、開発の進捗も思っているよりはちょっと遅かったです。

そしてもう1つ、僕は実はRxSwiftのOperatorをバリバリに使った書き方ってわりと読みにくいんじゃないかなと思っています。なぜかというと、どこにどういう処理がどういうふうに実装されてるのかが、非常に探しにくいですし、あと、大量の.disposed(by: disposeBag)が、けっこう目障りなんじゃないかなと思います。これはあくまで個人の感想です。

というわけで、ちょっと振り返ってみて、そもそもうちのチームはなぜMVVMを使うんでしたっけ? MVVMを使う理由って何でしたっけ? さっきの会話を振り返ってみると、ふむふむ、そういう会話があったんですね。

MVCにまつわる誤解

MVVMを導入した理由は3つありました。1つ目は、リアルタイムのレート変動をリアルタイムで表示したい。2つ目は、Androidは実質MVVMの設計を使っている。そして3つ目はチームメンバーの人たちが「私たちもMVVMをやりたい」と言っていた。

という3つの理由で、MVVMを導入することにしましたけれども、よくよく考えてみたら、「そもそもまずリアルタイムのレート変動、その1画面しかないやんけ!」というのが1つ目。「俺ら、Androidとソースコードの共有してるわけじゃないじゃん!」っていうのが2つ目。3つ目は「そもそも誰1人経験者がいないやんけ!」……という話になりました。

そしてもう1つ、深くツッコんでみると、実はそもそも、「MVCではリアルタイムで画面更新がしにくい」というわけではないんですよね。MVCはよく誤解されてるんですけど、まずここでちょっと簡単に2点紹介します。

1点目、我々は言葉で「MVC」と言っているんですけど、MVCというのは1つだけのMVCではないんですね。MVCにはいくつかの種類がありまして、1つ目は最初に論文化されたMVC、これは「原初MVC」とも呼ばれています。先ほど杉上さんが紹介しているiOS設計本(注:『iOSアプリ設計パターン入門』)のなかでも、「原初MVC」と呼んでいます。

そして2つ目、Appleが提唱しているCocoa MVCというものです。これが我々iOSエンジニアが言っているMVCです。我々iOSエンジニアが「MVC」と呼ぶと、9割9分このCocoa MVCのことを指しています。

そしてさらにフロントエンドのほうではMVC Model 2というMVCもあるらしいです。僕はそんなに詳しくは知らないです。他にもいろいろあるらしいんですけれども、とりあえずMVCというのは、実はいくつかのMVCがあるということです。

そして2点目です。MVCでも普通にModelからのデータ更新っていうのは通知されてきます。

MVCのなかではMVVMで言うような「データバインディング」という言葉は基本的に使わないですけれども、それでも実はModelの状態変更っていうのは、Observerパターンを利用して、購読をしているオブジェクトにリアルタイムで通知しているわけです。

ちなみにこの購読オブジェクトというのも、原初MVCだったらViewのほう、Cocoa MVCでしたらViewControllerのほうにあたります。というふうに、MVCにまつわるよくある誤解について、とりあえずここで2つ挙げてみました。

MVCに戻すことで得られたもの

というわけで、やっぱりMVCに戻そう。じゃあ、戻した結果どうなってるかっていうと、(スライドを指して)これがもともとのMVVMのほうでのログインコードの一部抜粋です。

みなさんはこのコードを見て、正直どう思いますかね? 少なくとも僕はパッと見、非常に読みにくいんじゃないかなと思っています。もう画面が緑だらけですね。どこに何のことが書いてあるのかさっぱり、……もちろん読めばわかるんですけど、パッと見、読みやすいとは言えないんじゃないかなと思います。

これをMVCに戻すことによって、こういうふうなコードになりました。

僕からすると、さっきよりはだいぶ読みやすいんじゃないかなと思います。

もう1回見てみますね。このコードが、こういうふうになりました。

(会場笑)

実装コストとしても、コード量がだいぶ減ったのと、緑だらけというようなコードではなくなりました。

というわけで、MVCに戻すことによって我々は何を得られたかというと、まずはコーディングコストと仕様変更に対する修正コストが、MVVMと比べるとちょっと少なくなりました。

そして一番大きかったのは、Rxと、いろんなよくわからないOperatorに対する修正コストが、だいぶ少なくなりました。なぜかというと、MVCのほうでは、RxSwiftはObserverパターンだけにしか使っていないということですので、そんなにいろんなOperatorは使いません。

そしてもう1つは、単一方向のデータフローによるデバッグのしやすさ。厳密には、Cocoa MVCの場合はそんなに単一方向ではないんですけど、MVVMと比べるとだいぶ単一方向にはなっているんじゃないかなと思います。

そしてもう1つが、無理矢理にリアクティブプログラミングを入れなくていいという心理的な穏やかさ。別にMVVMもどうしてもリアクティブプログラミングを入れなければいけないというわけではないんですけれども、やっぱりどうしても、「入れたいな」「そういうふうにこだわりたいな」ということになりがちなんじゃないかなと思います。

設計に銀の弾丸はない

というわけで教訓。

1つ目として、仕様変更が完全に定まっていない段階で、そこまで細かく責務を分割しすぎると、今度は逆に仕様変更に対する修正コストが非常に高くなりますので、むしろある程度は責務過多のほうが、仕様変更に対して柔軟になります。

2つ目、納期との戦いを強いられた場合は、無理矢理「良さそう」な設計を導入する必要はありません。納期という観点では、どの設計を使うかよりも、設計のイメージがどれだけチームメンバーと共有できているのかのほうが重要なんじゃないかなと思います。

3つ目、MVCはまだまだ現役です。少なくともリアルタイムの更新という要件だけで、MVCを排除する理由にはならないと思います。

そしてもう1つ、設計に銀の弾丸はないです。これもiOS設計本のなかでこういうふうに語っておりますので、詳しく知りたい方はぜひ購入していただいて、読んでいただければと思います。

最後に宣伝です。

iOS設計本。僕は今日の話ではMVCの話でだいぶかかりましたけれども、僕はこの設計本のなかでは第5章のMVCの章を担当しておりますので、興味がある方はぜひ読んでいただけたらとてもうれしいです。

最後にもう1つ、株式会社ゆめみはエンジニア絶賛募集中です。興味がある方はぜひ僕に話しかけてください。ありがとうございます。以上です。

(会場拍手)