Previous month:
September 2009
Next month:
November 2009

ブラウザー上で動く iPhone-style トグルスイッチ

 ここのところ「iPhoneアプリのUIの大半(ひょっとしたらアプリすべて)をHTML+JavaScript+CSSで作ることはできないか?」に挑戦している私。

 そのためにまずは部品作りからとりかかっているのだが、昨日から今日にかけて作ったのは、プログレス・バー、スライダー、トグルスイッチなどの「連続値・不連続値」を表示・入力用UIコントロールをウェブページ上で実現するためのJavaScriptライブラリ。

 見た目(Look&Feel)はCSSを使って自由に指定できるように作りつつ、シンプルでありながらいろいろな場面で使い回しがきくライブラリを作りたかったので、何度もリファクタリングを繰り返してしまったが、なんとか形になってきた。

 ということで、そのライブラリ(jTouchControl version 0.10)を使ったiPhone風トグルスイッチを公開。一応、Safari (4.0), mobile Safari, Firefox(3.5), Chrome(4.0), Opera(9.0), IE (8.0)での動作確認済み。ただし、微妙なグラディエーションやアニメーションは、webkit-base のブラウザーでしか見えない。

 iPhone向けのアプリの開発に作ったのだからmobile Safariでさえ動けば十分だったのだが、「せっかく公開するのだから、せめてIE8で動く様にしよう」と欲を出したのが苦労の始まり。半日つぶれてしまった。

 ソースコードは http://widgetpad.com/954/ からアクセス可能。アプリ側のJavaScriptは基本的に以下の2行。最初の行がそれぞれのトグルスイッチを初期化し、次でその二つを連携させている(下のスイッチを変更すると上のスイッチが変更される)。

  1.      $('.switch').jTControl("slider"padding:20steps:});
         $('#switch2').bind("valuechanged"function($('#switch1')[0].setValue(this.getValue()0.2true)});
  2.  JTControlに渡す最初のパラメターは、コントロールの種類。現時点では、"slider"と"progressBar"のみをサポートしている。二番目のパラメターはオプションで、スライド範囲をwidthよりせばめるための"padding", 非連続値の場合の段階を指定する "steps" (1でトグルスイッチになる、デフォールトは非連続)、ドラッグするものを指定する "thumb" (省略すると空のDIVが挿入される)などを指定することができる。

