2011年6月18日土曜日

mvcPhotosの出来るまで

ちょっと書いてみます。あんまり面白く無いですよ。

ASP.NET MVCをメインにした企画をやってみたいとチャックから連絡があって、喋る人が決まったところで各々にテーマがふられました。んで、たけはら担当として「クライアントサイドのテクノロジをメインに扱うセッションを」というリクエストから始まるんですが、ぶっちゃけ「それMVC関係ないじゃない...」と愕然としたものです。

とはいえ、テーマを無視するのもあれだからと、まずはセッション概要を伝え(もちろんこの時にはまだ何をするのか決めてないので、ぼかしまくった感じで)募集開始。そろそろ真面目に考えないとね~、と思いつつ仕事も忙しかったしで、ほっといたらあっという間に5月中旬。そろそろスライドだけでも書かねばと書き始めるものの、何を作るかは全く決まらず...。とりあえずの方向性としては

  1. 作ったものに参加者もその場でアクセスできる(だけど会場内のネットワークでは自マシンに参加者がアクセス出来ないはず)
  2. アーキテクチャを意識する
  3. MVC使いつつクライアントサイドモリモリ
  4. コードは参加者へのプレゼント

の4点。

※ネットワークについては、昨年のTechEDでダメだったのを経験してたので。

はてさて、どうしたものか。Twitterは他の人が絶対利用するだろうからパス。単純に外部サーバーにWebアクセスしてみんなでワイワイする感じで何がいいかな~、って考えるとどうしてもMvcGraffiti(みんなでお絵かき)とかぶる。となると、手堅い方法はメールか。ケータイなら絶対繋がるはず。メールということはPOP3の実装は必要だな~。メールなら写メがいいかも。という流れでとりあえずPOP3の実装と画像のリサイズ部分だけ先行コーディング。

いろいろ悩んだ挙句、普通に写真共有っていうところに落ち着くんだけど、どうやってクライアントサイドモリモリを達成するか。そこは後回しにしてアーキテクチャ。この時点でAppHarborをプラットフォームにして、ストレージはGoogle Storage使ってみようかと実験。でもGoogle Storageが思ったようにいかないからS3にチェンジ。モデルはCodeFirstで、ストレージは置き換えられるようにProviderとして実装。MVCでのサーバーサイドはシンプルにAPI的なものと、UA切り替え出来るような仕組みをどうするか考えつつ、ワーカーによるバックグラウンド処理でメールとストレージのつなぎをやろうと決める。UAに合わせてViewを切り替えるのはいろんなやり方があるけど、出回ってるやり方を実装してもつまらないので、随分悩んだ末にRoutingとViewEngineのコンビネーションで行う方法を思いつく。さすがオレ。

クライアントサイドはこのころすごく気になってたknockout.jsとModernizrを使うことで、うまいことやろうと思いつつ具体的なことは決めずにサーバーサイドをゴリゴリ作る。あと、それっぽくテストコードも用意することで、スタックというかレイヤというか、その辺を意識しやすいようにしておこう。

ちょっと横道にそれますが、ControllerのテストをしやすくするためにFormCollectionをパラメータに使う例をよく見ますね。でも意味ないですよね。そこは普通に入力モデルを渡せばいいじゃないっていうふうに思うわけですよ。だって、FormなりのValueProviderからModelBinder経由した入力モデルへのマッピングって、Controllerのテストじゃ無いからですよ。通常のFormを想定した場合、FormCollectionからUpdateModelをするなら、それはもうMVCが提供してくれるModelBinderのテストをするようなもんでしょう。意味無いじゃん!なので、ModelBinderのテストはMVCの開発チームに任せて、自分たちの書いたコードに対するテストを書きましょう。ただ、今回Controllerのテストは書いてないですけどね!てへ。

ここまで全然コード解説じゃないですけど、セッションで話したいのはそもそも製品の紹介じゃなくて「アプリケーションの作り方」。何をどういう設計で作るかを決めることで詰みです。「拳(コード)で語る」のがプログラマーですよ。だって、ASP.NET MVCも1~3へと進み、4以降になったら製品の使い方、コードの書き方なんて変わるわけですよ。Razorなんてものも出てくるし。だけど、考え方とか適用の仕方ってMVCっていうアーキテクチャスタイルとか、デザインパターンとかって基礎として使い続けるじゃん?そこ意識すること大事だと思うんす。

