グラニがC#にこだわる理由

第2回ASP.NET MVCとC#で加速するフロントエンド開発

100万人以上が遊ぶソーシャルゲームを支えるWeb技術

グラニでは現在、⁠神獄のヴァルハラゲート」「モンスターハンター ロア オブ カード」という2つのタイトルのソーシャルゲームをリリースしています。それらのゲームを支える技術としてC#を利用しているという話は前号Vol.80でも触れましたが、今回はWebアプリケーション、そしてフロントエンドにまつわる技術について掘り下げていきます。

最初に、現在稼働している両タイトルで採用している技術について簡単に触れておきます。まず、サーバサイドのアプリケーションフレームワークには、Microsoftが提供するASP.NET MVC 5.1を採用しています。ASP.NET MVCはフルスタックなフレームワークではなく、テンプレートとコントローラ周りの機能に絞られており、データアクセス層を含みません。性能も拡張性もとても高く、バランスの良いフレームワークだと感じます。ソースコードはオープンソースで提供されています。

そしてフロントエンドですが、クライアントスクリプトに関しては両タイトルともにJavaScriptを直接記述するのではなく、AltJSの1つであるTypeScriptという言語を採用しています。TypeScriptについてはのちほどもう少し詳しく触れます。ライブラリにはjQueryやKnockout.js、少し変わったところではQなどを利用しています。

もう1つフロントエンドに欠かせないものとして、マークアップに対するスタイルシートの記述があります。スタイルシートについても、CSSファイルを直接記述するのではなく、CSSプリプロセッサでCSSファイルを生成するCSSメタ言語を採用しています。⁠神獄のヴァルハラゲート」ではLESSを、⁠モンスターハンター ロア オブカード」ではSass(scss)を採用しています。

2つのタイトルで異なる言語を採用していますが、これはマークアップエンジニアの人員を確保できなかった初期タイトルでは開発者が導入しやすかったLESSを採用し、その後、マークアップエンジニアにとって必要な機能を備えたSassを採用したためです。

ここまでアプリケーションで実際に採用している技術をざっと見てきましたが、一般的なLightweight LanguageでのWebアプリケーション開発と大きく違うところはあまりないのではないでしょうか? もちろんC#という言語を採用している以上、アプリケーションフレームワークはASP.NETになるとしても、RubyならRailsといったところと大きくは変わりません。

C#がもたらすタイプセーフなテンプレート

ここからは、少しフロントエンドに近い部分を見ていきます。まずは、HTMLを組み立てるためのテンプレートエンジンについてです。先ほども説明したとおり、アプリケーションのフレームワークにはASP.NET MVCを採用していますので、ASP.NET MVCが標準で提供するRazorテンプレートエンジンを利用しています。このテンプレートエンジンの特徴は、C#のコードをテンプレートに自然に記述できる点にあります(なお、Visual Basic.NETを選択することもできます⁠⁠。実際のRazorテンプレートの例をリスト1に示します。

リスト1 Razorテンプレートの例
@model IndexViewModel
<!DOCTYPE html>
<title>Index</title>
<h1>Index</h1>
@if (Model.Items.Any())
{
  <ul>
    @foreach (var item in Model.Items.OrderBy(x => x.Order))
    {
      <li>@item.Name</li>
    }
  </ul>
}

初めて見た方は、HTMLなのかC#なのかひと目では区別が付かないかもしれません。簡単に説明すると、@(アットマーク)で開始するとC#のコードとして扱われ、コードとして判断できるところまでを「いい感じに」認識してくれます。たとえば、@ifで開始すればifステートメントに、@変数名とすれば変数名の値を出力、となります。

ハイブリッドなところが、良くも悪くもRazorテンプレートの良さの1つです。C#を日ごろ書いている人がビューのロジック(View Modelよりも些細なロジック)を書く際に、いつものとおりLINQを使い、C#の構文をそのまま書けます。それでいてHTMLもそのまま書いておけるので、慣れると見通しの良いテンプレートを書きやすくなります。

そしてもちろん、Visual Studioの強力なエディタ機能はRazorテンプレートでもその力を発揮します。たとえば、変数に型が設定されているため、IntelliSenseによる強力な補完を通常のC#のコードと同様に利用できます。また、編集中に型の不一致などのチェックも行われるため、コードを実行するまでもなく問題を発見できます。これにより、テンプレートを記述する効率は飛躍的に上がります図1⁠。

図1 Visual StudioでRazorテンプレートを編集しているときに型の不一致問題が報告されているところ(上)と、IntelliSenseでメンバ候補を表示したところ(下)
図1 Visual StudioでRazorテンプレートを編集しているときに型の不一致問題が報告されているところ(上)と、IntelliSenseでメンバ候補を表示したところ(下)

また、実際のアプリケーション開発時には何らかの装飾などを施すヘルパーを作ると思いますが、RazorではRazor書式そのものでヘルパーを作る点が特徴的です。加えて、ヘルパーにHTMLの断片を渡せる点が少し変わっているでしょうか。たとえば、単純にstrong要素で包むヘルパーを作ると次のようなコードになります。スッキリ書けて、マークアップエンジニアとしてはありがたいところです。

@helper WrapStrong(Func<dynamic, HelperResult> content) {
  <strong>@content(null)</strong>
}

そして、このコードはテンプレート側から次のように呼び出せます。

@WrapStrong(@<span>ほむほむ<img src="" alt="" /></span>)