Cloud Computing考:Amazon ec2とGoogle App Engineの違いを私なりにまとめてみた

 Cloud Computing の話が注目されるようになってしばらく経つが、商用での本格応用という意味ではまだまだ未熟な市場である。PhotoShareは去年の7月サービス開始時から Amazon の ec2+S3 という組み合わせで運営しており、私から見れば当然の選択だったわけだが、あのタイミングで商用サービスへの採用に踏み切った会社も少なかったのか、何件かインタビューの申し込みが来たりして少し驚いている(参照)。

 すぐに陳腐化するハードウェアの資産はできるだけ持ちたくないし、自分でデータセンターにラックを借りるなんてことはコスト的に見合わない。かといって、通常のレンタルサーバーは初期費用がばかにならない(今は少しは改善されているのかも知れないが、去年の段階では「それじゃあハードが自分で買えるじゃん」と言わせるぐらいの初期費用を請求する企業がほとんどであった)。それに加えて、どのくらいのトラフィックが来るのかを予測するのが不可能な場合(一般ユーザー向けのネットサービスのほとんどがそう)、「需要を予測した上で、それに見合うだけの初期投資が必要」なモデルはどう考えてもありえなかった。

 そんな理由で Amazon のウェブサービスを選択したわけだが、結果から見れば正しい判断だったと言える。特にサービス開始時のトラフィックが予想しにくい時期に、モバイルビジネスに良くある「はやって地獄(予想以上にユーザーが集まったためにサーバーが足らなくて四苦八苦すること)、はやらないで地獄(多大なトラフィックを想定してそれなりの初期投資をしたにもかかわらず、実際にはトラフィックが予想を遥かに下回り、初期投資の回収がままならなくなること)」というジレンマに陥らずに済んだことは大きい。

 しかし、実際に1年以上PhotoShareを運営して来て、Amazon のウェブサービスに足らない部分もいくつか見えては来ているので、ここに書いてみる。

 まず一つ目は、ec2はバーチャル・サーバーと呼ばれてはいるが、私が期待していたレベルのバーチャル・サーバーではないこと。Amazonはバーチャル・サーバーの仕組みを、「一つのパワフルなサーバーを複数のバーチャル・サーバーとして小分けしてレンタルする」ことに使ってはいるものの、「サーバーを完全にバーチャルにしてハードウェアと切り離し、ハードウェアに問題があってもサービスには一切支障をきたさない」というレベルまでは使っていない。バーチャル・サーバーと呼ぶのであれば、「ハードの問題」とか「特定のCPUから別のCPUへの引っ越し」とかを見えなくしてほしい。

 二つ目はAmazonの問題ではないのだが、ec2を使っても「データベースのお守り」は自分でしなければならないこと。PhotoShareはMySQLを使っているので、Oracleほどのチューニングは必要ないとは言え、バックアップとか修復とか、それなりの手間はかかる。そして当然だが、データベースのスケーラビリティの問題を解決するのもサーバーの借り手の責任である。一つのデータベースで足りているうちは良いが、ユーザーが増えて複数のデータベースに分けなければならない段階になると、パーティショニングやリプリケーションやらといろいろと複雑な問題を解決しなければならない。

 つまり簡単にまとめると、Amazon のウェブサービス(ec2)は、自分のサーバーを持つことや通常のレンタルサーバーを借りることと比べると、(1)初期投資が少なくかつ安い、(2)トラフィックの量が急激に変動したときに柔軟に対応できる、という利点があるが、(3)ハードの故障からは完全にはプロテクトされない、(4)データベースのスケーラビリティの問題は自分で解決しなければならない、という点は十分認識しておく必要がある。

 そんなことを頭に置いた上で、先週少し Google の App Engine について調べてみた。私がもっとも気に入ったのは、Amazonが解決してくれなかった、(3)ハードの故障問題から解放、と(4)データベースのスケーラビリティ問題からの解放、という部分。

 クラウドコンピューティングを「サーバー運営のアウトソース」という意味で見た時に、Amazon と Google では、セルフサービスの学食とフルサービスのレストランの違いぐらいがある。「ハードウェアの故障にどう対応しよう」「ユーザーが増えた時にデータベースをどう分けよう」などのことは心配せずに、サービス作り・ソフトウェア作りに100%集中したいのであれば、Google App Engineの方が格段の「おもてなし」である。

 とは言え、Google App Engineにまったくマイナス面がないわけではない。自分でOSのインストールまでできるAmazonと比べると以下のような制限がある:

1. Goolgle App Engine上のアプリケーションはサンドボックスの中で走る。OSのインストールはもちろんだめだが、それだけでなく、さまざまなリソースへのアクセスはかなり制限される(例:「ファイル」を作ることができない、デーモン・プロセスを起動したり、TCP/IPソケットを開きっぱなしにすることもできない)。基本的に、「入って来たHTTPリクエストを高速にステートレスに処理する」ことしか出来ないと思って間違いない。

2. データベースはGoogleのDatastore(Big Table)を使わなければならない。MySQLやOracleのようなリレーショナル・データベースとは違い、スキーマレスのオブジェクト・データベースなので、リレーショナル・データベースに関するノウハウはほとんど使えない。作ったアプリケーションを他の環境(例えばAmazon ec2)に大きな変更を加えずに持って行くことは不可能。

3. 公式にサポートされている言語は、PythonとJava(Javaの上でRubyやPHPなどの他の言語を動かすことは可能)。

 以上が、私から見たAmazon・Google二社のクラウドコンピューティング・サービスの違いである。App Engineに関しては、実際に商用サービスを運用した経験があるわけでもないので、どこかに見えない落とし穴があるかも知れないが、私から見れば「商用サービスを試してみる価値のある」レベルには十分に達していると思う。ちょうど一つ(ひょっとすると二つ)、新しいサービスで良い候補があるので、試してみようと考えている。

 ちなみに、私はPythonは初めてだったが、とても簡単な言語なのでそれほど悩まずに1日ぐらいでそれなりに書けるようになったので、皆さんにもおすすめする(特にJavaScript使いにはおすすめ)。Datastoreも初めはとっつきにくいかも知れないが、一度その中身がどうなっているかを理解すれば(つまり、慣れ親しんだリレーショナルデータベースとの違いをはっきりと認識できれば)それほど難しいものではない。