ただでも、このやり方は諸刃で、聞きに来てくれる層によってはドン引きされるんです(経験あり)。だって「お前の作ったアプリケーションを見に来たんじゃないんだよ!」とか「そのアプリでオレのプロジェクトは解決できない!」という意見もあるからね。いろいろです。どんな意見も、それぞれの人のコンテキストでは正論っす。ただ、自分にとっては、目の前の問題の答えを提示する局所最適じゃなく、全体最適を目指すほうが楽しい。なので、これからもこのやり方は変わらないでしょう。

はっ!熱くなってた!しっけいしっけい。

サーバーサイドが概ね出来たところで、クライアントサイドの実装に入るわけですが、PC,iPad,iPhone、そして日本が誇る超精密パーソナル通信機器、通称ガラケー対応も無視できない。モダンブラウザ向けにはjQuery Mobile使おうと思ってたんだけど、Azure担当大臣のだいちゃんが「jQuery Mobileでモテモテになるっす!」とか言い出しやがって、かぶるじゃねーかよ、的なね。まぁ、いいか。んじゃ、オレ適当に実装する、ということになりました。なので、見た目かなりしょぼくなったけど、オレのせいじゃないから!エロ大臣のせいだから!!Azureチーム金持ってるからって可愛いキャラ多すぎなんだよ。ASP.NET界隈では緑のキグルミしかいないっつーの。羨ましくなんか..うっぐ。泣かない。

はいはい。クライアントサイドでどういう感じに動かすのか、図に書いて最初に実装したのが、↓こんなやつ。

sample

受信画像をタイル状にランダム表示。緑も意識してみた。だけどコレがまたダサいのなんのって。イメージ通りに作ったはずなのに。自分のセンスに絶望。

sample2

ランダムがだめなのかと思って順番に表示するようにしたりしたけど...。根本的におかしい。マジやべー。

sample3

色がだめなのか!?と思って黒くしてみた。

sample4

で、最終的には↑こうなるんだけど、みんな知ってた?ウィンドウサイズに合わせてサムネイルの画像サイズは100→50→25と収まりよくなるようにリサイズするんだよ?

http://mvcphotos.takepara.com/

試してみてね。

ソースはこちら。

http://mvcphotos.codeplex.com/

Source Codeタブをクリックして右端のLatest VersionにあるBrowseで見たり、Downloadで取得してね。

source

書き疲れた...。もういい?仕様書もマニュアルもなしで、コードを追いかけるのも大変だと思うので、今回作成したmvcPhotosの実装をザックリ書きだしておきます。

  • POP3でメール受信
  • クラウドストレージとローカルストレージを切り替えやすくするためのストレージプロバイダ化
  • 画像のリサイズ
  • EF CodeFirstによるDAL
  • データベースアクセスをRepositoryにより抽象化
  • サーバーサイドでもDAL用のモデルと、入出力用のモデルを分けることでレイヤ分離と検証ルールの明確化
  • 動的画像リサイズを行うためのコンカレント制御と非同期Controller
  • 複数のUserAgentを同一Controllerで処理するためのViewEngineとRouting制御
  • モダンブラウザの判定と、動的スクリプト読み込みにModernizr
  • knockout.jsによるクライアントサイドでのMVVM実装
  • 自作Service Locatorと、DependencyResolver実装
  • DIを3パターン実装(探してみてね!)

こんな感じです。

ちなみにパネルディスカッションの最後でゴニョゴニョ言ってたことなんですけど「大事なのはMVCの心を理解しようとし、SoC - Separation of Concerns - 関心の分離を意識すること」。つまりきちんと役割を分離して、実装も可能なかぎり分離して参照関係を単純にしましょうね、と言いたかったですが言葉足らずのドヤ顔で失礼しました。

あと、一色さん、変なやりとりでスマセンした。失礼ぶっこいてスマセンした。ホントはすごいシャイボーイなんです。自分で言うのもなんですが、草食系男子なんです。型は古くて時化には強いタイプですけどシャバいやつなんす。

今後ともご贔屓に~。