ヘルパーの引数に、@に続けてHTMLの断片を書くことができます。こうすることで、HTMLのエスケープについて気にする必要がなくなるというメリットがあります。たとえば、@WrapStrong("<span>ほむほむ</span>")という文字列をヘルパーに渡す場合、⁠そのヘルパーはエスケープされていないHTMLを受け取るのか?⁠⁠、あるいは「エスケープされた状態で出力されるのか?」といったことを気にする必要が出てきます。もちろん「HTMLエスケープされた文字列」というクラスで文字列を扱う方法もありますが、結局、利用する側の不安は残りますし、エスケープを忘れるとXSSの原因になったりと実に厄介です。そういった問題も防止でき、マークアップする側もヘルパーを作りやすく開発を進められるのが、このRazorテンプレートエンジンなのです。

C#の生みの親が開発したタイプセーフなスクリプト言語

もう少しクライアントサイドについて見ていきましょう。冒頭でも少し触れましたが、クライアントサイドではJavaScriptを直接記述するのではなく、TypeScriptという言語を利用します。TypeScriptはAltJSと呼ばれる変換型言語の1つで、TypeScriptで書いたコードをコンパイルすることでJavaScriptを生成します。

AltJSにはTypeScriptのほか、CoffeeScriptやHaxe、JSXなどいくつもの言語があります。にもかかわらずTypeScriptを採用するに至った大きな理由の1つは、TypeScriptの開発者がC#の開発者であるAnders Hejlsberg(アンダース・ヘルスバーグ)だからです……というのは冗談ですが、次のようなポイントで採用を決定しました。

  • 開発がオープンでコミュニティも活発であり、採用実績も多い
  • 社内の開発者のほぼ100%が使っているC#と同じ静的型付け言語である
  • 文法の雰囲気がC#に若干近い
  • Visual Studioからシームレスに扱え、エディタの支援も多く得られる

普段から開発環境として利用しているVisual Studioでそのまま扱えるのは大きなアドバンテージとなります。スクリプトを書くのはフロントエンドを担当するエンジニアだけではないため、コードを書いてコンパイルするまでを公式サポートのあるVisual Studioで行えることはスムーズな開発を後押ししてくれます。もちろんコードの記述に関する支援も多く受けることができます図2⁠。

図2 Visual StudioでTypeScriptファイルを編集しているときにIntelliSenseでメンバ候補を表示したところ
図2 Visual StudioでTypeScriptファイルを編集しているときにIntelliSenseでメンバ候補を表示したところ

C#でフロントエンドを支援する

さて、先ほどテンプレートを介したフロントエンドとC#のつながりについて触れましたが、それとは別の角度からもフロントエンドの開発支援にC#の力を利用しています。

ソーシャルゲームの世界においてフィーチャーフォン、いわゆるガラケーは未だ大きなシェアがあり、現実にはその対応がまだまだ必要です。しかしながら、ガラケー対応のHTMLというのはstyle属性に直接スタイルを書くような作業であり、マークアップエンジニアにとっては控えめに言ってもとても残念な気分になるものです。

そこでグラニでは、Cartelet(カータレット)というライブラリを開発して利用しています。Carteletは、HTMLをパースしてCSSセレクタにマッチした要素の属性を操作し、TextWriterを通してフィルタを行うといった機能を持っています図3⁠。その機能を利用し、次のようにフロントエンド開発を支援しています。

  • CSSファイルを読み込んでstyle属性に展開する
  • 全角カタカナを半角に、半角カタカナを全角に変換する
  • ページサイズや画像サイズをチェックし、サイズ超過時にNewRelicへ通知する
図3 フィーチャーフォン向けテンプレートのHTML(上)とSassファイル(下)
図3 フィーチャーフォン向けテンプレートのHTML(上)とSassファイル(下)

特にCSSファイルを読み込んでstyle属性に展開する機能は、マークアップとスタイルシートの設計のスマートさの向上に大きく寄与しています。CarteletはCSS Selectors Level 3(一部を除く)をサポートしており、::before/after擬似要素も簡易的ではありますが扱えるため、ガラケー向けのマークアップとCSSをスマートフォンの設計に合わせてモダンに管理/設計できるようになっています。

「速さ」へのこだわり

ところで、HTMLを処理するライブラリは、C#においてもSgmlReaderやCSQueryなど数多くありますが、わざわざ新たにライブラリを開発したのは、速度を落としたくないという理由があったからです。

高性能なライブラリは、その分処理時間が若干ですが長くなります。たとえば、50ミリ秒でレスポンスが返ってくるところにパースとフィルタ処理で30ミリ秒かかるものを導入するのはインパクトが大き過ぎます。そこでCarteletでは、機能を限定することでパースとフィルタを平均5ミリ秒程度で処理できるようにしました。このような部分でも、グラニは速度にこだわりを持っています。

なお、CarteletのソースコードはMITライセンスでGitHubに公開しています。成果物を公開するのはいつか誰かのためになること、そしてC#コミュニティの発展の一助になることを期待しつつ、積極的にコミットしていきたいと考えています。

おわりに

今回は、グラニのアプリケーションで利用しているWebの技術、おもにフロントエンドにフォーカスした解説となりました。昨今のWebアプリケーション開発というと、やはりLightweight Language環境の話ばかりが目に付きますが、C#やVisual Studioを利用したWeb開発もけっして後れをとっていませんので、今回の記事で少しでも興味を持っていただけると幸いです。

提供/株式会社グラニ

http://grani.jp/

おすすめ記事

記事・ニュース一覧