「RESTful MVC」なアーキテクチャの話

Architecture

 最近、増井君と私でアーキテクチャの話をすることが多いのだが、そんなディスカッションの中で気に入っているのは左の図のようなアーキテクチャ。

 もちろん、核となるのはビジネスロジックを含んだModelの部分。そこをしっかりと実装し、内部構造を隠す粒度の荒いインターフェイスを定義し、外から何をされてもデータの整合性が壊れない様にすることは何よりも大切。

 そして、そのModel層へのインターフェイスを特定の言語に依存したクラスやAPIではなく、HTTP上でJSON(XMLでもかまわない)をやりとりするだけの RESTfulなWeb Serviceにすることがミソ。こうすることによりにより、どんなに締め切りに負われようが、誰がControllerを実装しようが「ずるができない」ように作っておく(ずる=本来使うべき外部インターフェイスだけでなく、Model内部に直接アクセスして依存関係を作ってしまう事)。

 クライアント側でJavaScriptが実行できないようなブラウザーに対しては、サーバー側にControllerをおいてView TemplateとModelの結合を行って生成したHTMLを返す。JavaScriptが実行できるブラウザーに対しては、あえてサーバー側にはControllerをおかず(もしくは最小限のものにとどめ)、JavaScriptで記述されたControllerをブラウザーに送り込み、HTMLで記述されたView TemplateとJSONの形で送られて来たデータとの結合はクライアント側で行う(先日のjQBinder参照)。

 こんな風に作る一番の利点は、Modelへのインターフェイス作りをさぼることが絶対にできなくなること。ブラウザーのタイプによって二つの異なるView/Controllerペアとやりとりをしなければならないのでインターフェイスの明確な定義は必須だし、Statelessで非同期なインターフェイスなので、データの整合性を守るための複数のテーブルにまたがったトランザクションは絶対にModel側でしなければならないことはプロジェクトに関わる全員に自明となる。

 また、Modelはデータベースやサーバー側のハードコアなプログラミングに慣れたエンジニアが担当し、View/Controllerは見た目やユーザーインターフェイスにこだわるエンジニアが担当する、など作業分担もしやすくなる。

 それに加えて、Modelのインターフェイスが特定の言語に依存しないため、ModelはJavaで(サーバー側の)ControllerはPHPでとか、各モジュールのモックアップをRailsでアジャイルに作ってから本来の言語で本実装をする、などのテクニックが使えるのも利点だ。

 もちろん、これもデザイン・パターンの一つでしかないので、どんな場合にも適用できる話ではないが、少なくとも私が関わっているプロジェクトのほとんどすべてにこのアーキテクチャが適用できそうだな、と思っている今日この頃である。


デザイン・パターンとは何か

 先日のMVCの議論の際には、私自身いろいろと勉強させていただいたが、少し心配になったのは、「MVCの定義だって時代とともに変わる」「ウェブサービス用のMVCはSmalltalk時代のMVCとは異なるもの」「MVCなんか理解してなくてもアプリケーションが作れればいいじゃん」など、そもそも「MVCとは何か」どころか「デザイン・パターンとは何か」を理解していないんじゃないかと思われる発言が見られたこと。ということで、今日はデザイン・パターンについてひと言。

 デザイン・パターンとは、(業界に蓄積されたノウハウに立脚した)何かを作る際の指針のこと。ソフトウェアに限らず、ものを作るときにはさまざまな(場合によってはお互いに矛盾する)要求条件や制約が課せられるわけだが、そんな時に過去にさまざまな事例を解決してきた先人の知恵を「パターン化」してノウハウとして身につけておけば、似たような事例に出会った時に効率よく正しい答えにたどり着ける、というのがデザイン・パターン活用の背景にある考え方である。

 なので、MVCのようにいったん明確に定義されたデザイン・パターンは「時代とともに変わったり」は決してしないものである。もちろん、時代とともに要求条件や制約も変化するので、過去のデザイン・パターンのどれもがしっくりと来ない事例に出会う可能性も十分あり、その場合には自分なりの独自の設計をしなければならない。そんなことを多くの人が繰り返しているうちにある特定の形のデザインがたくさんの人の支持を得て新しいデザイン・パターンとして認知されることもあるが、それはあくまで「新しいデザイン・パターンが作られた」だけの話であり、「過去に定義されたデザイン・パターンそのものが変化した」のではない。

 ここを理解していただければ、「MVCの定義だって時代とともに変わる」「ウェブサービス用のMVCはSmalltalk時代のMVCとは異なるもの」などの発言がいかに的外れなものかが分かっていただけると思う。

 MVCがデザイン・パターンであることを皆が理解していれば、「ModelとView/Controller間のインターフェイスをきちんと設計しなければならないMVCは、アジャイルな開発には向かない」「いや、たとえアジャイルでもそこをさぼると後々のコストが高くなる」とか「RailsでModel層と呼ばれているActiveRecordは、データベースのテーブルとModelが1対1という比較的シンプルなアプリケーションの場合には文字通りModel層の役目を果たすことができるが、ビジネス上のモデルを複数テーブルにまたがって実装する必要がある場合は本来Model層にあるべきロジックをController側に記述せざるをえないので、その場合にはMdel/View/CcontrollerというよりはData/View/Model+Controller の形になる」などの建設的な議論が可能になる。

【追記】

 ちなみに、混乱の元はMVC2なる言葉。Sun MicrosystemsがMVCをウェブサービスに適用したアーキテクチャを提案した際に、JSPがViewとControllerの両方の役目を果たすものを Model1、ちゃんとMVCを適用してBeans(Model)+JSP(View)+Servlet(Controller)の形にしたものを Model 2(もしくは MVC Model 2)と呼んだことに始まる(参照)。この "MVC Model 2" を "MVC2" と省略して呼んだ人がいたために、「ウェブサービス用のMVCはSmalltalk時代のMVCとは異なるもの」などという混乱をまねいているのだ(参照)。


組み込み機器向けandroidに関してのつぶやき

 もともとは携帯電話向けに提供されていたGoogleのandroidが、それ以外の組み込み機器向けのOSとして注目されている。私なりの見解もそれなりにあるのだが、勘違いしている部分もあるかも知れないので、確認のためにも私の見方をぽろぽろとTwitterでつぶやいてみたので、ぜひともフィードバックをいただきたい(Twitter、このブログのコメント欄やトラックバック、はてぶ、のいずれでも結構)。以下がつぶやきの内容。

  • androidが携帯だけでなく組み込み機器一般で注目されている背景には、「要求される機能が肥大化し開発費が膨大になり、機種ごとにOSから組み上げるのがコスト的に見合わなって来た」というのがある(リンク)。
  • それに加えて、GUIやマルチタスクなどの要求に対し、従来の組み込みOS(μiTron・VxWorksなど)が答えられなかったという状況もある(リンク)。
  • その答えの一つとして浮上してきたのがLinuxだが、GUIレイヤーが統一されていないし、オープンソースという責任の所在が不明確なものを商品に使うことに不安があるし、GPLはいやだし、意外に開発費が安くならないし、という悩みを業界全体が抱えていた(リンク)。
  • そこに、Googleという大企業が全面的にバックアップするandroidがオープンソースの形でGUIレイヤーも含めて出て来たものだから、既にLinuxに以降していた・移行に二の足を踏んでいた企業がこぞって参加を表明した、というのが私の見方(リンク)。
  • ある意味で「赤信号、みんなで渡れば怖くない」的な心理が働いて、androidに一気に傾いたのでは、と私は見ている。このあたり、当事者の方々にはぜひともご意見をうかがいたい(リンク)。
  • もうひとつ忘れていけないのは、GPLの件。GPLゆえにLinux上にソフトウェア資産を築くことに二の足を踏んでいた企業が、GoogleがGUIレイヤーをApacheライセンスにしたことに安心感を持った、というのもあるんじゃないかと私は見ている(リンク)。
  • はてぶで指摘してもらって言い忘れていたことに気がついたけど、エミュレータとデバッグ環境がしっかりしていることも android の魅力の一つ。
  • こうやって書いていると「じゃあどうしてWindowsCEじゃだめなの?」という疑問が湧いて来る。WinCEはPDAだけじゃなくてSTBとかの組み込みデバイスにも使えるはずなのになぜ全然だめなのか?Microsoftが本気でないから?PDAマーケットの挫折と一緒に挫折したのか?
  • Microsoftにはパソコンビジネスでおいしいところを全部持っていかれた苦い経験があるから、もうあまり組みたくないとか?数ドルのライセンス料が部材コスト100ドル以下のSTBには高すぎるとか?


jQBinder, ブラウザー側でのHTML templateを可能にするjQuery plug-in

 一昨日はMVCの話で妙に盛り上がってしまったが、考えてみるとModel/View/Controller間の分離が不十分という話はサーバー側だけの話ではなく、クライアント側にも言える事。事実、私自身も

div.innerHTML = "<span class='red'>" + message + "</span>";

みたいなHTMLが混ざったJavaScriptコードを書く事は良くある。特に、最近はJSONとして取得して来たデータセットをリストとして表示するケースが増えて来たが、そんな時に「サーバー側のようなHTMLテンプレートが使えたらいいな」と思う事は良くある。手っ取り早くとりあえず動くものを作るのにはHTML埋め込み型のJavaScriptで良いのかも知れないが、後々のメンテナンスを考えると少なくともModelとViewぐらいはキチンと切り話しておいた方が良い事は確か。

 ということで、jQueryの勉強もかねて、簡単なHTMLテンプレート・エンジン(jQBinder)を作ってみた。使い方は至って簡単、まずはHTMLファイルの中に以下のようにテンプレートを埋め込んでおく。

  1.   <div id="stage">  
  2.       <div class="tweet">  
  3.         <div class='item_left'><img class='prof_img' src='$(.user.profile_image_url)' /></div>  
  4.         <div class='item_right'>$(.text)</div>  
  5.         <div class='name'>$(.user.screen_name) $(.created_at)</div>  
  6.         <div class='clearfix'></div>  
  7.       </div>  
  8.     </div>  

 一番外側のDIVがリストの表示の際の親になるエレメントで、その間にイタリックで書いた部分が各行をどう表示するかを記述したテンプレートである。$(.〜)の部分がデータとの結合(data-bind)時に置き換えられる。例えば$(.text)は、json[k].text (k:行番号)の値で置き換えられる。

 ドキュメントのロード時にテンプレートのままでは表示したくないので、CSSで親エレメントに "display:none" を指定して隠しておき、適切なタイミングで表示する(.show()を呼ぶ)ようにする。

 このテンプレートを利用してTwitterの最新のタイムラインを表示するには、以下のコードをドキュメントのロード時に実行する。

$("#stage").dataBindTo( { url:"http://twitter.com/statuses/public_timeline.json?callback=?"})
       .html("(loading...)").show(); // jsonを取得している間 "Loading..."と表示

 こうすると、指定したURLからJSONを非同期に取得し、取得後は各行のデータ(json[0..n])のプロパティを使ってテンプレートを展開する。

 実際のサンプルを左に貼付けたので、見ていただきたい(Safari4, Chrome4, iPhone Safari3.1, Firefox3.5, Opera9, IE8で動作確認済み)。

 ソースコードは、http://widgetpad.com/815/ からアクセスできるので、そのシンプルさを実感していただきたい(htmlが22行、jsが5行)。

 ちなみにこのjQBinder、せっかく作ったので、オープンソースのjQuery plug-inとして進化させて行くのも悪くないと考えている(jquery.comにはプラグインとして登録済み)。ご意見・ご要望・バグレポート等、大歓迎である。特にIE6やIE7の実行環境をお持ちの方がいたらこれがちゃんと表示されるかどうかの確認をしていただけるととても助かる。


O/Rマッピング技術の進化が皮肉にも助長している「えせMVC症候群」

 昨日の「Ruby on Railsの『えせMVC』の弊害」というエントリー。若干「釣り」の要素が含まれたタイトルが功を奏したのか、たくさんのフィードバックがいただけた。そんな中で見えて来たのは、この問題はRailsに限った話ではなく、業務用アプリケーションで使われているJavaや.Netの世界でもよく見られる問題だということ。

 その「問題」とは、ActiveRecordに代表されるO/Rマッピングの技術の進化が、本来のMVC(そしてオブジェクト指向そのもの)のメリットを無視した「えせMVC」な設計を助長している、という問題である。

・MVCやオブジェクト指向を表面的にしか理解していないエンジニアが増えている(ここが根本的な問題)
       
・SQLを自分で記述しなくて良いO/Rマッピングはとても魅力的(これはこれで別の問題を含んでいるが、このエントリーではあえて突っ込まない)
 
       
・O/Rマッピングにより抽象化したデータは一見れっきとしたModelに見える(ここが誤解のもと)
 
       
・O/RマッピングとHTMLテンプレートを使っただけで、自分は「MVCのデザインパターンに従った設計が出来る」という幻想を抱かせる(これが大きな誤解)。 
         
・本来ならModelの中に記述すべきビジネスロジック(ビジネスルールに基づいてデータベースにアクセスし、データの整合性に責任を持つロジック)をControllerの中に記述しはじめてしまい、結果的にController層が必要以上に分厚くメンテナンスしにくいアプリケーションができてしまう(スパゲッティのできあがり)。

 ちなみに、私は「O/Rマッピングが悪い」とも「O/Rマッピングを使うな」とも言っているわけではないので勘違いしないでいただきたい。単に「この業界でプロとして仕事をするなら、使う言語やフレームワークにかかわらず、オブジェクト指向とMVCのコンセプトだけはしっかりと理解した上で仕事をしてほしい。そして、O/Rマッピングを使う時には、それだけでModel作りが終わったと誤解してはいけない」と言っているだけである。

 オブジェクト指向と同じく、MVCのコンセプトは「はやりすたり」とは関係のない良いアプリケーションを設計する上での基本中の基本。Ruby on RailsやJ2EEを使ったウェブアプリケーションにも、Cocoa/UIKitの上のiPhoneアプリケーションにも通じる話だということを覚えておいてほしい。

 読者の皆さんからいただいた情報によれば、この問題は2003年の時点ですでに指摘されているようだ(Anemic Domain Model)。Rails上で犯しやすい設計上のミスに関しては「Skinny Cotroller, Fat Model」というエントリーが参考になるので一読をお進めする。


Ruby on Railsの「えせMVC」の弊害

 先日のエントリーでも少し触れたが、Ruby on Railsの最大の問題点は、それが持つ「一見そのフレームワークがMVCの形をとりながら、MVCの最も大切なところを外している『えせMVC』である」点にある。MVC(Model View Controller)がなぜ必要かを根底の部分でちゃんとと意識せずにRailsアプリケーションを作ると、後々ひどい目に会うので注意が必要である。

 その意味では「RailsでMVCを学ぶ」などもっての他だし、「JavaにもRailsと同じようなフレームワークを作って業務用アプリの開発を効率化しよう」などという発想もとても危険である。

 ということで、今日はまずはMVCの解説から。

 MVCの発想の根底には、「モジュール化と情報の隠蔽により、プログラムがスパゲッティ化するの(コード間の相互依存関係が複雑に入り込んでしまってにっちもさっちも行かない状態になること)を避けよう」というオブジェクト指向の発想がある。MVCは、そのオブジェクト指向に基づいて、GUIアプリケーションを以下の三つの大きなモジュールに分けて設計しましょう、というアーキテクチャの指針である。

  • Model:データベースなどに格納された生のデータを隠蔽し、抽象化された形のAPIを通じて他のモジュールからのアクセスをコントロールするモジュール。アプリケーション特有のルールやロジック(ビジネスロジック)を持ち、データの整合性(後述)に絶対の責任を持つ。
  • View:Modelが提供する抽象化されたデータを、どんな形で人間に見せるかを記述したモジュール。GUIアプリケーションの場合、使うGUI部品や画面上のレイアウトを指定するのがこのモジュール。
  • Controller:ViewとModelの間に位置して、ユーザーにどんな順序でデータを見せて行くとか、Viewを通したユーザーからの入力をModelへのAPIコールへとマッピングするのがこのモジュールの役目。

 この中で、もっとも丁寧に設計し徹底的にテストをしなければならないのがアプリケーションの土台となるModelである。ControllerやViewに多少のバグがあってもユーザーに一時的な迷惑をかけるだけの話だが、Modelにバグがあるとデータの整合性が壊れてしまう。

 ここで、先ほどから何度か触れている「データの整合性」とは何かを、業務用の「会計ソフト」を例に上げて説明してみよう。例えば、八百屋さんで「60円で仕入れたリンゴ1つを100円で売った」こと(Sales Transaction)を記録する場合を想定しよう。

 会計ソフトが一般的な会計の常識に従って作られていれば、この1つのSales Transactionにより、少なくとも4つの変更がデータベースに加えられる。

  1. 「手持ちの現金の増減」を記録するテーブルに「現金100円の増加」を記録
  2. 「売り上げ」を記録するテーブルに「100円の売り上げ」を記録
  3. 「在庫の増減」を記録するテーブルに「リンゴ1つ減少」を記録
  4. 「経費の計上」を記録するテーブルに「仕入れ値60円の経費計上」を記録

 八百屋さんのビジネスにとって大切なことは、この4つの変更が同時に行われること。このうち一つの変更だけが欠けていたりすると、テーブル間のつじつまが合わなくなってしまい、年度末の決算がちゃんとできなくなってしまう。

 この「データの変更が中途半端でつじつまが会わなくなってしまっている状況」のことがすなわち「データの整合性が壊れた」状況である。

 Modelの外部インターフェイスの設計においてもっとも大切なことは、この「データの整合性」の責任を100%Model側で引き受け、「Controllerが何をしてもデータの整合性だけは絶対に壊れない」ように作っておくことである。そのためには、上の例の「手持ちの現金の増減を記録したテーブル」へのControllerによる直接のアクセスは絶対禁物である。Controllerが出来る事は「何をいくらで売ったか」をModelに報告するだけで、その情報に基づいてデータベースに適切な変更を加えるのはModelの役割である。

 この「Controllerが何をしてもデータの整合性だけは絶対に壊れない」という部分はとても重要で、Controllerに少々のバグがあろうが、会計の知識が全くない新人がControllerを作ろうが、Controllerに悪意のあるコードが紛れ込もうが、整合性だけは絶対に壊れないようにModelを作っておくことが必須である。

 さて、そこで問題となるのは、Ruby on RailsというフレームワークでModelの役を果たしていると言われている(もしくは誤解されている)ActiveRecordである。

 RailsのActiveRecordは、データベースのテーブル(厳密にはクエリーの結果)の1行1行をオブジェクトの形にパッケージ化し、メソッドとプロパティの形で簡単にアクセスできるようにするもの(「O/Rマッピング」と呼ばれる)である。

 ActiveRecordそのものはとても便利なもので全く問題はないのだが、問題はRailsの解説書などでActiveRecordを使って抽象化されたデータベースをModelと読んでいるケースが多く見受けられる点だ。

 上に述べた通り、ActiveRecordは、データベースのテーブルを単にオブジェクトの形に抽象化しただけのものであり、そこにはビジネスロジックは一切含まれていない。その意味では、MVCにおけるModelとはほど遠いものであり、これをModelと呼ぶ事は(特に初心者に)大きな誤解を生むのでとても危険である。

 私は「どんなプログラムを常にMVCに厳密に基づいて作るべきだ」と主張している分けでも、「Ruby on Railsは使い物にならない」と批判しているわけでもないので誤解しないでいただきたい。ここで私が強調したいのは「Ruby on Railsフレームワークは本来のMVCとはほど遠い」「Ruby on Railsの上にMVCのことを意識せずに普通にアプリケーションを作ると、ビジネスロジックをControllerに混ぜ込んで書く事になってしまい、『データの整合性』を保つことが難しくなる」という点である。

 (誤解した人が多かったので追記すると)結論としては、「Railsを使って(データの整合性が大切な)アプリケーションを作る場合、素のままのActiveRecordにControllerから直接アクセスするのは避け、ActiveRecordの上に一枚皮をかぶせる形でビジネスロジックを含んだModelをきちんと設計・実装し、ビジネスロジックがControllerに浸食していくことを意識して避けることが大切である。

 なお、読者からのコメントで学んだのだが、Javaにおいても同じような「えせMVC症候群」は蔓延しているようで、MVCの本質を理解していないエンジニアが、うすっぺらなDAO(Data Access Object)の上にビジネスロジックを含んだ分厚いControllerを書きながらそれをMVCと思い込んでいる、という話は良くあるらしい。

 それから「MVCは時代とともに変わる」というコメントもいただいたが、この手の基本原理の定義を変えてしまうことはとても混乱を招くのでやめた方が良いと思う。MVCの発想は未来永劫いろいろな場面で使える話なので、別のアーキテクチャにはちゃんと別の名前を与えて混乱を避けるべきである。

【参考文献】


HTML5時代の「運営しやすいアーキテクチャ」の話

 増井君と二人でPhotoShareというサービスを立ち上げてもう15ヶ月になるが、いろいろと学んだことがある。その中でもつくづく思うのは、サービスを作り上げる段階よりも、運営のことを考えた設計が大切なこと。つまり、メンテナンスしやすい、テストしやすい、多少のミスをしても大丈夫、こまめなアップデートがしやすい、作業分担がしやすい、などなどである。

 そんななかで強く感じるのは、「AJAXを見た目や使いやすさの面だけに利用するだけでなく、『運営しやすいサービス』を作るのに利用できないか」ということである。

 私のイメージするアーキテクチャを図にするとこんな感じになる。

Architecture

 まず一番の特徴は、テンプレート等を利用したHTMLのダイナミックな生成をすべてやめて、データ(JSONもしくはXML)だけをダイナミックに生成するようにし、HTMLはスタティック・ファイルをサーバー側に置いておく(上の図で、CSS, HTML, JS, Media Filesはすべてスタティック・ファイル)。

 この設計の一番目の利点は、「(Controllerとブラウザーの間の)Web Service APIの定義をきちんとしなければならなくなる」点である。「そんなことはどんなアーキテクチャでも可能だ」と感じる人も多いだろうが、納期に迫られたり緊急のバグフィックスを施す時に、どうしても人間は安易な方向に走ってしまうもの。そんな時に本来Controller側に置くべきものがViewに紛れ込んでしまったり、仕様書に書かれていないViewとController依存関係が生まれてしまったり、というのは良くある話だ。HTMLをスタティックファイルにし、JavaScriptでJSONなりXMLを引っ張って来て表示する設計にしておけば、さすがにそこの仕様定義をおろそかにはできない。すごく人間的な話だが、こんなつまらないことが「運営しやすいサービス作り」には大切だと思う。

 もう一つの利点は、点線で囲まれた「アプリケーション・ロジック」の部分のデプロイメントと、HTMLやCSSなどのアップデートを別のサイクルで行える点である。PhotoShareを運営していてつくづく思うのは、ユーザーの声を聞き入れてもっと頻繁にウェブサイトのUIを変更したいな、ということである。アプリケーションロジックと表示側をAPIできれいに分けておけば、細かなUIの変更を比較的少ないリスクで行うことが可能になる。UIをちょっと変更するたびにアプリケーション・ロジックをすべてデプロイしていては手間もかかるしリスクも高い。

 次に大切だと思うのは、(図ではちゃんと表現できていないが)ModelとControllerの役割を少し見直すべき、という点である。PhotoShareは主にRailsで作られているので、ModelはActiveRecordが担当しているわけだが、Modelのレイヤーが非常に薄いために(O/Rマッピングをしているだけ)、データベースの整合性の責任がController側にある。そのため、ちょっとした機能変更のたびにAPIレベルでのテストを大量に走らせなければならないし、それでもどうしてもミスが生じてしまう。

 そこでデータベースの整合性の責任を100%Modelに負わせ(つまりModelを単なるO/Rマッパーではなく、ビジネスロジックを含んだモジュールとして設計して作り込む)、そこだけは徹底的なテストケースを作って強固なものにしておくことにより、Controller側の変更で多少のミスをしてもデータベースの整合性が壊れたりしない、という設計にしておくとController側の変更がもう少し気楽に、かつ頻繁にできると考えている。

 こうは書いてみたが、実際にサービスとして運営するとなると、AJAXが使えないブラウザーはどうするという問題や、顧客のために受託でものを作っているからアップデートのたびに仕事が取れるアーキテクチャの方が良い、などの大人の事情があったりするのですぐに実践できる話ではないかも知れないが、HTML5の目指している方向は明らかにこちらだ、と思う今日この頃である。